WhatsApp (Web channel)
Section titled “WhatsApp (Web channel)”Status: production-ready via WhatsApp Web (Baileys). Gateway owns linked session(s).
Install (on demand)
Section titled “Install (on demand)”- Onboarding (
openclaw onboard) andopenclaw channels add --channel whatsappprompt to install the WhatsApp plugin the first time you select it. openclaw channels login --channel whatsappalso offers the install flow when the plugin is not present yet.- Dev channel + git checkout: defaults to the local plugin path.
- Stable/Beta: defaults to the npm package
@openclaw/whatsapp.
Manual install stays available:
openclaw plugins install @openclaw/whatsappDefault DM policy is pairing for unknown senders.
Cross-channel diagnostics and repair playbooks.
Full channel config patterns and examples.
Quick setup
Section titled “Quick setup”Configure WhatsApp access policy
{channels: {whatsapp: {dmPolicy: "pairing",allowFrom: ["+15551234567"],groupPolicy: "allowlist",groupAllowFrom: ["+15551234567"],},},}Link WhatsApp (QR)
Terminal window openclaw channels login --channel whatsappFor a specific account:Terminal window openclaw channels login --channel whatsapp --account workStart the gateway
Terminal window openclaw gatewayApprove first pairing request (if using pairing mode)
Terminal window openclaw pairing list whatsappopenclaw pairing approve whatsappPairing requests expire after 1 hour. Pending requests are capped at 3 per channel.
Deployment patterns
Section titled “Deployment patterns”Dedicated number (recommended)
This is the cleanest operational mode:
- separate WhatsApp identity for OpenClaw
- clearer DM allowlists and routing boundaries
- lower chance of self-chat confusion
Minimal policy pattern:
{ channels: { whatsapp: { dmPolicy: "allowlist", allowFrom: ["+15551234567"], }, },}Personal-number fallback
Onboarding supports personal-number mode and writes a self-chat-friendly baseline:
dmPolicy: "allowlist"allowFromincludes your personal numberselfChatMode: true
In runtime, self-chat protections key off the linked self number and allowFrom.
WhatsApp Web-only channel scope
The messaging platform channel is WhatsApp Web-based (Baileys) in current OpenClaw channel architecture.
There is no separate Twilio WhatsApp messaging channel in the built-in chat-channel registry.
Runtime model
Section titled “Runtime model”- Gateway owns the WhatsApp socket and reconnect loop.
- Outbound sends require an active WhatsApp listener for the target account.
- Status and broadcast chats are ignored (
@status,@broadcast). - Direct chats use DM session rules (
session.dmScope; defaultmaincollapses DMs to the agent main session). - Group sessions are isolated (
agent:<agentId>:whatsapp:group:<jid>).
Access control and activation
Section titled “Access control and activation”channels.whatsapp.dmPolicy controls direct chat access:
pairing(default)allowlistopen(requiresallowFromto include"*")disabled
allowFrom accepts E.164-style numbers (normalized internally).
Multi-account override: `channels.whatsapp.accounts.
.dmPolicy(andallowFrom`) take precedence over channel-level defaults for that account.
Runtime behavior details:
- pairings are persisted in channel allow-store and merged with configured `allowFrom`- if no allowlist is configured, the linked self number is allowed by default- outbound `fromMe` DMs are never auto-pairedGroup access has two layers:
-
Group membership allowlist (
channels.whatsapp.groups)- if
groupsis omitted, all groups are eligible - if
groupsis present, it acts as a group allowlist ("*"allowed)
- if
-
Group sender policy (
channels.whatsapp.groupPolicy+groupAllowFrom)open: sender allowlist bypassedallowlist: sender must matchgroupAllowFrom(or*)disabled: block all group inbound
Sender allowlist fallback:
- if
groupAllowFromis unset, runtime falls back toallowFromwhen available - sender allowlists are evaluated before mention/reply activation
Note: if no channels.whatsapp block exists at all, runtime group-policy fallback is allowlist (with a warning log), even if channels.defaults.groupPolicy is set.
Group replies require mention by default.
Mention detection includes:
- explicit WhatsApp mentions of the bot identity
- configured mention regex patterns (
agents.list[].groupChat.mentionPatterns, fallbackmessages.groupChat.mentionPatterns) - implicit reply-to-bot detection (reply sender matches bot identity)
Security note:
- quote/reply only satisfies mention gating; it does not grant sender authorization
- with
groupPolicy: "allowlist", non-allowlisted senders are still blocked even if they reply to an allowlisted user’s message
Session-level activation command:
/activation mention/activation always
activation updates session state (not global config). It is owner-gated.
Personal-number and self-chat behavior
Section titled “Personal-number and self-chat behavior”When the linked self number is also present in allowFrom, WhatsApp self-chat safeguards activate:
- skip read receipts for self-chat turns
- ignore mention-JID auto-trigger behavior that would otherwise ping yourself
- if
messages.responsePrefixis unset, self-chat replies default to[{identity.name}]or[openclaw]
Message normalization and context
Section titled “Message normalization and context”Inbound envelope + reply context
Incoming WhatsApp messages are wrapped in the shared inbound envelope.
If a quoted reply exists, context is appended in this form:
[Replying toid:
]
[/Replying]
Reply metadata fields are also populated when available (`ReplyToId`, `ReplyToBody`, `ReplyToSender`, sender JID/E.164).Media placeholders and location/contact extraction
Media-only inbound messages are normalized with placeholders such as:
- `
-
-
-
-
`
Location and contact payloads are normalized into textual context before routing.Pending group history injection
For groups, unprocessed messages can be buffered and injected as context when the bot is finally triggered.
- default limit:
50 - config:
channels.whatsapp.historyLimit - fallback:
messages.groupChat.historyLimit 0disables
Injection markers:
[Chat messages since your last reply - for context][Current message - respond to this]
Read receipts
Read receipts are enabled by default for accepted inbound WhatsApp messages.
Disable globally:
{ channels: { whatsapp: { sendReadReceipts: false, }, },}Per-account override:
{ channels: { whatsapp: { accounts: { work: { sendReadReceipts: false, }, }, }, },}Self-chat turns skip read receipts even when globally enabled.
Delivery, chunking, and media
Section titled “Delivery, chunking, and media”Text chunking
- default chunk limit:
channels.whatsapp.textChunkLimit = 4000 channels.whatsapp.chunkMode = "length" | "newline"newlinemode prefers paragraph boundaries (blank lines), then falls back to length-safe chunking
Outbound media behavior
- supports image, video, audio (PTT voice-note), and document payloads
audio/oggis rewritten toaudio/ogg; codecs=opusfor voice-note compatibility- animated GIF playback is supported via
gifPlayback: trueon video sends - captions are applied to the first media item when sending multi-media reply payloads
- media source can be HTTP(S),
file://, or local paths
Media size limits and fallback behavior
- inbound media save cap:
channels.whatsapp.mediaMaxMb(default50) - outbound media send cap:
channels.whatsapp.mediaMaxMb(default50) - per-account overrides use `channels.whatsapp.accounts.
.mediaMaxMb` - images are auto-optimized (resize/quality sweep) to fit limits - on media send failure, first-item fallback sends text warning instead of dropping the response silently
Reaction level
Section titled “Reaction level”channels.whatsapp.reactionLevel controls how broadly the agent uses emoji reactions on WhatsApp:
| Level | Ack reactions | Agent-initiated reactions | Description |
|---|---|---|---|
"off" | No | No | No reactions at all |
"ack" | Yes | No | Ack reactions only (pre-reply receipt) |
"minimal" | Yes | Yes (conservative) | Ack + agent reactions with conservative guidance |
"extensive" | Yes | Yes (encouraged) | Ack + agent reactions with encouraged guidance |
Default: "minimal".
Per-account overrides use channels.whatsapp.accounts.<id>.reactionLevel.
{ channels: { whatsapp: { reactionLevel: "ack", }, },}Acknowledgment reactions
Section titled “Acknowledgment reactions”WhatsApp supports immediate ack reactions on inbound receipt via channels.whatsapp.ackReaction.
Ack reactions are gated by reactionLevel — they are suppressed when reactionLevel is "off".
{ channels: { whatsapp: { ackReaction: { emoji: "👀", direct: true, group: "mentions", // always | mentions | never }, }, },}Behavior notes:
- sent immediately after inbound is accepted (pre-reply)
- failures are logged but do not block normal reply delivery
- group mode
mentionsreacts on mention-triggered turns; group activationalwaysacts as bypass for this check - WhatsApp uses
channels.whatsapp.ackReaction(legacymessages.ackReactionis not used here)
Multi-account and credentials
Section titled “Multi-account and credentials”Account selection and defaults
- account ids come from
channels.whatsapp.accounts - default account selection:
defaultif present, otherwise first configured account id (sorted) - account ids are normalized internally for lookup
Credential paths and legacy compatibility
- current auth path: `~/.openclaw/credentials/whatsapp/
/creds.json - backup file:creds.json.bak - legacy default auth in~/.openclaw/credentials/` is still recognized/migrated for default-account flows
Logout behavior
`openclaw channels logout —channel whatsapp [—account
]` clears WhatsApp auth state for that account.
In legacy auth directories, `oauth.json` is preserved while Baileys auth files are removed.Tools, actions, and config writes
Section titled “Tools, actions, and config writes”- Agent tool support includes WhatsApp reaction action (
react). - Action gates:
channels.whatsapp.actions.reactionschannels.whatsapp.actions.polls
- Channel-initiated config writes are enabled by default (disable via
channels.whatsapp.configWrites=false).
Troubleshooting
Section titled “Troubleshooting”Not linked (QR required)
Symptom: channel status reports not linked.
Fix:
openclaw channels login --channel whatsappopenclaw channels statusLinked but disconnected / reconnect loop
Symptom: linked account with repeated disconnects or reconnect attempts.
Fix:
openclaw doctoropenclaw logs --followIf needed, re-link with channels login.
No active listener when sending
Outbound sends fail fast when no active gateway listener exists for the target account.
Make sure gateway is running and the account is linked.
Group messages unexpectedly ignored
Check in this order:
groupPolicygroupAllowFrom/allowFromgroupsallowlist entries- mention gating (
requireMention+ mention patterns) - duplicate keys in
openclaw.json(JSON5): later entries override earlier ones, so keep a singlegroupPolicyper scope
Bun runtime warning
WhatsApp gateway runtime should use Node. Bun is flagged as incompatible for stable WhatsApp/Telegram gateway operation.
Configuration reference pointers
Section titled “Configuration reference pointers”Primary reference:
High-signal WhatsApp fields:
- access:
dmPolicy,allowFrom,groupPolicy,groupAllowFrom,groups - delivery:
textChunkLimit,chunkMode,mediaMaxMb,sendReadReceipts,ackReaction,reactionLevel - multi-account:
accounts.<id>.enabled,accounts.<id>.authDir, account-level overrides - operations:
configWrites,debounceMs,web.enabled,web.heartbeatSeconds,web.reconnect.* - session behavior:
session.dmScope,historyLimit,dmHistoryLimit,dms.<id>.historyLimit