docs/channels/group-messages.md
For the cross-channel groups model (Discord, iMessage, Matrix, Microsoft Teams, QQBot, Signal, Slack, Telegram, WhatsApp, Zalo), see Groups. This page covers the WhatsApp-specific behavior on top of that model: activation, group allowlists, per-group session keys, and pending-message context injection.
Goal: let OpenClaw sit in WhatsApp groups, wake up only when pinged, and keep that thread separate from the personal DM session.
<Note> `agents.list[].groupChat.mentionPatterns` is shared with the other channels' mention gating. For multi-agent setups, set it per agent, or use `messages.groupChat.mentionPatterns` as a global fallback. With neither set, patterns are derived from the agent identity name/emoji. </Note>mention (default) or always. mention requires a ping: a real WhatsApp @-mention (mentionedJids), a configured regex pattern, the bot's E.164 digits anywhere in the text, or a quoted reply to one of the bot's messages (except shared-number self-chat setups). always wakes the agent on every message, but the injected group prompt tells it to reply only when it adds value and to return the exact silent token NO_REPLY (case-insensitive) otherwise. Defaults come from config (channels.whatsapp.groups requireMention) and can be overridden per group via /activation.channels.whatsapp.groups is set, only listed group JIDs are admitted (include "*" to allow all); messages from unlisted groups are dropped with a log hint.channels.whatsapp.groupPolicy controls whether group messages are accepted (open|disabled|allowlist). allowlist uses channels.whatsapp.groupAllowFrom (fallback: explicit channels.whatsapp.allowFrom). Default is allowlist (blocked until you add senders).agent:<agentId>:whatsapp:group:<jid> (non-default accounts append :thread:whatsapp-account-<accountId>), so directives such as /verbose on, /trace on, or /think high (sent as standalone messages) are scoped to that group; personal DM state is untouched.[Chat messages since your last reply - for context], with the triggering line under [Current message - respond to this]. The pending window is cleared after the run; messages already in the session are not re-injected.[WhatsApp <groupJid> <timestamp>] Alice (+447700900123): text, and sender identity plus group subject/members ride along in the untrusted conversation-metadata block./activation changes the mode) injects activation guidance into the system prompt (Activation: trigger-only ... or Activation: always-on ..., plus "address the specific sender"). Persistent group-chat delivery guidance ("You are in a WhatsApp group chat...") is always included.Make display-name pings work even when WhatsApp strips the visual @ from the text body:
{
channels: {
whatsapp: {
groups: {
"*": { requireMention: true },
},
historyLimit: 50, // pending group context window (default 50)
},
},
agents: {
list: [
{
id: "main",
groupChat: {
mentionPatterns: ["@?openclaw", "\\+?15555550123"],
},
},
],
},
}
Notes:
mentionedJids when someone taps the contact, so the number fallback is rarely needed but is a useful safety net.channels.whatsapp.accounts.<id>.historyLimit → channels.whatsapp.historyLimit → messages.groupChat.historyLimit → 50.Use the group chat command:
/activation mention/activation alwaysOnly owner numbers (from channels.whatsapp.allowFrom, or the bot's own E.164 when unset) can change this; /activation from anyone else is ignored and stored as context only. Send /status as a standalone message in the group to see the current activation mode.
@openclaw ... (or include the number). Only allowlisted senders can trigger it unless you set groupPolicy: "open"./verbose on, /trace on, /think high, /new or /reset, /compact) apply only to that group's session; send them as standalone messages so they register. Your personal DM session stays independent.@openclaw ping in the group and confirm a reply that references the sender name.--verbose) for inbound web message entries showing from: <groupJid> and the sender-labeled body.agent:<agentId>:whatsapp:group:<jid> in the session store (~/.openclaw/agents/<agentId>/sessions/sessions.json by default); a missing entry just means the group has not triggered a run yet.session.typingMode / agents.defaults.typingMode. When visible replies are opted into message-tool-only mode, typing starts immediately by default so group members can see the agent working even if no automatic final reply is posted. Explicit typing-mode config still wins.