website/docs/user-guide/messaging/whatsapp.md
Hermes connects to WhatsApp through a built-in bridge based on Baileys. This works by emulating a WhatsApp Web session — not through the official WhatsApp Business API. No Meta developer account or Business verification is required.
Run
hermes gateway setupand pick WhatsApp for a guided walk-through.
:::warning Unofficial API — Ban Risk WhatsApp does not officially support third-party bots outside the Business API. Using a third-party bridge carries a small risk of account restrictions. To minimize risk:
:::warning WhatsApp Web Protocol Updates WhatsApp periodically updates their Web protocol, which can temporarily break compatibility with third-party bridges. When this happens, Hermes will update the bridge dependency. If the bot stops working after a WhatsApp update, pull the latest Hermes version and re-pair. :::
| Mode | How it works | Best for |
|---|---|---|
| Separate bot number (recommended) | Dedicate a phone number to the bot. People message that number directly. | Clean UX, multiple users, lower ban risk |
| Personal self-chat | Use your own WhatsApp. You message yourself to talk to the agent. | Quick setup, single user, testing |
Unlike older browser-driven bridges, the current Baileys-based bridge does not require a local Chromium or Puppeteer dependency stack.
hermes whatsapp
The wizard will:
To scan the QR code:
Once paired, the wizard confirms the connection and exits. Your session is saved automatically.
:::tip If the QR code looks garbled, make sure your terminal is at least 60 columns wide and supports Unicode. You can also try a different terminal emulator. :::
For bot mode, you need a phone number that isn't already registered with WhatsApp. Three options:
| Option | Cost | Notes |
|---|---|---|
| Google Voice | Free | US only. Get a number at voice.google.com. Verify WhatsApp via SMS through the Google Voice app. |
| Prepaid SIM | $5–15 one-time | Any carrier. Activate, verify WhatsApp, then the SIM can sit in a drawer. Number must stay active (make a call every 90 days). |
| VoIP services | Free–$5/month | TextNow, TextFree, or similar. Some VoIP numbers are blocked by WhatsApp — try a few if the first doesn't work. |
After getting the number:
hermes whatsapp and scan the QR code from that WhatsApp accountAdd the following to your ~/.hermes/.env file:
# Required
WHATSAPP_ENABLED=true
WHATSAPP_MODE=bot # "bot" or "self-chat"
# Access control — pick ONE of these options:
WHATSAPP_ALLOWED_USERS=15551234567 # Comma-separated phone numbers (with country code, no +)
# WHATSAPP_ALLOWED_USERS=* # OR use * to allow everyone
# WHATSAPP_ALLOW_ALL_USERS=true # OR set this flag instead (same effect as *)
:::tip Allow-all shorthand
Setting WHATSAPP_ALLOWED_USERS=* allows all senders (equivalent to WHATSAPP_ALLOW_ALL_USERS=true).
This is consistent with Signal group allowlists.
To use the pairing flow instead, remove both variables and rely on the
DM pairing system.
:::
Optional behavior settings in ~/.hermes/config.yaml:
unauthorized_dm_behavior: pair
whatsapp:
unauthorized_dm_behavior: ignore
unauthorized_dm_behavior: pair is the global default. Unknown DM senders get a pairing code.whatsapp.unauthorized_dm_behavior: ignore makes WhatsApp stay silent for unauthorized DMs, which is usually the better choice for a private number.Then start the gateway:
hermes gateway # Foreground
hermes gateway install # Install as a user service
sudo hermes gateway install --system # Linux only: boot-time system service
The gateway starts the WhatsApp bridge automatically using the saved session.
The Baileys bridge saves its session under ~/.hermes/platforms/whatsapp/session. This means:
If the session breaks (phone reset, WhatsApp update, manually unlinked), you'll see connection errors in the gateway logs. To fix it:
hermes whatsapp
This generates a fresh QR code. Scan it again and the session is re-established. The gateway handles temporary disconnections (network blips, phone going offline briefly) automatically with reconnection logic.
Hermes supports voice on WhatsApp:
.ogg opus) are automatically transcribed using the configured STT provider: local faster-whisper, Groq Whisper (GROQ_API_KEY), or OpenAI Whisper (VOICE_TOOLS_OPENAI_KEY)config.yaml:# ~/.hermes/config.yaml
whatsapp:
reply_prefix: "" # Empty string disables the header
# reply_prefix: "🤖 *My Bot*\n──────\n" # Custom prefix (supports \n for newlines)
WhatsApp supports streaming (progressive) responses — the bot edits its message in real-time as the AI generates text, just like Discord and Telegram. Internally, WhatsApp is classified as a TIER_MEDIUM platform for delivery capabilities.
Long responses are automatically split into multiple messages at 4,096 characters per chunk (WhatsApp's practical display limit). You don't need to configure anything — the gateway handles splitting and sends chunks sequentially.
Standard Markdown in AI responses is automatically converted to WhatsApp's native formatting:
| Markdown | Renders as | |
|---|---|---|
**bold** | *bold* | bold |
~~strikethrough~~ | ~strikethrough~ | |
# Heading | *Heading* | Bold text (no native headings) |
[link text](url) | link text (url) | Inline URL |
Code blocks and inline code are preserved as-is since WhatsApp supports triple-backtick formatting natively.
When the agent calls tools (web search, file operations, etc.), WhatsApp displays real-time progress indicators showing which tool is running. This is enabled by default — no configuration needed.
WhatsApp delivers each message individually, so a rapid burst (forwarded batches, paste-splits, multi-line text) would otherwise trigger a separate agent invocation per fragment — wasting tokens and producing several disjointed replies. The adapter buffers successive text messages from the same chat and dispatches them as one combined request after a short quiet period (default 5s, extended to 10s for very long fragments). Tune via config.yaml:
# ~/.hermes/config.yaml
gateway:
platforms:
whatsapp:
extra:
text_batch_delay_seconds: 5.0 # quiet period before flushing a batch
text_batch_split_delay_seconds: 10.0 # extended delay near the split threshold
Set text_batch_delay_seconds: 0 to dispatch each message immediately (disables batching).
| Problem | Solution |
|---|---|
| QR code not scanning | Ensure terminal is wide enough (60+ columns). Try a different terminal. Make sure you're scanning from the correct WhatsApp account (bot number, not personal). |
| QR code expires | QR codes refresh every ~20 seconds. If it times out, restart hermes whatsapp. |
| Session not persisting | Check that ~/.hermes/platforms/whatsapp/session exists and is writable. If containerized, mount it as a persistent volume. |
| Logged out unexpectedly | WhatsApp unlinks devices after long inactivity. Keep the phone on and connected to the network, then re-pair with hermes whatsapp if needed. |
| Bridge crashes or reconnect loops | Restart the gateway, update Hermes, and re-pair if the session was invalidated by a WhatsApp protocol change. |
| Bot stops working after WhatsApp update | Update Hermes to get the latest bridge version, then re-pair. |
| macOS: "Node.js not installed" but node works in terminal | launchd services don't inherit your shell PATH. Run hermes gateway install to re-snapshot your current PATH into the plist, then hermes gateway start. See the Gateway Service docs for details. |
| Messages not being received | Verify WHATSAPP_ALLOWED_USERS includes the sender's number (with country code, no + or spaces), or set it to * to allow everyone. Set WHATSAPP_DEBUG=true in .env and restart the gateway to see raw message events in bridge.log. |
| Bot replies to strangers with a pairing code | Set whatsapp.unauthorized_dm_behavior: ignore in ~/.hermes/config.yaml if you want unauthorized DMs to be silently ignored instead. |
:::warning
Configure access control before going live. Set WHATSAPP_ALLOWED_USERS with specific
phone numbers (including country code, without the +), use * to allow everyone, or set
WHATSAPP_ALLOW_ALL_USERS=true. Without any of these, the gateway denies all incoming
messages as a safety measure.
:::
By default, unauthorized DMs still receive a pairing code reply. If you want a private WhatsApp number to stay completely silent to strangers, set:
whatsapp:
unauthorized_dm_behavior: ignore
~/.hermes/platforms/whatsapp/session directory contains full session credentials — protect it like a passwordchmod 700 ~/.hermes/platforms/whatsapp/session