If you landed here asking “how do I connect OpenClaw to WhatsApp?”, this is the article you need. Below is the exact process we use on ClawCloud to bring a fresh OpenClaw agent online, pair it with the official WhatsApp Business API, handle group permissions, and keep the session alive. Everything is tested on OpenClaw v1.11.4 (Node 22.7) and the WhatsApp Cloud API released in April 2024.
1. Why OpenClaw + WhatsApp Needs Its Own Playbook
Telegram, Discord, and Slack give you OAuth tokens and you are done. WhatsApp is different because:
- The consumer app is locked down; you need the Business API (or Cloud API) to automate.
- Meta enforces a phone-number → WhatsApp Business Account (WABA) binding that must be verified.
- Sessions can drop silently if your webhook dies for >30 seconds.
- Group chats require explicit
adminapproval before a bot can post.
Ignoring those nuances is why most first-time setups break after a day. Let’s get it right from line 1.
2. Prerequisites, Versions, and One Reality Check
Before you copy anything below, confirm you have:
- OpenClaw Gateway: v1.11.4+ running (
npm i -g openclaw@latest). - Node.js: ≥22.0. The grpc bindings for WhatsApp break on 20.x.
- WhatsApp Business Account: Verified in Facebook Business Manager, status =
APPROVED. - Phone number: Not currently tied to any WhatsApp client. You will lose consumer chat history when you migrate.
- Webhook endpoint: Public HTTPS (Cloudflare Tunnel or ngrok works). Needs to accept Meta callbacks in
POST /webhook. - Local port: 3100 free (default OpenClaw gateway port).
Reality check: Meta still rate-limits templates and requires user opt-in for the first proactive message. If you need blazing outbound marketing, WhatsApp is the wrong channel. For interactive agents, it shines.
3. WhatsApp Business API Setup in 6 Terminal Commands
The Business API exists in two flavours: self-hosted Docker bundle and the newer Cloud API. We’ll use Cloud API because it’s free and removes the EKS horror show.
Create an App: In Facebook Developers → Create App → “Business”. Give it a name like OpenClaw Gateway.
Add WhatsApp: Inside the app dashboard → Add Product → WhatsApp → Set Up.
Generate a System User Token:
curl -X POST \ "https://graph.facebook.com/v19.0/{app-id}/access_tokens" \ -d "app_secret={app-secret}" \ -d "scope=whatsapp_business_messaging"Store it in OpenClaw secrets:
openclaw secrets set WHATSAPP_TOKEN "EAAJ...SDZ"Subscribe a Webhook:
curl -X POST \ "https://graph.facebook.com/v19.0/{phone-number-id}/webhooks" \ -d "callback_url=https://your-domain.com/webhook" \ -d "verify_token=openclaw_verify"Verify the callback: Meta sends a GET challenge. Expose:
app.get('/webhook', (req, res) => { if (req.query['hub.verify_token'] === 'openclaw_verify') { res.send(req.query['hub.challenge']); } else { res.sendStatus(403); } });
At this point the WhatsApp API will happily POST any incoming messages to /webhook. We still need to teach OpenClaw to consume them.
4. Pairing the OpenClaw Gateway via QR Code
OpenClaw uses the same pairing flow you get in WhatsApp Web, but via the Baileys library (v5.20.1). The QR code model is rock-solid and faster than the official OAuth path.
4.1 Start the gateway in pairing mode
openclaw gateway --channel whatsapp --pair
The CLI prints something like:
[whatsapp] Waiting for QR… press CTRL+C to abort
4.2 Scan from the WhatsApp Business mobile app
Open the app → Linked devices → Scan QR. Within 10 seconds you’ll see ✔ Paired in the terminal. OpenClaw writes a .openclaw/session.json file that contains the encrypted auth tokens. Back it up; losing it means re-pairing.
4.3 Run the daemon
openclaw daemon --channels whatsapp --port 3100
The daemon does three things: serves the web UI, registers the WhatsApp transport, and streams messages to your agents. Keep it in systemd or PM2 so QR never expires.
5. Routing Messages and Handling Group Permissions
5.1 Routing logic
OpenClaw ships with @openclaw/router-whatsapp. Install if you’re on an older custom build:
npm i @openclaw/router-whatsapp@1.7.0
Edit openclaw.config.js:
module.exports = {
channels: {
whatsapp: {
phoneId: process.env.WHATSAPP_PHONE_ID,
token: process.env.WHATSAPP_TOKEN,
defaultAgent: 'fred-bot',
allowGroups: true
}
}
};
Message mapping happens in this order:
- Direct message → routed to
defaultAgentunless you define#aliasin the first line. - Group chat → allowed only if bot is admin and group appears in
openclaw.groups.json. - If no match → dropped with
404: NO_HANDLER.
5.2 Granting group permissions
After adding the bot as a group participant you must promote it to admin once. Then run:
openclaw groups add 12036302527392@group.chat.whatsapp.com --agent fred-bot
This writes:
{
"12036302527392@group.chat.whatsapp.com": {
"agent": "fred-bot",
"created": "2024-05-03T10:22:12Z"
}
}
The router consults the file on each inbound message, so you can revoke by deleting the key.
6. The Pairing Safety Model and DM Approval Flow
WhatsApp’s spam model is strict: users must initiate or approve DMs before you can message them outside a 24h window. OpenClaw implements two guardrails:
6.1 Opt-in tags
When a user first pings hi, the router adds their JID to optin.whatsapp.json with a timestamp. Agents check this before any outbound send:
if (!context.optedIn("556199728234@c.us")) {
throw new Error('No opt-in');
}
6.2 DM approval workflow
For proactive messages (e.g., daily stand-up reminders) you need user approval. OpenClaw provides a built-in flow:
Your agent attempts
sendMessage(); router detects missing opt-in.Router sends a CTA: “Bot XYZ wants to message you. Reply YES to approve.”
If user replies
YESwithin 24h, router adds them to opt-in and re-queues the original payload.
No external database needed, just JSON and retries.
7. Monitoring, Session Drops, and Other Pain Points
7.1 Detecting disconnects
Baileys emits connection.update. Wire it to Prometheus:
claw.on('connection.update', ({ connection, lastDisconnect }) => {
if (connection === 'close') {
metrics.whatsapp_down.inc();
}
});
7.2 Auto-reconnect logic
Put this in whatsapp.ts:
async function connect() {
sock = makeWASocket({ auth: state });
sock.ev.on('connection.update', (u) => {
if (u.connection === 'close' && shouldReconnect(u.lastDisconnect?.error)) {
setTimeout(connect, 1000);
}
});
}
The magic is shouldReconnect() returns false on 401 → you need to re-pair.
7.3 Long-running uploads
Sending >25 MB videos often fails. WhatsApp compresses but timeouts at 100 s. Chunk on your side:
await agent.sendFile(path, { split: 20000000 });
7.4 Limits recap
- Message throughput: 250/s baseline. Meta will throttle silently.
- Concurrent logins per number: 4 including the phone.
- Session TTL: 14 days inactivity.
7.5 Alerting snippet (Prometheus Alertmanager)
- alert: WhatsAppSessionDown
expr: whatsapp_down > 0
for: 2m
labels:
severity: pager
annotations:
summary: "OpenClaw WhatsApp session is disconnected"
8. Next Steps: Automate Something Real
You now have a live OpenClaw agent answering on WhatsApp, with group scope locked down, DM approvals, and reconnect watchdogs. The next logical step is to plug tools into your workflow. Two popular ideas:
- Gmail triage: Connect the Composio Gmail integration so your agent can fetch unread mail when a user types “inbox”.
- On-call helper: Bind to PagerDuty’s REST API, post the active incident list into a WhatsApp group every 10 minutes.
Run openclaw tools install gmail pagerduty, add credentials in secrets.json, and your WhatsApp bot becomes an actual teammate.
Questions or gotchas? The GitHub Discussions board has an ongoing “WhatsApp Transport” thread with logs and patches. If something above breaks, post there — we watch it daily.