Caricamento in corso...
Caricamento in corso...
Last synced: Today, 22:00
Technical reference for the OpenClaw framework. Real-time synchronization with the official documentation engine.
Use this file to discover all available pages before exploring further.
Status: production-ready via WhatsApp Web (Baileys). Gateway owns linked session(s).
openclaw onboardopenclaw channels add --channel whatsappopenclaw channels login --channel whatsapp@openclaw/whatsappManual install stays available:
bashopenclaw plugins install @openclaw/whatsapp
If npm reports the OpenClaw-owned package as deprecated or missing, use a current packaged OpenClaw build or a local checkout until the npm package train catches up.
Default DM policy is pairing for unknown senders.
Cross-channel diagnostics and repair playbooks.
Full channel config patterns and examples.
textFor a specific account: ```bash} openclaw channels login --channel whatsapp --account work ``` To attach an existing/custom WhatsApp Web auth directory before login: ```bash} openclaw channels add --channel whatsapp --account work --auth-dir /path/to/wa-auth openclaw channels login --channel whatsapp --account work ```
```
textPairing requests expire after 1 hour. Pending requests are capped at 3 per channel.
note
OpenClaw recommends running WhatsApp on a separate number when possible. (The channel metadata and setup flow are optimized for that setup, but personal-number setups are also supported.)
Deployment patterns
Runtime model
- Gateway owns the WhatsApp socket and reconnect loop.
- The reconnect watchdog uses WhatsApp Web transport activity, not only inbound app-message volume, so a quiet linked-device session is not restarted solely because nobody has sent a message recently. A longer application-silence cap still forces a reconnect if transport frames keep arriving but no application messages are handled for the watchdog window; after a transient reconnect for a recently active session, that application-silence check uses the normal message timeout for the first recovery window.
- Baileys socket timings are explicit under text
web.whatsapp.*: textkeepAliveIntervalMs controls WhatsApp Web application pings, textconnectTimeoutMs controls the opening handshake timeout, and textdefaultQueryTimeoutMs controls Baileys query timeouts.
- Outbound sends require an active WhatsApp listener for the target account.
- Status and broadcast chats are ignored (text
@status, text@broadcast).
- The reconnect watchdog follows WhatsApp Web transport activity, not only inbound app-message volume: quiet linked-device sessions stay up while transport frames continue, but a transport stall forces reconnect well before the later remote disconnect path.
- Direct chats use DM session rules (text
session.dmScope; default textmain collapses DMs to the agent main session).
- Group sessions are isolated (text
agent:<agentId>:whatsapp:group:<jid>).
- WhatsApp Web transport honors standard proxy environment variables on the gateway host (text
HTTPS_PROXY, textHTTP_PROXY, textNO_PROXY / lowercase variants). Prefer host-level proxy config over channel-specific WhatsApp proxy settings.
- When text
messages.removeAckAfterReply is enabled, OpenClaw clears the WhatsApp ack reaction after a visible reply is delivered.
Plugin hooks and privacy
WhatsApp inbound messages can contain personal message content, phone numbers,
group identifiers, sender names, and session correlation fields. For that reason,
WhatsApp does not broadcast inbound
textmessage_received hook payloads to plugins
unless you explicitly opt in:
json5{
channels: {
whatsapp: {
pluginHooks: {
messageReceived: true,
},
},
},
}
You can scope the opt-in to one account:
json5{
channels: {
whatsapp: {
accounts: {
work: {
pluginHooks: {
messageReceived: true,
},
},
},
},
},
}
Only enable this for plugins you trust to receive inbound WhatsApp message
content and identifiers.
Access control and activation
`channels.whatsapp.dmPolicy` controls direct chat access:
text* `pairing` (default)
* `allowlist`
* `open` (requires `allowFrom` to 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
* OpenClaw never auto-pairs outbound `fromMe` DMs (messages you send to yourself from the linked device)
Group access has two layers:
text1. **Group membership allowlist** (`channels.whatsapp.groups`)
* if `groups` is omitted, all groups are eligible
* if `groups` is present, it acts as a group allowlist (`"*"` allowed)
2. **Group sender policy** (`channels.whatsapp.groupPolicy` + `groupAllowFrom`)
* `open`: sender allowlist bypassed
* `allowlist`: sender must match `groupAllowFrom` (or `*`)
* `disabled`: block all group inbound
Sender allowlist fallback:
* if `groupAllowFrom` is unset, runtime falls back to `allowFrom` when 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.
textMention detection includes:
* explicit WhatsApp mentions of the bot identity
* configured mention regex patterns (`agents.list[].groupChat.mentionPatterns`, fallback `messages.groupChat.mentionPatterns`)
* inbound voice-note transcripts for authorized group messages
* 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
When the linked self number is also present in
textallowFrom, WhatsApp self-chat safeguards activate:
- skip read receipts for self-chat turns
- ignore mention-JID auto-trigger behavior that would otherwise ping yourself
- if text
messages.responsePrefix is unset, self-chat replies default to text[{identity.name}] or text[openclaw]
Message normalization and context
Delivery, chunking, and media
Reply quoting
WhatsApp supports native reply quoting, where outbound replies visibly quote the inbound message. Control it with
textchannels.whatsapp.replyToMode.
Value Behavior text"off" Never quote; send as a plain message text"first" Quote only the first outbound reply chunk text"all" Quote every outbound reply chunk text"batched" Quote queued batched replies while leaving immediate replies unquoted
Default is
text"off". Per-account overrides use textchannels.whatsapp.accounts.<id>.replyToMode.
json5{
channels: {
whatsapp: {
replyToMode: "first",
},
},
}
Reaction level
textchannels.whatsapp.reactionLevel controls how broadly the agent uses emoji reactions on WhatsApp:
Level Ack reactions Agent-initiated reactions Description text"off" No No No reactions at all text"ack" Yes No Ack reactions only (pre-reply receipt) text"minimal" Yes Yes (conservative) Ack + agent reactions with conservative guidance text"extensive" Yes Yes (encouraged) Ack + agent reactions with encouraged guidance
Default:
text"minimal".
Per-account overrides use
textchannels.whatsapp.accounts.<id>.reactionLevel.
json5{
channels: {
whatsapp: {
reactionLevel: "ack",
},
},
}
Acknowledgment reactions
WhatsApp supports immediate ack reactions on inbound receipt via
textchannels.whatsapp.ackReaction.
Ack reactions are gated by textreactionLevel — they are suppressed when textreactionLevel is text"off".
json5{
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 text
mentions reacts on mention-triggered turns; group activation textalways acts as bypass for this check
- WhatsApp uses text
channels.whatsapp.ackReaction (legacy textmessages.ackReaction is not used here)
Multi-account and credentials
Tools, actions, and config writes
- Agent tool support includes WhatsApp reaction action (text
react).
- Action gates:
- text
channels.whatsapp.actions.reactions
- text
channels.whatsapp.actions.polls
- Channel-initiated config writes are enabled by default (disable via text
channels.whatsapp.configWrites=false).
Troubleshooting
System prompts
WhatsApp supports Telegram-style system prompts for groups and direct chats via the
textgroups and textdirect maps.
Resolution hierarchy for group messages:
The effective
textgroups map is determined first: if the account defines its own textgroups, it fully replaces the root textgroups map (no deep merge). Prompt lookup then runs on the resulting single map:
- Group-specific system prompt (text
groups["<groupId>"].systemPrompt): used when the specific group entry exists in the map and its textsystemPrompt key is defined. If textsystemPrompt is an empty string (text""), the wildcard is suppressed and no system prompt is applied.
- Group wildcard system prompt (text
groups["*"].systemPrompt): used when the specific group entry is absent from the map entirely, or when it exists but defines no textsystemPrompt key.
Resolution hierarchy for direct messages:
The effective
textdirect map is determined first: if the account defines its own textdirect, it fully replaces the root textdirect map (no deep merge). Prompt lookup then runs on the resulting single map:
- Direct-specific system prompt (text
direct["<peerId>"].systemPrompt): used when the specific peer entry exists in the map and its textsystemPrompt key is defined. If textsystemPrompt is an empty string (text""), the wildcard is suppressed and no system prompt is applied.
- Direct wildcard system prompt (text
direct["*"].systemPrompt): used when the specific peer entry is absent from the map entirely, or when it exists but defines no textsystemPrompt key.
note
`dms` remains the lightweight per-DM history override bucket (`dms..historyLimit`). Prompt overrides live under `direct`.
Difference from Telegram multi-account behavior: In Telegram, root
textgroups is intentionally suppressed for all accounts in a multi-account setup — even accounts that define no textgroups of their own — to prevent a bot from receiving group messages for groups it does not belong to. WhatsApp does not apply this guard: root textgroups and root textdirect are always inherited by accounts that define no account-level override, regardless of how many accounts are configured. In a multi-account WhatsApp setup, if you want per-account group or direct prompts, define the full map under each account explicitly rather than relying on root-level defaults.
Important behavior:
- text
channels.whatsapp.groups is both a per-group config map and the chat-level group allowlist. At either the root or account scope, textgroups["*"] means "all groups are admitted" for that scope.
- Only add a wildcard group text
systemPrompt when you already want that scope to admit all groups. If you still want only a fixed set of group IDs to be eligible, do not use textgroups["*"] for the prompt default. Instead, repeat the prompt on each explicitly allowlisted group entry.
- Group admission and sender authorization are separate checks. text
groups["*"] widens the set of groups that can reach group handling, but it does not by itself authorize every sender in those groups. Sender access is still controlled separately by textchannels.whatsapp.groupPolicy and textchannels.whatsapp.groupAllowFrom.
- text
channels.whatsapp.direct does not have the same side effect for DMs. textdirect["*"] only provides a default direct-chat config after a DM is already admitted by textdmPolicy plus textallowFrom or pairing-store rules.
Example:
json5{
channels: {
whatsapp: {
groups: {
// Use only if all groups should be admitted at the root scope.
// Applies to all accounts that do not define their own groups map.
"*": { systemPrompt: "Default prompt for all groups." },
},
direct: {
// Applies to all accounts that do not define their own direct map.
"*": { systemPrompt: "Default prompt for all direct chats." },
},
accounts: {
work: {
groups: {
// This account defines its own groups, so root groups are fully
// replaced. To keep a wildcard, define "*" explicitly here too.
"120363406415684625@g.us": {
requireMention: false,
systemPrompt: "Focus on project management.",
},
// Use only if all groups should be admitted in this account.
"*": { systemPrompt: "Default prompt for work groups." },
},
direct: {
// This account defines its own direct map, so root direct entries are
// fully replaced. To keep a wildcard, define "*" explicitly here too.
"+15551234567": { systemPrompt: "Prompt for a specific work direct chat." },
"*": { systemPrompt: "Default prompt for work direct chats." },
},
},
},
},
},
}
Configuration reference pointers
Primary reference:
High-signal WhatsApp fields:
- access: text
dmPolicy, textallowFrom, textgroupPolicy, textgroupAllowFrom, textgroups
- delivery: text
textChunkLimit, textchunkMode, textmediaMaxMb, textsendReadReceipts, textackReaction, textreactionLevel
- multi-account: text
accounts.<id>.enabled, textaccounts.<id>.authDir, account-level overrides
- operations: text
configWrites, textdebounceMs, textweb.enabled, textweb.heartbeatSeconds, textweb.reconnect.*, textweb.whatsapp.*
- session behavior: text
session.dmScope, texthistoryLimit, textdmHistoryLimit, textdms.<id>.historyLimit
- prompts: text
groups.<id>.systemPrompt, textgroups["*"].systemPrompt, textdirect.<id>.systemPrompt, textdirect["*"].systemPrompt
Related
© 2024 TaskFlow Mirror
Powered by TaskFlow Sync Engine