WhatsApp

Linking, devices and profiles

Link a WhatsApp device by QR code, manage profiles and understand the single-connection rule.

Read this page when you connect wa to your WhatsApp account for the first time, when you add a second account, or when wa says a profile is not linked. At the end you know how to link, how to check who a profile is, how to unlink, and where wa keeps what it needs to stay linked.

⚠️ wa is an unofficial client of your real WhatsApp account. WhatsApp may ban an account that uses one, and bans accounts that send in bulk or write to strangers. wa writes only when a command asks, limits sends and holds every write when WhatsApp says to slow down. Do not send in bulk or to strangers (limits).

First, the words this page uses:

  • Linked device: wa on this computer, as WhatsApp sees it. You link it from the phone, the way you link WhatsApp Web, and the phone lists it under Settings → Linked devices. Its keys live in one file on this computer. Whoever has that file can read and send as you, so treat it like your password.
  • History push: the copy of your recent chats the phone sends once, seconds after linking. wa keeps what arrives; older messages of one chat can be asked of the phone later (older history).
  • Profile: a name for one linked device on this computer, with its own keys and settings. Every command that uses an account names it, so you pick one name at setup (wa personal setup) and use it from then on (profiles).

First run

wa personal setup guides a first run in five steps: this computer's folders, the link, the account, five chats from the local store, and the agent skill (--agent codex, cursor, claude, gemini, all or none). Allow about five minutes, most of it the history push. Run it in a terminal. A profile linked before is checked without linking again, and nothing is asked. Before the QR code or the pairing code, setup and session start print the warning above on stderr, once per link. wa personal session start is the command for the link alone.

Linking

wa personal session start          # a QR code in the terminal
wa personal session start phone    # your number, typed in the terminal, then a code to type on the phone

QR: scan the code in WhatsApp on the phone: Settings → Linked devices → Link a device. The code is renewed while you wait.

Phone: type your number in international format when wa asks. wa shows an eight-character pairing code; on the phone, open Settings → Linked devices → Link a device → Link with phone number instead, and type it. The number goes to the engine on its input, never as an argument, so other programs on this computer cannot see it in the list of processes.

Right after either, the phone pushes your history. session start keeps the same connection open, saves what arrives into the local store, and stops when the phone has been quiet for 45 seconds, or at Ctrl+C. Ctrl+C there, or --timeout, ends only this wait: the device stays linked, what arrived is kept and counted, and the command ends with exit code 0. wa personal setup waits the same way, then goes on to its remaining steps under the command's usual time limit, started afresh. Then keep receiving with wa personal server install (the local store).

Your AI agent can start the link for you. Without a terminal, wa prints the QR code as plain text, and the agent pastes it into the chat for you to scan:

wa personal setup --agent claude --json
wa personal session start qr

The agent runs the command in the background, since it waits for your scan. WhatsApp sends a new code after 60 seconds and then every 20 seconds; the agent pastes each new one and says the old one expired. With --json, each code is also one line on stderr: {"event":"qr","qr":{"text":…,"expires_at":null,"scan":…}}. The text is about 73 columns wide. Linking is not offered over MCP: an app that only has MCP asks you to run the command. A pairing code is for you to run in your own terminal: an agent never asks you for your phone number or a code in the chat.

wa personal account show     # who this profile is linked as; the phone number shows only its last four digits
wa account list              # every profile on this computer, and the account each is linked as
wa personal session end      # unlink the device on WhatsApp's side, and delete its keys here

Change your name, about and photo

wa personal account update --first-name Ana --last-name Silva   # WhatsApp keeps one name: "Ana Silva"
wa personal account update --description "Back on Monday"       # the "about" line
wa personal account update --photo ~/me.jpg                     # the profile photo, a square JPEG

The name goes to the phone and your other devices at once. Other people probably see it only once the phone next comes online: a device tells WhatsApp its name when it says it is online, and wa never does. A device linked a few minutes ago may not have WhatsApp's settings keys yet; keep serve running a while and try again.

For a profile photo, wa requires a square JPEG from 190 to 720 pixels per side, using the same validation as for a group photo. wa does not convert or crop images and rejects PNG or WebP content before changing anything. When name, about and photo are supplied together, they are changed in that order; a later error names the changes already made. Remove the photo from the phone.

wa personal session end removes the device on WhatsApp's side too: it disappears from the phone's list of linked devices. It leaves the local store as it is. While serve runs for the profile, it refuses (exit code 12): stop serve first with wa personal server stop, or Ctrl+C where it runs.

One connection per device

WhatsApp allows one connection for each linked device; a second one makes WhatsApp drop the first. So one wa command at a time may connect a profile. serve, watch and every command that connects take the device's lock first; another command for the same profile is refused and names the holder:

this WhatsApp login is in use by serve (pid 4242)

serve is the exception. While it runs, a command for the same profile that would connect does not take the lock: it runs inside serve, on serve's connection. It reaches serve through a socket next to serve's lock (<state>/serve/<profile>.sock, mode 0600, so only your own user can open it). This covers sends, edits, deletions, reactions, marking read, downloads, group and people commands, watch, doctor --online and the MCP server wa <profile> mcp. The send guard and the profile's permissions still apply. A command run this way never asks: a write at permission level ask needs --yes (--allow-dangerous for a deletion), or it is refused and says so.

  • Not through serve: linking and unlinking (session start, session end, setup) and mcp --http. chats list and chats show read the local store, so they never connect. --offline and --dry-run runs do not connect at all.
  • serve is starting or does not answer: the command fails. It never opens a second connection.
  • wa was upgraded and serve not restarted: the command runs inside the older serve, with its code. When the two speak different relay versions, the command is refused and says to restart serve. wa upgrade restarts running servers itself; otherwise use wa <profile> server restart.
  • Windows: commands do not go through serve. While serve runs, a command that connects is refused as above, with exit code 12.

With no serve running, each command connects on its own. While one of them holds the device, or wa personal mcp, which keeps its connection for two minutes after a call, serve cannot start. Reads never connect, so they work beside any of them.

Until it is ended: by wa personal session end, from the phone's list of linked devices, or by WhatsApp itself. The phone must come online now and then, or WhatsApp logs its linked devices out. When the device was removed, every command that connects says so with exit code 4; link again with wa personal session start (WhatsApp logged this device out).

Profiles

A profile is a separate linked device: its own keys, settings, recipients and runs. It is named by the first word, not by an option:

wa personal chats list     # profile "personal"
wa work chats list         # profile "work"
export WA_PROFILE=work     # the same for the whole shell session

The first word is the profile when it is not a command. A profile therefore cannot be called chats, messages or any other command word. Names are letters, digits, dot, dash and underscore, starting with a letter or a digit.

The order, first match wins: the first word, then WA_PROFILE. With neither, a command that uses an account stops with exit code 2 and lists the profiles on this computer. wa never picks one, not even the only one. Commands that use no account run without a profile: --help, --version, commands, skill show, account list and config show.

WA_PROFILE_LOCK pins a process to one profile. Set it where an agent runs, and a first word or WA_PROFILE naming any other profile is refused (exit code 5). Without it, an agent could pick a profile with fewer limits.

What each profile is for: profiles.

Where the parts are kept

WhatWhere
the device keys~/.local/share/whatsapp-cli/profiles/<profile>/private.db, readable by your user only
who holds the one connectionprivate.db.lock beside it
chats and messagesthe WireCat store every WireCat CLI shares, ~/.local/share/WireCat/wirecat.db
settings~/.config/whatsapp-cli/config.json; never a secret

WA_CONFIG_DIR, WA_STATE_DIR and WA_CACHE_DIR move the three folders (configuration reference).

Next