Skip to content

Usage

Run WhatsApp Web Extractor on a browser profile or loose stores, with every option, the output formats, chain of custody and exit codes.

There are no sub-commands. Point wawf at a browser profile and it does the whole job: recovers the device credentials, captures the at-rest key and decrypts.

wawf <PROFILE> --out D:\case\outwawf <PROFILE> --offline --out D:\case\outwawf <PROFILE> --key companion_enc_static.txt --out D:\case\outwawf

In order: capture the key (signs in once) and decrypt everything; never go online and export everything except message text; decrypt offline with a saved key; open the window.

<PROFILE> is the browser profile folder: for Chromium Default, Profile 1 and so on (for example %LOCALAPPDATA%\Microsoft\Edge\User Data\Default); for Firefox the profile folder, or --origin for its web.whatsapp.com storage folder. Nothing is auto-detected: which profile is examined is always your choice. wawf -h prints the locations on your machine.

Close the browser completely first (on Windows, also Edge’s Startup boost and Chrome’s “Continue running background apps”), then copy the profile folder. A running browser keeps writing its stores, and a copy taken meanwhile can lose recent tables, including the key store; then nothing can be decrypted. On a damaged copy the tool reads everything that survived and reports exactly what could not be read.

When only the stores were collected, pass them directly; they can be anywhere and renamed:

wawf --idb "E:\item7\IndexedDB" --local-storage "E:\item7\Local Storage" --out D:\case\out
Option Location in a Chromium profile Needed for
--idb IndexedDB\https_web.whatsapp.com_0.indexeddb.leveldb, or WebStorage\<n>\IndexedDB Messages, chats, contacts, groups, calls, the root key
--local-storage Local Storage\leveldb The key salt, device keys and signed-in account
--media-cache (optional) WebStorage\<n>\CacheStorage, Service Worker\CacheStorage, Cache\Cache_Data Media WhatsApp Web had cached

The tool reads where the profile came from (browser, version, original path) from the folder’s own files and records it in the audit trail.

Option What it does
--out [FORMAT:]PATH Where to write, and in which format (see below). Repeatable
--key FILE A companion_enc_static.txt captured earlier: decrypt without the network. Always a file, never the key itself, so no secret reaches shell history
--offline Never contact WhatsApp. Without a key, exports everything except message text
--chat WHO Only this conversation: a contact or group name, a phone number with country code, a lid or a jid. Repeatable
--partition WHICH Which WhatsApp session to examine when a profile holds several
--list-partitions List every WhatsApp session in the profile, then stop
--origin DIR A Firefox web.whatsapp.com storage folder instead of a profile
--idb, --local-storage, --media-cache Loose stores instead of a profile folder
--history Also pull history older than the browser cache from the phone, resuming across runs. Networked and rate-limited
--history-refetch With --history: re-ask for history already recovered, to fill in fields an earlier run did not capture
--queue After the export, record what WhatsApp’s server is holding for this device, acknowledging nothing
--fetch-media With --out sqlite:PATH: download, decrypt and verify media the browser never cached. Networked
--raw-include-keys With --out raw:: also dump the key-material stores. Such a dump must not travel with a case
--creds FILE Reuse an existing creds_in.json instead of recovering credentials again (skips a minutes-long read of the browser storage). It must describe the same device the profile holds
--yes Auto-confirm prompts that only affect the tool’s own folder. It does not authorise installing Node.js
--install-node Only for the optional Node history engine: allow --history to install Node.js via winget. Modifies the machine and asks for elevation
--no-audit Do not write the chain-of-custody database
--audit-db DB Path for the audit database (default: beside the output)
--case-id ID, --examiner NAME, --case-notes TEXT Case details recorded in the audit database
--audit-secrets Also store raw key material in the audit database (default: only SHA-256 fingerprints)
-v, --log-file FILE Full logs and tracebacks; mirror them to a file
--version Print the version recorded in export receipts and the audit database
wawf <PROFILE> --chat "Book club" --chat +15555550101 --out D:\case\out

A phone number, its lid and its jid are treated as one person. Names are matched exactly (case and spacing aside). A name or number that fits more than one chat, or none, stops the run with exit code 2 and lists the candidates. The export, contacts and group membership then hold only those chats; signing in still delivers whatever the server holds, so --queue and --history keep that outside the export folder.

--out is repeatable. A plain path writes text and JSON.

Form Writes
--out PATH transcripts.txt, chats.json, identities.json
--out txt:PATH Only transcripts.txt
--out json:PATH Only chats.json and identities.json
--out sqlite:PATH Android-layout msgstore.db and wa.db
--out raw:PATH Every store, decrypted in place and otherwise unchanged, with a SHA-256 manifest

A SQLite case database, wawf_audit.db, is written beside the output unless --no-audit is given. Re-running appends a new run, so repeated passes over one case accumulate in one history. It records each run (command, arguments, exit code, host and tool version), every log line, every file opened with its SHA-256, every decryption with key fingerprints, network requests and responses, and every output with its SHA-256.

The wawf window after a run: the command it ran and a log summarising the date range, chats, senders identified and decrypted message count.
After a run: the command line it ran, and its log. Names, numbers and paths are made up. View full size: The wawf window after a run: the command it ran and a log summarising the date range, chats, senders identified and decrypted message count.

The run summary reports how each sender was identified, for example senders identified: address-book=8,120 pushname=3,410 phone=212 unresolved=0. On a healthy profile unresolved is zero.

Code Meaning
0 Success
1 Error (with --history: nothing recovered, or nothing could be asked)
2 Bad usage or a refused combination, including a missing profile or store folder and a --chat that matches no chat or several
3 Wrong key or an unusable --key file, or nothing for --history or --queue to work from
4 A file the run needs was not found
6 The server ended a --queue capture early
130 Interrupted
  • During --history, the default Python engine never asks a sender to re-encrypt a message it cannot decrypt. Such messages are kept as received and counted, but their text is not recovered. The optional Node engine does ask.
  • When the Python engine starts a new Signal session with the phone, it does not verify the signature of the phone’s signed prekey. The Node engine (libsignal) does.

For the full reference (what a browser holds compared with the phone, where the key comes from, the server queue and history recovery), see the documentation on GitHub.