Skip to content

Latest commit

 

History

1,576 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

whatsapp-rust

CodSpeed

A high-performance, async Rust library for the WhatsApp Web API. Inspired by whatsmeow (Go) and Baileys (TypeScript).

Documentation | llms.txt | llms-full.txt

Features

  • Authentication — QR code pairing, pair code linking, persistent sessions
  • Messaging — E2E encrypted (Signal Protocol), 1-on-1 and group chats, editing, reactions, quoting, receipts
  • Media — Upload/download images, videos, documents, GIFs, audio with automatic encryption
  • Voice calls — 1:1 VoIP audio calls with built-in MLOW or external encoded Opus/MLOW; see the codec boundary and production profiles
  • Groups & Communities — Create, manage, invite, membership approval, subgroup linking
  • Newsletters — Create, join, send messages, reactions
  • Status — Text, image, and video status posts with privacy controls
  • Contacts — Phone number lookup, profile pictures, user info, business profiles
  • Presence & Chat State — Online/offline, typing indicators, blocking
  • Chat Actions — Archive, pin, mute, star messages
  • Profile — Set push name, status text, profile picture
  • Privacy — Fetch/set privacy settings, disappearing messages
  • Modular — Pluggable storage, transport, HTTP client, and async runtime; SQLite, Tokio WebSocket, and ureq ship as the defaults, swap any of them with default-features = false
  • Native plugins — Build-time, type-safe extensions with scoped capabilities and lifecycle ownership behind the plugins feature
  • Runtime agnostic — Bring your own async runtime via the Runtime trait (Tokio included by default)

For the full API reference and guides, see the documentation.

Quick Start

[dependencies]
whatsapp-rust = "0.7"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] }
use whatsapp_rust::prelude::*;

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

    // Runs until logout or shutdown; a single await.
    bot.run().await;
    Ok(())
}

The default cargo features wire up the Tokio WebSocket transport, the ureq HTTP client, the SQLite store, and the Tokio runtime; only the storage backend has to be chosen explicitly. Every piece is replaceable through the builder (with_transport_factory, with_http_client, with_runtime) for custom environments such as wasm or embedded targets.

Native plugin APIs are opt-in: use features = ["plugins"] when implementing a plugin in the application. Published plugin crates can enable that feature in their own whatsapp-rust dependency, and Cargo feature unification activates it for the consumer. See agent_docs/plugin_architecture.md for the host contract and type-safe API example.

Codegen flags

The crate sets no target-feature, because a published library cannot know which CPU it will run on and such a flag has no runtime fallback. A binary built with one dies with SIGILL on hardware that lacks the feature — and not necessarily at startup: -C target-feature emits no GNU ISA-needed property, so this configuration gives you no guaranteed load-time check, and it traps whenever execution first reaches an emitted instruction, which can be well into serving traffic. A clean startup is not a compatibility check.

An application that does control its deployment target can take about a fifth of the per-message instruction count on the Signal paths by setting it itself:

# <your app>/.cargo/config.toml
[target.x86_64-unknown-linux-gnu]
rustflags = ["-Ctarget-feature=+bmi2,+avx2"]   # append to what this key holds

Cargo takes rustflags from exactly one source — CARGO_ENCODED_RUSTFLAGS, then RUSTFLAGS, then target.<triple>.rustflags, then build.rustflags — and they never combine, so setting RUSTFLAGS for any reason discards the entry above.

Confirm every deployment target reports both features first, by feature check rather than by the CPU's year or its product name: the Silvermont, Goldmont, Jaguar and Puma cores have neither (Goldmont and Puma are outright later than Haswell), while other parts sold under the same Atom/Celeron/Pentium names do have both. Use an OS-filtered report such as /proc/cpuinfo — AVX2 also needs the OS to have enabled YMM state, which a raw CPUID feature bit does not tell you. The build machine needs both features too unless you pass an explicit --target, since without one cargo applies these flags to build scripts and proc macros as well.

Measurements per flag, the CPU floor each one raises, why +adx and -Ctarget-cpu=native are not worth taking, and the wasm32 equivalent are in agent_docs/build_flags.md.

One dependency is enough

whatsapp-rust re-exports the whole stack, so you never need to declare the sibling crates (wacore, wacore-binary, waproto, whatsapp-rust-tokio-transport, whatsapp-rust-ureq-http-client, whatsapp-rust-sqlite-storage) yourself, including when pinning a git revision:

[dependencies]
whatsapp-rust = { git = "https://github.com/oxidezap/whatsapp-rust", rev = "<commit>" }
  • Protobuf types: whatsapp_rust::waproto::whatsapp (aliased as wa in the prelude)
  • Core protocol/types: whatsapp_rust::wacore, whatsapp_rust::wacore_binary (Jid is also at the crate root)
  • Bundled implementations: whatsapp_rust::transport::TokioWebSocketTransportFactory, whatsapp_rust::http::UreqHttpClient, whatsapp_rust::store::SqliteStore, each behind its default-on cargo feature (tokio-transport, ureq-client, sqlite-storage)

With default-features = false, pick only what you need (e.g. features = ["tokio-runtime", "tokio-transport", "ureq-client"] for a custom store while keeping the bundled networking).

To run the bot in the background instead of blocking, use spawn() and keep the handle:

use whatsapp_rust::prelude::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let bot = Bot::builder()
        .with_backend(SqliteStore::new("whatsapp.db").await?)
        .build()
        .await?;

    let handle = bot.spawn(); // full Client API stays available via handle.client()

    tokio::signal::ctrl_c().await?;
    handle.shutdown().await; // graceful: flushes pending state, then stops
    Ok(())
}

Run the included demo bot:

cargo run --example demo                              # QR code only
cargo run --example demo -- -p 15551234567            # Pair code + QR code
cargo run --example demo -- -p 15551234567 -c MYCODE  # Custom pair code

Project Structure

whatsapp-rust/
├── src/                    # Main client library
├── wacore/                 # Platform-agnostic core (no runtime deps)
│   ├── binary/             # WhatsApp binary protocol
│   ├── libsignal/          # Signal Protocol implementation
│   └── appstate/           # App state management
├── waproto/                # Protocol Buffers definitions
├── storages/sqlite-storage # SQLite backend
├── transports/tokio-transport
└── http_clients/ureq-client

Disclaimer

This is an unofficial, open-source reimplementation. Using custom WhatsApp clients may violate Meta's Terms of Service and could result in account suspension. Use at your own risk.

Acknowledgements

About

Whatsapp client written purely in Rust

Topics

Resources

Stars

721 stars

Watchers

14 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages