Connect your AI agent to WhatsApp via Baileys.
Setup
pnpm add @whiskeysockets/baileys
pnpm add qrcode-terminal # optional: print the pairing QR in the terminalHow It Works
WhatsApp doesn't have a bot API like Telegram. Instead, Baileys connects as a "linked device" to your personal WhatsApp account (like WhatsApp Web). This means:
- Your agent responds as your WhatsApp number
- No separate bot account needed
- Works with personal and business WhatsApp
First-Time Pairing
- Start the gateway — a QR code appears in the terminal (requires
qrcode-terminal; otherwise passqrCallback) - On your phone: WhatsApp → Settings → Linked Devices → Link a Device
- Scan the QR code
- Session is saved to disk — next restart reconnects automatically
Usage
import { Gateway, whatsappChannel } from '@cogitator-ai/channels';
const whatsapp = whatsappChannel({
sessionPath: '.cogitator/whatsapp-session',
printQr: true,
});
const gateway = new Gateway({ agent, cogitator, channels: [whatsapp] });
await gateway.start();Use with cogitator up
Add a whatsapp entry to cogitator.yml (the wizard does not ask about it, but cogitator wizard --edit keeps it):
channels:
whatsapp:
ownerIds:
- '15551234567' # phone number without @s.whatsapp.net
sessionPath: ~/.cogitator/whatsapp-session # defaultcogitator up (or RuntimeBuilder) starts the channel with the QR printed in the terminal on first run. ownerIds work like on other channels: the first one gets owner commands and self-config access. See the config reference.
Configuration
interface WhatsAppChannelConfig {
sessionPath?: string; // default: '.cogitator/whatsapp-session'
qrCallback?: (qr: string) => void; // takes precedence over printQr
printQr?: boolean; // default: true, uses qrcode-terminal
}Features
| Feature | Support |
|---|---|
| 1-on-1 chats | ✅ |
| Group chats | ✅ |
| Streaming (edit) | ✅ via message edits |
| Typing indicator | ✅ (presence update) |
| Reactions | ❌ |
| Incoming media | ✅ images, voice, video, documents (+ captions) |
| Sending files | ✅ image / audio / video / document by type, from buffers or URLs |
| Quoted replies | ✅ for recent messages |
| Markdown | ✅ WhatsApp-native formatting |
| Auto-reconnect | ✅ exponential backoff (1s → 60s), not after stop() or logout |
| Session persistence | ✅ (filesystem) |
User ids
Baileys 6 and 7 both work. WhatsApp increasingly addresses people by a private id (LID, ...@lid) instead of their phone number; Baileys 7 passes the number along when WhatsApp shares it. A message's userId is the phone number whenever it is known — so owner lists and per-user memory keep matching — and the LID only for someone whose number WhatsApp hides. Replies go to the chat the message came from either way: channelId is the chat JID (the group JID in groups, where groupId is set too). Messages you send yourself from the linked phone are ignored.
WhatsApp Markdown
WhatsApp uses its own formatting syntax. Cogitator auto-converts standard markdown before sending:
| Standard | |
|---|---|
**bold** | *bold* |
__bold__ | *bold* |
~~strike~~ | ~strike~ |
# Heading | *Heading* |
[text](url) | text (url) |
| Code blocks | Preserved |
| Inline code | Preserved |
Limitations
- QR code expires after ~20 seconds, bot retries automatically
- If you unlink the device from your phone (logout), the channel stops reconnecting; delete the
sessionPathdirectory and restart to pair again - WhatsApp may temporarily ban automated accounts with high message volume
Tips
- Use a dedicated phone number for production bots
- The
sessionPathdirectory must be writable - Use
qrCallbackto display the QR in a web UI instead of terminal