@whiskeysockets/baileys 7.0.0-rc.9 (pinned; the WhatsApp Web protocol), not the Chat SDK bridge. For Meta’s official Cloud API instead, use /add-whatsapp-cloud — see the channels overview.
You can run it in two modes:
- Shared number — the agent lives on your own WhatsApp account. Its replies are prefixed with the agent name (
Andy: …) so they’re distinguishable from yours. - Dedicated number — a separate phone/SIM for the agent. Setting
ASSISTANT_HAS_OWN_NUMBER=truedrops the name prefix on outbound messages and switches bot-echo detection from prefix matching to sender identity.
Prerequisites
- A phone with WhatsApp installed and online — you’ll link NanoClaw under Settings → Linked Devices
- A working NanoClaw install (quickstart)
- For pairing-code auth: the account’s phone number, digits only with country code (e.g.
14155551234)
Install
WhatsApp is offered in the first-run setup wizard, or add it later by running/add-whatsapp in Claude Code. Both flows do the same thing:
Pick an auth method
QR code (scan with your phone’s camera) or pairing code (enter an 8-character code on your phone — no camera needed). The pairing-code flow asks for your phone number first.
Adapter install
The skill copies
src/channels/whatsapp.ts from the channels branch, wires it into the channel barrel, and installs the pinned Baileys, qrcode, and pino packages.Link your phone
A QR code renders (terminal, or a local browser page via the skill) and rotates every ~60 seconds until scanned. Pairing codes also expire in ~60 seconds — enter them immediately under Linked Devices → Link a Device → Link with phone number instead. Credentials land in
store/auth/, and the wizard restarts the service so the adapter picks them up.Choose your mode
The wizard asks which number you’ll chat from. Same number as the one you linked = shared mode, and messages land in your “You” self-chat. A different number = dedicated mode — the wizard writes
ASSISTANT_HAS_OWN_NUMBER=true to .env (and data/env/env for containers)./manage-channels.
Platform notes
- Auth persistence — credentials live in
store/auth/(multi-file auth state). Restarts reuse the saved session; you only re-pair if WhatsApp logs the device out. On a server-side logout the adapter wipesstore/auth/so the next start prompts a fresh pair. - Activation — the adapter only starts when
store/auth/creds.jsonexists,WHATSAPP_PHONE_NUMBERis set (pairing-code mode), orWHATSAPP_ENABLED=true(QR mode). Otherwise it’s skipped at startup. - Reconnection — on disconnect the adapter reconnects immediately (with one retry after 5s if that attempt throws) unless it was logged out. Messages sent while disconnected are queued in memory and flushed when the connection reopens.
- No threads — the adapter sets
supportsThreads: false; every inbound message has a null thread ID. Wirings withper-threadsession mode behave likesharedhere — see the entity model. - DMs vs groups — DMs always count as addressed to the agent. In groups (
…@g.usJIDs) the agent is by default only triggered by an explicit @-mention of the bot’s number, which the adapter also normalizes to@<agent name>for trigger matching. Group names sync from WhatsApp every 24 hours. - Media — inbound images, video, audio, and documents are downloaded to
data/attachments/and passed to the agent (unsafe attacker-controlled filenames are replaced). Outbound files are sent as native WhatsApp media by extension, with the reply text as the first file’s caption. - Formatting — the agent’s markdown is converted to WhatsApp formatting (
**bold**→*bold*, headings → bold, links →text (url)); code blocks pass through untouched.@<phone>in replies becomes a real tappable mention. - Interactive questions —
ask_user_questionrenders as text with slash-command answers (/approve,/reject); the adapter matches your reply to the pending question. Editing and deleting sent messages isn’t supported (linked-device limitation). - Self-chat — in shared mode you can message the agent in your own “You” chat. The adapter tells your typed messages apart from its own echoes via a sent-message cache.
Troubleshooting
- Logged out / re-pair loop — if logs show
WhatsApp logged outfollowed byWhatsApp auth cleared, the account was unlinked server-side (often a 401). The adapter already wipedstore/auth/; setWHATSAPP_ENABLED=trueand restart (or re-run/add-whatsapp) to scan a fresh QR. Could not fetch current WhatsApp Web version— Baileys’ hardcoded protocol version goes stale and WhatsApp rejects it (405), so the adapter fetches the current version at startup from wppconnect.io with web.whatsapp.com as fallback. This error means both fetches failed: check outbound network access to those hosts.- Agent silent, messages arrive late in a burst — the connection dropped; outbound messages were queued (
WA disconnected, message queuedin logs) and flushed on reconnect. Confirm the lastConnected to WhatsApplog line and that only one NanoClaw process holds these credentials — a second instance causes “conflict” disconnect loops. - QR or pairing code expired — both rotate/expire in ~60 seconds. Re-run the auth step for a fresh code; for pairing codes, the number must be digits only with country code, no
+. If pairing codes keep getting rejected, switch to the QR method — it’s more reliable.