whatsapp-web-cli
v0.2.3
Published
A local WhatsApp Web CLI for agents and scripts.
Maintainers
Readme
WhatsApp Web CLI
wwa is a local WhatsApp Web CLI for agents and scripts. It uses whatsapp-web.js, persists auth locally, exposes JSON-friendly commands, and keeps realtime state in a local daemon.
Requirements
- Node.js 22+
- Bun 1.3+ for local install/build tasks
- ffmpeg for
wwa send audio --voice/wwa reply audio --voiceconversion when the input is not already OGG/Opus - macOS/Linux with a local Chromium/Puppeteer-compatible environment
- A WhatsApp account that can link WhatsApp Web
The package is managed and built with Bun, but the published wwa binary runs on Node. This keeps whatsapp-web.js/Puppeteer on the runtime they support best.
Install
From a published package:
npm install -g whatsapp-web-clior:
bun install -g whatsapp-web-cliFrom this local folder:
bun install
bun run build
bun linkThen run the command you actually need:
wwa chat-search "Name" --jsonTo install the bundled Codex skill for local agent use:
wwa skill install --jsonBy default this writes:
~/.agents/skills/whatsapp-cli/SKILL.mdCodex reads user skills from ~/.agents/skills. For a repository-scoped skill,
install into a repo folder explicitly:
wwa skill install --dir .agents/skills --jsonIf WhatsApp is not logged in, data commands return a JSON object like:
{
"ok": false,
"ready": false,
"message": "You need to login. Run `wwa auth login --image --json`.",
"nextCommand": "wwa auth login --image --json"
}Run that login command, render/open the returned imagePath, and scan it in
WhatsApp > Linked Devices. After scanning, run the original command again:
wwa auth login --image --json
wwa chat-search "Name" --jsonThere is no required doctor or ready step in normal usage. Data commands
auto-start the daemon and wait for readiness after auth is scanned.
If the first run fails before a QR appears because Puppeteer cannot find or launch Chrome-for-Testing, run the browser recovery command recommended by the CLI:
wwa recover browser --jsonOn macOS, if that reports a launch failure for the downloaded Chrome-for-Testing app, explicitly allow the CLI to clear quarantine metadata from that isolated test browser:
wwa recover browser --clear-quarantine --jsonThen retry:
wwa auth login --image --jsonCommon Flow
wwa chat-search "Gardelin" --json
wwa message-search "Aaah" --chat <chatId> --json
wwa unread --limit 20 --jsonCommon Commands
wwa daemon start --json
wwa daemon stop --json
wwa daemon status --json
wwa auth login --image --json
wwa auth status --json
wwa auth logout --json
wwa ready --wait 120 --json
wwa doctor --json
wwa doctor --browser --json
wwa recover browser --json
wwa chat-search "name or text" --json
wwa message-search "message text" --limit-chats 20 --messages-per-chat 50 --json
wwa message-search "message text" --chat <chatId> --json
wwa unread --limit 20 --json
wwa unread messages --limit-chats 10 --messages-per-chat 5 --json
wwa chats list --unread --limit 20 --json
wwa messages list --chat <chatId> --limit 50 --json
wwa events list --since 24h --json
wwa events next --chat <chatId> --incoming --timeout 120 --json
wwa events tail --chat <chatId> --incoming --jsonl
wwa media save --message <messageId> --json
wwa transcribe --message <messageId> --json
wwa transcribe --file ./audio.oga --json
wwa tts --text "Mensagem em voz natural." --out /tmp/voice.mp3 --json
wwa tts --text "Mensagem em voz natural." --to <chatId> --json
wwa send text --to <chatId> --body "..."
wwa send media --to <chatId> --file ./image.png --caption "..."
wwa send audio --to <chatId> --file ./note.ogg --voice
wwa reply text --message <messageId> --body "..."
wwa reply media --message <messageId> --file ./file.pdf --as-document
wwa reply audio --message <messageId> --file ./note.ogg --voiceevents tail follows new events from the end of the log by default. Use
--replay only when you intentionally want to replay stored history before
following new events.
events next is the best primitive for agents that need to answer live
messages. It waits for one matching event, prints it, and exits. It also starts
from the end of the event log by default, so agents do not accidentally answer
old messages unless --replay is explicitly provided.
Media commands send existing local files only. Classification and reply drafting
belong in a higher-level agent workflow.
When --voice is used with an MP3, AIFF, WAV, or other non-OGG audio file,
wwa converts it to OGG/Opus with ffmpeg before sending.
OpenAI TTS Workflow
For higher-quality voice notes, use wwa tts instead of macOS say. It calls
OpenAI text-to-speech with gpt-4o-mini-tts and voice nova, writes an MP3
locally, then optionally sends it as a WhatsApp voice note.
wwa tts --text "Mensagem em voz natural." --out /tmp/voice.mp3 --voice nova --json
wwa tts --text "Mensagem em voz natural." --to <chatId> --jsonThe command reads OPENAI_API_KEY from .env.local, .env, or the process
environment.
OpenAI Transcription Workflow
To transcribe WhatsApp audio without hand-normalizing file extensions:
wwa transcribe --message <messageId> --json
wwa transcribe --file ~/.wwa/default/media/audio.oga --json
wwa transcribe --message <messageId> --to <chatId> --jsonThe command saves media when given a message ID, renames WhatsApp .oga voice
notes to .ogg for OpenAI compatibility, and uses gpt-4o-mini-transcribe by
default.
Runtime Data
The default profile stores runtime state under:
~/.wwa/default/Auth persists across daemon restarts in:
~/.wwa/default/auth/You should only need to scan a QR again if WhatsApp invalidates the linked device, you run wwa auth logout, or the auth folder is removed/corrupted.
Codex Skill
The generic skill is included in the package at:
skills/whatsapp-cli/SKILL.mdInstall or update it for Codex with:
wwa skill install --jsonIt teaches agents to use the CLI directly, without MCP, and keeps transcription/classification workflows outside the low-level CLI.
