High-performance TypeScript implementation of the WhatsApp Web protocol.
Built for high-scalability workloads, multi-session operation, and full user configurability.
- Stability Notice
- What Makes This Project Different
- Core Principles
- Architecture at a Glance
- Requirements
- Quick Start
- Minimal Usage
- Useful Scripts
- Versioning and Releases
- GitHub Release Notes
- Protobuf Generation
- Support the Project
- Contribution Notes
- Disclaimer
Frequent breaking changes are expected until the first major release. If you run
zapoin long-lived environments, pin exact versions and validate upgrades carefully.
zapo is an independent runtime implementation (not a wrapper/fork of an existing WhatsApp library).
- No wrappers around third-party WhatsApp SDKs
- No forks of existing WhatsApp client libraries
- No copied protocol abstractions from community libraries
WAProto.protois sourced fromwppconnect-team/wa-protoand compiled locally for runtime/types
The protocol source of truth is the deobfuscated WhatsApp Web. The target is behavior parity with WhatsApp Web, while improving internal performance and memory efficiency.
These principles drive implementation decisions:
index-first: validate protocol behavior against WhatsApp Web before implementing anythingperformance-first: optimize for low CPU, low RAM, low allocations, and zero-copy in hot pathsasync-first: I/O, network, and crypto operations are async
- Coordinator-first feature design in
src/client/coordinators/ - Pure node builders in
src/transport/node/builders/for reusable protocol stanzas - Incoming parsers/normalizers in
src/client/events/, with coordinators handling orchestration only - Typed store contracts in
src/store/contracts/withmemoryandsqliteproviders - Protocol constants in
src/protocol/usingObject.freeze({...} as const)
Uint8Arrayeverywhere for binary data (Bufferis avoided)- Zero-copy (
subarray, byte views) in critical paths - Bounded in-memory structures to prevent unbounded growth
- Path aliases (
@client,@crypto,@store, etc.), no relative../imports - Named exports only, no default exports
- No enums (
Object.freeze+as constinstead)
- Node.js
>= 20.9.0 - npm
Runtime dependencies:
- Mandatory: none
Optional peer dependencies:
better-sqlite3for SQLite-backed storespinoandpino-prettyfor structured logging
- Install dependencies.
npm install- Run the real-flow example.
npm run example- Scan the QR code emitted by
auth_qr. - Send
pingto the connected session, the example replies withpong.
Auth state is persisted in .auth/state.sqlite.
import { createPinoLogger, createStore, WaClient } from 'zapo-js'
const logger = await createPinoLogger({
level: 'info',
pretty: true
})
const store = createStore({
sqlite: {
path: '.auth/state.sqlite',
driver: 'auto'
},
providers: {
messages: 'sqlite',
threads: 'sqlite',
contacts: 'sqlite'
}
})
const client = new WaClient(
{
store,
sessionId: 'default',
connectTimeoutMs: 15_000,
nodeQueryTimeoutMs: 30_000,
history: {
enabled: true,
requireFullSync: true
}
},
logger
)
client.on('auth_qr', ({ qr, ttlMs }) => {
console.log('qr', { qr, ttlMs })
})
client.on('message', (event) => {
console.log('incoming', {
chatJid: event.chatJid,
senderJid: event.senderJid
})
})
await client.connect()npm run build- build CJS, ESM, and typesnpm run test- run unit tests (non-flow)npm run test:flow- run real-flow testsnpm run test:coverage- run coverage reportnpm run typecheck- type-check projectnpm run lint- lint source filesnpm run format- format codebasenpm run proto:generate- regenerate protobuf runtime/types fromproto/WAProto.protonpm run changeset- create a versioning entry (patch/minor/major)npm run changeset:status- show pending versioning entriesnpm run version:packages- apply pending versions and updateCHANGELOG.mdnpm run release:publish- build and publish to npm with Changesets
Versioning is managed with Changesets.
Release flow:
npm run changeset
npm run changeset:status
npm run version:packages
npm run release:publishNotes:
- Changesets are stored in
.changeset/*.md - Multiple changesets are merged automatically into the next release
- SemVer is manual and intentional:
patch,minor,major
Release notes are generated automatically (including grouped changes and contributors) when a version tag is pushed.
- Workflow:
.github/workflows/github-release.yml - Categories config:
.github/release.yml
Trigger example:
git tag v0.1.1
git push origin v0.1.1If the tag contains - (example: v0.2.0-rc.1), the release is marked as prerelease.
WAProto.proto source: https://github.com/wppconnect-team/wa-proto
npm run proto:generate runs scripts/generate-proto.cjs, which:
- Ensures proto tooling dependencies are installed in
proto/ - Generates and minifies
proto/index.js - Regenerates compact typings at
proto/index.d.ts
If zapo is useful in your production or study setup, you can support ongoing development on GitHub Sponsors:
Before opening a PR:
- Validate behavior against WhatsApp Web
- Keep performance and memory constraints in mind
- Keep node building/parsing aligned with project patterns
- Avoid API changes that diverge from observed WhatsApp Web behavior
- Test real flows when touching auth, transport, app state, retry, or signal paths
This project is an independent implementation for engineering and interoperability research. It is not affiliated with or endorsed by WhatsApp.