← Back to PRs

#21719: feat(whatsapp): add replyToOfflineMessages config to process missed messages after reconnect

by faahim open 2026-02-20 08:45 View on GitHub →
docs channel: whatsapp-web size: S
## Problem Closes #19856. Related issues (all caused by the same `upsert.type === "append"` skip in `monitor.ts`): **DM messages lost after reconnect/disconnect:** - #1619 — Messages missed during connection drops (append-type messages skipped) - #19856 — WhatsApp inbound messages lost after reconnect (408 timeout) - #18672 — WhatsApp: recent append messages dropped after prekey renegotiation **Group messages stop working after restart:** - #1952 — Group inbound messages stop working after gateway restart (closed as config error, but root cause is append skip) - #2767 — Group messages stop working after gateway restart (references #1619, #1952) - #20952 — Group messages not working after restart (correct config confirmed) - #14069 — Group messages stop arriving after relinking device (syncFullHistory: false) **Other append-related:** - #904 — Clawdbot messages itself on WhatsApp (closed) - #13113 — Duplicate of append skip issue - #14663, #17526, #19025, #19302, #19537 — Various append skip reports (open) - #1443 — History sync triggers pairing responses (related: append messages reaching access control) - #20887 — Capture and expose messaging-history.set for chat history search (feature request for the same underlying gap) This is one of the most frequently reported WhatsApp issues in the project — **15+ issues** across DMs, groups, and various reconnection scenarios, all tracing back to the same 3 lines: ```typescript // If this is history/offline catch-up, mark read above but skip auto-reply. if (upsert.type === "append") { continue; } ``` The worst part: messages are **marked as read** (blue tick sent) before being skipped, so senders see the bot read their message but never replied. ## Solution Add an opt-in `replyToOfflineMessages` config flag (default: `false` for full backward compatibility). When enabled, offline/catch-up messages are processed normally instead of being skipped. A safety limit `offlineMessageMaxAgeSeconds` (default: 300s / 5 minutes) ensures that only recent offline messages are processed — very old messages from extended disconnects are still skipped to prevent message flooding. ### Changes - **`src/config/types.whatsapp.ts`** — Add `replyToOfflineMessages` and `offlineMessageMaxAgeSeconds` to both `WhatsAppConfig` and `WhatsAppAccountConfig` - **`src/web/accounts.ts`** — Resolve the new fields with proper fallback chain (account → root → default) - **`src/web/inbound/monitor.ts`** — Replace the unconditional `continue` for append messages with configurable logic - **`src/web/auto-reply/monitor.ts`** — Pass the new options through to the inbox monitor - **New test** — Verifies: default skip behavior, opt-in processing, and age-based filtering ### Example config ```json { "whatsapp": { "replyToOfflineMessages": true, "offlineMessageMaxAgeSeconds": 600 } } ``` Or per-account: ```json { "whatsapp": { "accounts": { "main": { "replyToOfflineMessages": true, "offlineMessageMaxAgeSeconds": 300 } } } } ``` ### Safety considerations - **Default `false`** — No behavior change unless explicitly opted in - **Age-based filtering** — Prevents message flood after extended disconnects - **Existing dedupe** — `isRecentInboundMessage()` (20-min TTL, 5000 entries) prevents double-processing - **Access control** — `connectedAtMs` check already suppresses pairing replies for historical messages --- > 🤖 AI-assisted PR — lightly tested. Default is `false` so this is a no-op unless explicitly enabled.

Most Similar PRs