WhatsApp Channel
WhatsApp Channel Setup
Monitor WhatsApp groups via your OpenClaw agent to provide daily summaries, react to messages, and flag urgent items.
How It Works
Your personal WhatsApp is linked as a device to the agent Mac via the OpenClaw WhatsApp plugin (Baileys/WhatsApp Web). Everything the agent does on WhatsApp appears as you.
Flow:
- Messages flow into the group
- Groups with
requireMention: falsepass all messages to the agent session. Groups withrequireMention: trueonly pass messages where the agent is @mentioned — all others are silently dropped before reaching the session. - Every heartbeat cycle (~1h), the agent reviews messages in the session
- The agent occasionally reacts to a message with an emoji
- If something urgent is detected -> immediate ping to owner via iMessage
- Once daily (evening) -> agent sends a summary of the day’s chat via iMessage
Setup Steps
1. Enable WhatsApp Plugin
The WhatsApp plugin ships with OpenClaw but is disabled by default:
openclaw plugins enable whatsapp2. Link WhatsApp
openclaw channels loginScan the QR code using WhatsApp -> Settings -> Linked Devices on your phone. This links the agent Mac as a WhatsApp Web device.
3. Gateway Config
Add to ~/.openclaw/openclaw.json under channels:
"whatsapp": { "dmPolicy": "disabled", "selfChatMode": true, "groupPolicy": "allowlist", "groupAllowFrom": [ "+1XXXXXXXXXX", "+1XXXXXXXXXX" ], "groups": { "*": { "requireMention": true } }, "sendReadReceipts": true}Key settings:
- dmPolicy: “disabled” — no WhatsApp DMs, only group monitoring. Change to
"allowlist"withallowFromto enable DMs for testing. - selfChatMode: true — this is your own phone number
- groupPolicy: “allowlist” — only accept messages from explicitly allowed senders in groups (prevents prompt injection escalation via elevated tools)
- groupAllowFrom — E.164 phone numbers of senders whose group messages should reach the agent. Use
["*"]to allow all group participants. This must contain phone numbers, not group JIDs — the gateway matches each sender’s phone number against this list. - requireMention: true —
applyGroupGatingdrops all messages where the agent is not @mentioned. Messages that don’t mention the agent never reach the session — the agent can’t see them, react to them, or include them in summaries. Override per-group withrequireMention: falsefor groups where the agent should passively monitor (see below) - sendReadReceipts: true — mark messages as read
Per-group requireMention override:
To let the agent passively monitor a specific group (see all messages, react, summarize) while keeping other groups mention-gated:
"groups": { "*": { "requireMention": true }, "requireMention": false }}The * wildcard applies to all groups not explicitly listed. Groups with requireMention: false will have every message flow into the agent’s session — the agent can see message IDs, sender info, and content, enabling reactions and summaries.
4. Agent Binding
Route all WhatsApp traffic to a dedicated WhatsApp agent. This isolates WhatsApp-specific issues from iMessage and other channels:
{ "agentId": "wa-agent", "match": { "channel": "whatsapp", "peer": { "kind": "group", } }}Add a catch-all for remaining WhatsApp traffic (DMs and other groups):
{ "agentId": "wa-agent", "match": { "channel": "whatsapp" }}Why a separate agent? A dedicated WhatsApp agent provides better isolation — channel-specific failures stay contained and don’t affect iMessage DMs or group chats.
5. Agent Config Updates
HEARTBEAT.md — Add WhatsApp monitoring tasks:
- Group check (2-3x/day): review group history, react to 1-2 messages
- Daily summary (1x/day, evening): send summary to owner via iMessage
- Urgent items: immediate iMessage ping for health/safety/time-sensitive items
AGENTS.md — Add group chat guidelines:
- Listen-mostly role
- React naturally with heartfelt emoji
- Never respond unless @mentioned
- Route all summaries/pings via iMessage, not WhatsApp
Shadow Mode (sendPolicy)
To prevent the agent from sending text replies into group chats while still allowing observation and reactions, add a session.sendPolicy deny rule:
"session": { "sendPolicy": { "rules": [ { "action": "deny", "match": { "channel": "whatsapp", "chatType": "group" } } ], "default": "allow" }}In shadow mode, the agent:
- Observes all group messages (they flow into the session normally)
- Reacts to messages with emoji (reactions bypass sendPolicy)
- Cannot send text replies or auto-reply error messages into groups
- Can still reply in WhatsApp DMs (sendPolicy only blocks group chatType)
The main agent monitors WhatsApp group activity by reading the WhatsApp agent’s session via sessions_history during heartbeat check-ins.
Reactions
WhatsApp reactions are supported via the gateway’s react action. During heartbeat, the agent can:
- Fetch group history to see messages with IDs
- Call the react action with
chatJid,messageId, andemoji - Reactions appear in WhatsApp as you
Preferred emoji palette: ❤️, 😂, 👍, 🙌, 🥰
Reactions are delayed by up to the heartbeat interval (~1h), which actually feels natural — like you checked your phone later and hearted something.
Identity Rules
With selfChatMode: true, everything the agent does on WhatsApp appears as you:
- NEVER use the agent’s emoji prefix or branding
- NEVER sign messages or hint that an AI is writing
- Send EXACTLY what the owner approves — no paraphrasing
Gap Recovery with wacli
OpenClaw’s Baileys connection occasionally times out (408 errors), missing messages. wacli provides a separate WhatsApp device link for gap recovery.
Installation
brew install steipete/tap/wacliUsage
# Fetch group history
# Search all messageswacli messages search "query"
# Continuous sync (run in background)wacli sync --follow
# Check auth statuswacli auth statusImportant: Store locks if multiple wacli processes run simultaneously. Don’t run wacli sync while manually querying.
Cross-Channel Access (from BlueBubbles)
When the agent is in a BlueBubbles-bound session (e.g., chatting with the owner via iMessage), the message tool is constrained to BlueBubbles. To interact with WhatsApp from that session, use sessions_send:
sessions_list— find WhatsApp session keys (filter bychannel: "whatsapp")sessions_send— send the instruction to the WhatsApp session key (e.g., “Read recent messages from the family group” or “React with a heart to the last message from Mom”)- The run executes in the WhatsApp-bound session where
messageworks for WhatsApp - The reply comes back via the ping-pong loop
Required config (already set in Lobster’s config):
session.dmScope: "per-channel-peer"— BlueBubbles and WhatsApp have separate sessionstools.sessions.visibility: "all"— agent can see all sessionssessions_sendin the agent’s allowed tools
This works for reads, reactions, and message history — not just sends. The WhatsApp outbound restriction (no individual messages) still applies even via sessions_send.
Resilience and Recovery
Channel Health Monitor
Enable the gateway health monitor to auto-restart channels that go stale:
"gateway": { "channelHealthCheckMinutes": 5}The health monitor checks every 5 minutes. If no inbound events arrive within 30 minutes (default stale threshold), the gateway auto-restarts the channel. Cap: 10 restarts/hour.
Important: The health monitor alone does not fix the jiti VM realm isolation bug (see below). Apply the listener patch first, then enable the health monitor — otherwise restarts will cycle without recovering the listener.
Listener Realm Isolation (Patch Required)
After a Baileys WebSocket disconnect/reconnect (e.g., DNS outage, WhatsApp server maintenance), the listener may re-register in a new jiti VM realm while the delivery code reads from the old realm’s empty Map. Symptoms:
- Outbound sends fail with “No active WhatsApp Web listener”
openclaw channels status --probestill reports “connected” (false positive)- Inbound messages stop flowing silently
Fix: Apply openclaw-patch-wa-listeners (bridges the listener Map via process.__openclawWaWebListeners). Must be re-applied after every openclaw update.
Upstream: #50208
SecretRef Crash on Inbound Messages
If the WhatsApp embedded agent crashes with unresolved SecretRef errors, the agent is reading raw config instead of the gateway’s resolved runtime snapshot. Inline the affected secret values directly in openclaw.json as a workaround.
Upstream: #49427
Notes
- WhatsApp does not support the
readmessage action —sendReadReceiptsmay behave differently than BlueBubbles - WhatsApp does not support the
resolvecommand — group JIDs can’t be looked up by name selfChatModemeans messages the owner sends won’t appear as inbound — only messages from other group members trigger events- WhatsApp group messages route to their own session — use
sessions_historyto check, notmessage poll