whatsapp bundled extension owns
platform dependencies, login, session inspection, outbound delivery, polls, and reactions.
@whiskeysockets/baileys is resolved lazily at channel-activation time — the gateway boots and
the extension registers its config/status/onboarding surface even when the runtime dependency is
not installed (see Installation below).
deps missing for the whatsapp plugin in wednesdayai plugins list, reinstall the
managed copy:~/.openclaw/extensions/whatsapp and installs its runtime
dependencies there. Do not run npm install inside the global WednesdayAI package directory.
The gateway will emit a PLUGIN_DEPS_MISSING warning at boot until the managed copy has its
dependencies.Pairing
Channel troubleshooting
Gateway configuration
Quick setup
Configure WhatsApp access policy
Link WhatsApp (QR)
Start the gateway
Approve first pairing request (if using pairing mode)
Deployment patterns
Dedicated number (recommended)
Dedicated number (recommended)
- separate WhatsApp identity for OpenClaw
- clearer DM allowlists and routing boundaries
- lower chance of self-chat confusion
Personal-number fallback
Personal-number fallback
dmPolicy: "allowlist"allowFromincludes your personal numberselfChatMode: true
allowFrom.channels.whatsapp.selfChatMode enables same-phone setup where the bot uses your personal WhatsApp number. When enabled, self-chat safeguards activate (skip read receipts, ignore mention-JID auto-trigger, default response prefix).WhatsApp Web-only transport scope
WhatsApp Web-only transport scope
Baileys) in current WednesdayAI channel architecture.There is no separate Twilio WhatsApp messaging channel in the built-in chat-channel registry.Installation
Install the WhatsApp plugin with one command:whatsapp to @wednesdayai/whatsapp, installs it into ~/.openclaw/extensions/whatsapp, and installs Baileys plus QR-code runtime dependencies beside that managed copy. The plugin pins @whiskeysockets/baileys 7.0.0-rc14. That release depends on registry libsignal (not a git-protocol spec) and on whatsapp-rust-bridge 0.5.4 (Rust/WebAssembly utilities published as a registry package).
After install, enable it and restart the gateway. WhatsApp configuration (phone number, account settings) can be set before or after installation — it validates regardless of install state.
The global bundled WhatsApp copy is still used for catalog metadata and onboarding labels. Runtime
loads should use the managed copy under ~/.openclaw/extensions/whatsapp because WhatsApp depends
on Baileys and QR-code packages that are installed beside that managed copy.
Runtime model
- The
whatsappextension owns account config resolution, auth/session inspection, QR login helpers, outbound send/poll/reaction behavior, and extension runtime dependencies. - Gateway still owns the active listener and monitor loop while inbound monitoring is being extracted.
- During this stage, stateful auth operations in the extension proxy through the host runtime so QR login, monitor sockets, queued credential saves, and logout clearing share one auth-state owner.
- Outbound sends require an active WhatsApp listener for the target account.
- Direct QR relink refuses to open a second socket while the gateway listener owns the account. Use the gateway login flow, which stops the channel before starting QR relink.
- Logout stops gateway listeners that share the same canonical auth directory before clearing credentials, so relink checks do not see stale active-listener ownership.
- WhatsApp socket startup also takes a non-reentrant auth-directory lock, so a separate CLI, gateway process, or second in-process startup cannot open another Baileys socket on the same account credentials.
- 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
- DM policy
- Group policy + allowlists
- Mentions + /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.<id>.dmPolicy (and allowFrom) 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
fromMeDMs are never auto-paired
Personal-number and self-chat behavior
When the linked self number is also present inallowFrom, 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
Inbound envelope + reply context
Inbound envelope + reply context
ReplyToId, ReplyToBody, ReplyToSender, sender JID/E.164).channels.whatsapp.messagePrefix adds a prefix to inbound messages before agent processing (e.g. for context tagging).Media placeholders and location/contact extraction
Media placeholders and location/contact extraction
<media:image><media:video><media:audio><media:document><media:sticker>
Pending group history injection
Pending group history injection
- default limit:
50 - config:
channels.whatsapp.historyLimit - fallback:
messages.groupChat.historyLimit 0disables
[Chat messages since your last reply - for context][Current message - respond to this]
Read receipts
Read receipts
Delivery, chunking, and media
Text chunking
Text chunking
- default chunk limit:
channels.whatsapp.textChunkLimit = 4000 channels.whatsapp.chunkMode = "length" | "newline"newlinemode prefers paragraph/block boundaries and packs as many complete paragraphs as fit into each message up totextChunkLimit, falling back to length-based splitting only when a single block exceeds the limit. Fenced code blocks and tables are kept intact.channels.whatsapp.chunkNewlinePacking(defaulttrue): set tofalseto restore one message per paragraph (the pre-packing behaviour).
Message debouncing
Message debouncing
channels.whatsapp.debounceMs batches rapid consecutive messages from the same sender before agent processing. Default behavior depends on configuration; set to 0 to disable.Outbound media behavior
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
Media size limits and fallback behavior
- inbound media save cap:
channels.whatsapp.mediaMaxMb(default50) - outbound media cap for auto-replies:
agents.defaults.mediaMaxMb(default5MB) - 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
Acknowledgment reactions
WhatsApp supports immediate ack reactions on inbound receipt viachannels.whatsapp.ackReaction.
- 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
Account selection and defaults
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
Credential paths and legacy compatibility
- current auth path:
~/.openclaw/credentials/whatsapp/<accountId>/creds.json - backup file:
creds.json.bak - legacy default auth in
~/.openclaw/credentials/is still recognized/migrated for default-account flows - during the current extraction stage, the extension auth-store uses a host-runtime proxy so QR login, monitor sockets, credential save queues, and logout clearing share one process-local state map
- active WhatsApp sockets create
.socket-owner.locknext to the credentials to prevent cross-process gateway/CLI collisions; stale locks from dead processes are removed automatically by PID checks - compatibility SDK auth exports share the same process-scoped queues/clear markers; new extension code should prefer the channel runtime bridge while the monitor remains host-owned
Logout behavior
Logout behavior
openclaw channels logout --channel whatsapp [--account <id>] clears WhatsApp auth state for that account.Logout closes active QR sockets and stops gateway listeners that share the selected account’s canonical auth directory, refuses to clear credentials if another socket owner holds the lock, drains queued credential writes, then deletes Baileys auth JSON files from the configured auth directory. Symlinked auth directories are refused rather than followed; symlinked Baileys auth fragments inside a real auth directory are unlinked without touching their targets. In legacy shared auth directories, unrelated JSON state is preserved and only known Baileys fragments are removed; oauth.json is preserved.Disabling without removing config
Setchannels.whatsapp.enabled: false to disable the WhatsApp channel while preserving the rest of your config:
Tools, actions, and config writes
- Agent tool support includes WhatsApp reaction action (
react). - Outbound text, media, polls, and reactions are implemented in the WhatsApp extension.
- Action gates:
channels.whatsapp.actions.reactionschannels.whatsapp.actions.sendMessagechannels.whatsapp.actions.polls
- Channel-initiated config writes are enabled by default (disable via
channels.whatsapp.configWrites=false).
Troubleshooting
Not linked (QR required)
Not linked (QR required)
Linked but disconnected / reconnect loop
Linked but disconnected / reconnect loop
channels login.If the gateway is already running for the account, use the gateway login flow when available. A direct CLI login against the same auth directory will refuse to start while another openclaw process owns the socket lock.No active listener when sending
No active listener when sending
Group messages unexpectedly ignored
Group messages unexpectedly ignored
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
Bun runtime warning
Configuration reference pointers
Primary reference: High-signal WhatsApp fields:- access:
dmPolicy,allowFrom,groupPolicy,groupAllowFrom,groups - delivery:
textChunkLimit,chunkMode,chunkNewlinePacking,mediaMaxMb,sendReadReceipts,ackReaction - delivery target:
defaultTo - message behavior:
debounceMs,messagePrefix,selfChatMode - 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 - streaming:
blockStreaming,blockStreamingCoalesce - formatting:
markdown,responsePrefix - heartbeat:
heartbeat