Library / SDK
oxidezap/whatsapp-rust avatar
oxidezap/whatsapp-rust

whatsapp-rust, an async Rust client for WhatsApp Web

Whatsapp client written purely in Rust

933 stars154 forksRustMIT

At a glance

What is it?
whatsapp-rust is a Rust library that speaks the WhatsApp Web protocol directly, with QR pairing, end-to-end encrypted messaging, calls and a workspace where storage, transport and HTTP client are all replaceable. It is unofficial, and using it may get a number suspended.
Who is it for?
whatsapp-rust fits Rust developers building a WhatsApp bot or a service that needs end-to-end encrypted messaging with its own storage and transport, and it does not fit teams that need an officially supported channel or that cannot accept the account risk of a third-party client.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A client that speaks the protocol instead of wrapping one

whatsapp-rust is described as an async Rust library for WhatsApp Web. Pair a device, send and receive end-to-end encrypted messages, and build on a modular protocol stack. The word that carries the meaning is library. There is no browser process, no bridge to a running client, and no automation of a user interface. The protocol is implemented in Rust, which is also the primary language of the repository.

The capability list is broad for a client library. Authentication covers QR and pairing-code authentication with persistent sessions. Messaging is end-to-end encrypted and covers direct and group messaging, media, reactions, receipts and history sync. The social surface includes groups, communities, newsletters, status, contacts and privacy controls. There are audio and video calls in both one-to-one and group form, plus call links and screen sharing.

The structure of the crate reflects a deliberate separation. The default features include SQLite, Tokio WebSocket, ureq and Tokio, and the documentation is explicit that applications still choose a storage backend. Storage, transport, HTTP client and runtime are all replaceable, and native plugins are opt-in rather than always on. That is the architectural claim worth testing: how much of the stack you inherit versus how much you swap.

Pairing by QR code or pairing code, with sessions that persist

Authentication is the first thing you have to solve, and the library offers the two routes a WhatsApp Web client is expected to offer. QR authentication is the familiar one, where a phone scans a code that the library renders. Pairing-code authentication is the alternative for devices without a comfortable screen for a QR code, and the docker image documents the phone-number route with a --phone argument for pair code auth.

What matters more than the method is the persistence. Sessions are persistent, which means the paired state is not held only in memory between calls. In the quick start, the backend is opened from a SQLite file called whatsapp.db, so the device identity and the session live on disk and survive a restart of your process. That is the difference between a toy example and something you can run as a service, and it is why the storage layer is a swappable component rather than a hidden detail.

The alternative to a file-backed session is up to the application, because the storage backend is pluggable. The workspace contains a SQLite storage crate as the default path, and the documentation points to the site for alternative backends and configuration. If you intend to run several instances, or to keep session state somewhere else entirely, that is the knob to look at first.

The workspace shows where the protocol actually lives

The Cargo.toml workspace lists a lot of crates, and the names tell you the design. wacore is the core, and inside it sit appstate, binary, derive, libsignal and noise. The libsignal and noise crates are the cryptographic transport pieces, which is where end-to-end encrypted messaging gets its footing. waproto is the protocol definitions crate. Outside the core sit storages/sqlite-storage, transports/tokio-transport and http_clients/ureq-client, one crate per replaceable layer.

There are also plugins/metrics and plugins/wam, plus wam-catalog, and a tools/ directory with whatspec-codegen and oracle-cli, oracle-core and oracle-task. The whatspec-codegen crate ties back to a related project called whatspec, which extracts a language-neutral protocol specification from WhatsApp Web, and the documentation states that its IR supplies the protocol definitions generated in this repository. In other words, the wire format is derived from a generated specification rather than transcribed by hand, which is the only sane way to track a proprietary protocol.

The workspace also shows the project's testing posture. There are tests/bench-integration and tests/e2e crates, a benches/ directory, and the package metadata explicitly disables auto-discovery of bench targets so that a stray file on a reused CI runner cannot be compiled as a phantom benchmark. The examples/ directory adds alloc_tracking, benchmark, metrics, observability, retry_quarantine and a voip-cli, which are useful reading for anyone extending the library.

Calls, video frames and what the library leaves to you

The optional voip feature provides native relay transport and MLOW/Opus audio. That is the part of the stack that decides whether a call actually works over a given network, and it is opt-in, so a project that only sends messages never compiles it.

Video is deliberately asymmetric. Video takes application-supplied H.264 frames, with the media API and codec options documented in a separate whatsapp-rust-docs repository. The library does not capture, encode or decode your camera feed; it accepts frames you have already produced in H.264 and transports them. For a text and voice bot that is irrelevant. For a video calling client it is a significant amount of work that stays on your side of the line, and it is the clearest example of the library's philosophy of giving you the protocol and leaving the media pipeline alone.

The same pattern appears in the surrounding projects. oxidezap/client is a desktop and browser client built on this library as a complete application, whatsapp-rust-esp32 demonstrates the core on microcontrollers, whatsapp-rust-bridge provides Rust and WebAssembly utilities for JavaScript, and baileyrs is a JavaScript library backed by Rust and WebAssembly with a Baileys-compatible API. Together they show the intended split between a protocol library and the applications built on it.

The quick start is one dependency block and one bot

Adding the library is a normal Cargo dependency. The main crate re-exports the bundled stack, so you do not need to add its sibling crates separately, and the version shown in the quick start is 0.7:

toml
[dependencies]
whatsapp-rust = "0.7"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] }

The bot itself is built with a builder pattern. You supply a backend, a QR code callback and a message callback, then call run:

rust
use whatsapp_rust::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let bot = Bot::builder()
        .with_backend(SqliteStore::open("whatsapp.db").await?)
        .on_qr_code(|code, _timeout| async move {
            println!("Scan to pair:\n{code}");
        })
        .build()
        .await?;

    bot.run().await;
    Ok(())
}

The QR callback receives the code and a timeout, so the caller decides how to display it. If you would rather track a specific Git revision than the crates.io release, the same dependency can be pointed at the repository with a git and rev pair, using the commit placeholder shown in the documentation. The package metadata for docs.rs builds with the passkey and plugins features enabled, so the published documentation covers more than the default feature set.

A scratch container, an unprivileged user and one volume gotcha

The Dockerfile builds a fully static musl binary that runs in a scratch container, meaning an empty image with no shell and no package manager. The comment explains the choice of musl over glibc for a long-running process: predictable memory usage with no fragmentation from the per-thread arena allocator. The build uses cargo-chef pinned to an exact release so image rebuilds are deterministic instead of tracking the latest crates.io release.

The two commands the image documents are:

bash
docker build -t whatsapp-rust .
docker run -v whatsapp-data:/data whatsapp-rust

The /data volume persists the SQLite database across restarts. The image runs unprivileged as uid 65532, and the documentation is careful about why a named volume is used rather than a host bind mount, since a named volume inherits the ownership and stays writable while a bind mount would need matching ownership.

That leads to the one operational trap in the whole file. Upgrading from an older image that ran as root leaves root-owned files in the existing volume, which uid 65532 cannot write, so the fix is a one-off chown using any image that ships chown, since scratch does not. The image also documents the pair code route as a flag, docker run -v whatsapp-data:/data whatsapp-rust --phone 15551234567, for a headless container that has no screen to show a QR code on.

Unofficial by construction, and the version number tells you how far along it is

The disclaimer is short and unambiguous. This is an unofficial client, not affiliated with WhatsApp or Meta, using it may violate Meta's Terms of Service and could result in account suspension. That is not boilerplate in the same way it usually is, because the whole architecture depends on it. The library implements the same protocol the official clients use, so the behaviour that gets an account restricted is the behaviour this library depends on.

The version numbers carry their own message. The crate is at 0.7.0, with 0.6.0 and 0.5.0 before it, and the workspace declares a minimum supported Rust version of 1.94 with edition 2024. A pre-1.0 crate is expected to break between releases, so pinning an exact version in Cargo.lock is the sensible starting point rather than tracking main.

The last push was on 2026-10-20 and the newest tagged release is v0.7.0 from 2026-08-07, so the repository is moving faster than its tags. The licence field on the repository says MIT, the same licence the Cargo.toml declares, which is the permissive choice for a library that others will embed in their own applications. The acknowledgements name whatsmeow and Baileys as the inspirations, which tells you the shape of the design: the protocol approach follows the Go library, and the JavaScript-friendly surface follows the Node one.

Editorial conclusion

whatsapp-rust fits Rust developers building a WhatsApp bot or a service that needs end-to-end encrypted messaging with its own storage and transport, and it does not fit teams that need an officially supported channel or that cannot accept the account risk of a third-party client. Before you adopt it, check that the API of the WhatsApp account you intend to use tolerates unofficial clients, pin the crate version rather than tracking the main branch, since the crate is still pre-1.0, and read the docker run command for the volume ownership issue before deploying the scratch image.

Frequently asked questions

What is whatsapp-rust and what can it do?

It is an async Rust library that implements the WhatsApp Web protocol directly. It covers QR and pairing-code authentication with persistent sessions, end-to-end encrypted direct and group messaging, media, reactions, receipts, history sync, communities, newsletters, status, contacts, privacy controls, and audio and video calls including call links and screen sharing.

How do I add whatsapp-rust to a Cargo project?

Add whatsapp-rust = "0.7" under [dependencies], along with tokio. The main crate re-exports the bundled stack, so you do not need to add the sibling crates such as the SQLite storage or the Tokio transport separately.

Can I use my own storage, transport or HTTP client?

Yes. Storage, transport, HTTP client and runtime are all replaceable, and the default features include SQLite, Tokio WebSocket, ureq and Tokio. Native plugins are opt-in rather than enabled by default.

How do I run whatsapp-rust in Docker?

The Dockerfile builds a fully static musl binary for a scratch container. Build it with docker build -t whatsapp-rust . and run it with docker run -v whatsapp-data:/data whatsapp-rust, where the named volume persists the SQLite database and inherits the ownership needed by the unprivileged uid 65532.

Is using whatsapp-rust against WhatsApp's Terms of Service?

The project states that it is an unofficial client, not affiliated with WhatsApp or Meta, and that using it may violate Meta's Terms of Service and could result in account suspension. It is also pre-1.0, so expect breaking changes between releases.

Official sources

  1. License: MIT
  2. oxidezap/whatsapp-rust on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/oxidezap-whatsapp-rust.svg)](https://hysenlabs.com/projects/oxidezap-whatsapp-rust)

Was this useful?