Skip to content

WhatsApp

Backfill only — no live connector

WhatsApp has no sanctioned API for a live poll, so there's no kind in cap_connectors for it and no cap_connectors row to create. The only way to bring WhatsApp history into cap_items is the one-shot backfill below, run against an export you generate yourself.

What it does

Parses a per-chat WhatsApp "Export Chat" archive — the _chat.txt file (iOS or Android) — filtered by date, and normalizes each message into the same cap_items shape as every other connector. No network, no credentials.

Prereqs

Export the chat from the WhatsApp app: open the chat → ⋮ / contact name → More → Export Chat → choose "Without Media" or "Include Media" → save the result. You'll get either a single _chat.txt file or a folder containing _chat.txt plus attachments.

Run it

python -m capture_agent.backfill whatsapp --export <path to _chat.txt or its containing dir> --since 2026-01-01

--since filters to messages on or after that date (YYYY-MM-DD). If --export points at a directory, _chat.txt inside it is preferred; if there's no such file, every .txt file in the directory is parsed.

Verify

The command prints a summary when it finishes, e.g. capture whatsapp backfill: {'ingested': N, 'skipped_dupe': 0, 'unrouted': N, 'entities_created': N, 'errors': 0}. Check cap_items in the PocketBase admin for the new rows.

Notes on the export format

  • Two different mechanisms handle export tokens — don't confuse them.
    • Whole-message system notices are dropped entirely. Author-less notices — the end-to-end-encryption banner, business-account notices, and group subject/description/icon changes — are matched against a fixed phrase list and the whole line is skipped, so they never become a cap_items row. The media-omitted and "edited" markers (image omitted, video omitted, <This message was edited>) genuinely have no localized variants in the export. The group-change phrases are matched in English (the export's observed locale) plus a best-effort set of French variants — so a group-change notice in a language other than English or French may not be recognized as a system notice.
    • Media/attachment tokens are stripped in place. On an actual message the exporter emits an attachment or omitted-media token; the connector removes just that token and keeps the rest of the line as the message body (see the next note).
  • A caption on an attached/omitted media message stays in the body, mid-message. The connector strips only the attachment token itself (<attached: name> on iOS, name (file attached) on Android) or the <kind> omitted marker — any caption text on the same message is left in place around where the token was.

Errors

Per-message parsing failures are logged and skipped so one malformed line never aborts the whole import — re-running the same command later is safe, since cap_items dedupes by external_id and already-imported messages are left alone.