Skip to main content

Requirements

zapo requires Node.js >= 20.9.0. The package ships dual ESM/CJS builds and full TypeScript types.

Install the core package

The core package has no mandatory runtime dependencies. Everything else — storage, logging, and the WebSocket transport — is an opt-in peer dependency, so you only install what you use.

The package ecosystem

zapo-js is the only required install. Everything else is an optional @zapo-js/* package you add as needed:
zapo-js — core client, coordinators, store contract
@zapo-js/store-sqlite — SQLite backend
@zapo-js/store-postgres — PostgreSQL backend
@zapo-js/store-mysql — MySQL backend
@zapo-js/store-redis — Redis backend
@zapo-js/store-mongo — MongoDB backend
@zapo-js/media-utils — thumbnails, probes, waveforms
@zapo-js/voip — WhatsApp voice calls
@zapo-js/wam — WhatsApp Web telemetry parity (analytics)
@zapo-js/native — optional Rust NAPI + WASM crypto accelerator
@zapo-js/mcp-server — dev tool: drive from an AI agent
@zapo-js/fake-server — dev tool: in-process test server

Add a storage backend

zapo persists authentication and Signal state through a pluggable store. Pick the backend that matches your deployment and install its package:
You can also run with no backend at all — the built-in memory store works out of the box and is great for tests. It just does not survive a process restart, so you would re-pair on every boot.

Optional peer dependencies

Install these only if you use the corresponding feature:
  • pino + pino-pretty — required only if you use createPinoLogger. Without them, the built-in ConsoleLogger is used.
  • ws — only needed to route the WebSocket through a proxy. The runtime’s native WebSocket can’t take an HTTP Agent/dispatcher, so zapo falls back to ws for the proxy.ws leg. Without a proxy, the built-in WebSocket is used and you don’t need this package.
  • argo-codec — only needed for mobile connections (for now). The standard companion (QR / pairing-code) flow does not use it.

Sending media

@zapo-js/media-utils is effectively required to send usable media. Media still uploads without it, but there’s no processor to generate thumbnails/previews, image-video dimensions, or voice-note waveforms — so it can render as a plain attachment or with no preview. Install it whenever your app sends images, video, audio, documents, or stickers.
It shells out to ffmpeg/ffprobe and uses sharp, so make sure those binaries are available. See the media guide for how to wire the processor into the client.
@zapo-js/media-utils also lists file-type (^19) as an optional peer dependency. Install it (npm install file-type) to enable automatic mimetype detection — without it, the media guide’s mimetype resolution falls back to requiring an explicit mimetype on each send.

Voice calls

Install @zapo-js/voip to place and receive WhatsApp voice calls. It ships as a WaClient plugin and pulls two peer dependencies of its own:
  • @roamhq/wrtc — SCTP for the relay transport.
  • libmlow-wasm — WhatsApp’s Opus profile, as WebAssembly (no native build).
See the VoIP guide for how to wire voipPlugin() into the client.

Telemetry parity

Install @zapo-js/wam to make the session emit the client-side w:stats analytics batches a real WhatsApp Web tab sends — a wire-parity / anti-fingerprinting improvement, not required for messaging.
The only peer dependency is zapo-js. The WAM event registry (@vinikjkkj/wa-wam) is pinned as a regular dependencies entry on the plugin, so it comes down transitively. See the WAM guide for how to wire wamPlugin() into the client. It is opt-in: skip it unless you specifically want the parity.

Native crypto accelerator

Install @zapo-js/native to move the messaging crypto hot path off pure JavaScript — XEdDSA sign/verify (which dominates SKDM sign in group fanout) and X25519 ECDH scalar mult (avoiding the node:crypto.diffieHellman DER round-trip) — onto a Rust core shipped as a WebAssembly build. No toolchain, no post-install compile.
zapo-js try-requires the binding at module load; when the package (or its native binary) is absent, the pure-JS path takes over and the client works unchanged. Installing it is always safe.
Requires Node.js >= 20.19.0: loading the WASM glue relies on require(esm), unflagged only on 20.19+ / 22.12+. On older runtimes the client silently falls back to the pure-JS path.
Two environment variables force the JS path per primitive, useful for A/B measuring or as a kill switch:
  • ZAPO_XEDDSA_FORCE_JS=1 — force JS for XEdDSA sign/verify.
  • ZAPO_X25519_FORCE_JS=1 — force JS for X25519 scalar mult.
To disable the accelerator entirely, set ZAPO_NATIVE_BACKEND=js before the process starts. See the package README for backend selection details.

Verify your setup

Next, head to the quickstart to connect and send your first message.
Last modified on August 1, 2026