# BaileysEx
[](https://hex.pm/packages/baileys_ex)
[](https://hexdocs.pm/baileys_ex)
[](https://github.com/jeffhuen/baileys_ex/blob/main/LICENSE)
**WhatsApp Web API client for Elixir** — a behaviour-accurate port of
[Baileys](https://github.com/WhiskeySockets/Baileys) that brings the full
WhatsApp multi-device protocol to the BEAM.
BaileysEx connects directly to WhatsApp's WebSocket-based protocol. No browser
automation, no headless Chrome, no external Node.js sidecar. Just a supervised
Elixir process tree that handles the Noise handshake, Signal Protocol encryption,
binary XMPP framing, and the complete WhatsApp feature surface — natively.
> **Note:** This library communicates with WhatsApp's servers using a reverse-engineered
> protocol. It is not affiliated with, authorized by, or endorsed by WhatsApp or Meta.
> Use responsibly and in accordance with WhatsApp's Terms of Service.
## Features
### Authentication
- **QR code pairing** — scan from WhatsApp mobile to link a new device
- **Phone number pairing** — enter a numeric code instead of scanning
- **Persistent sessions** — save credentials to disk and reconnect without re-pairing
- **Multi-device protocol** — operates as a linked companion device
### Messaging
- **End-to-end encryption** via the Signal Protocol (pure Elixir implementation)
- **27+ message types** — text, images, video, audio, documents, stickers, contacts, location, polls, reactions, forwards, edits, deletes, and more
- **Quoted replies and mentions** — reply to and reference specific messages
- **Delivery tracking** — delivery receipts, read receipts, played receipts
- **Link previews** — attach URL preview metadata to outbound messages
### Media
- **Upload and download** — images, video, documents, audio, stickers, GIFs, voice notes
- **Streaming architecture** — encrypted media with AES-256-CBC + HMAC, never loads entire files into memory
- **Automatic key management** — HKDF-derived media keys with type-specific info strings
- **Stale URL refresh** — re-request expired media download URLs from paired devices
### Groups and Communities
- **Full group lifecycle** — create, update subject/description, leave, delete
- **Participant management** — add, remove, promote, demote
- **Invite flows** — v3/v4 invite codes, join-by-link, join approval
- **Community support** — create communities, link/unlink subgroups, manage metadata
- **Group settings** — ephemeral messages, announcement mode, membership approval
### Presence and Status
- **Online/offline/typing indicators** — send and subscribe to presence updates
- **Profile management** — get/set profile pictures, push names, status text
- **Contact validation** — check which phone numbers are registered on WhatsApp
- **Business profiles** — fetch and manage business profile data, catalogs, collections
### Newsletters
- **Subscribe/unsubscribe** — follow and unfollow WhatsApp channels
- **Create and manage** — create, update, and delete newsletters
- **Interact** — mute, react, and fetch newsletter content
### App State Sync
- **Cross-device sync** — archive, mute, pin, star, and read state synced across linked devices
- **LTHash integrity** — rolling hash verification detects drift or tampering before applying patches
- **Full Syncd codec** — encode and decode WhatsApp's versioned app state patch format
### Analytics
- **WAM encoding** — build and send WhatsApp Analytics and Metrics buffers for Baileys wire parity
## Why Elixir?
BaileysEx isn't just a translation — it's a reimagining of Baileys for a runtime
built for exactly this kind of work:
| Baileys (Node.js) | BaileysEx (Elixir/OTP) |
|----|-----|
| Callbacks and Promises | Supervised process trees with `:rest_for_one` restart strategy |
| `async-mutex` library | BEAM processes — concurrency is the runtime, not a library |
| Manual reconnect logic | `:gen_statem` state machine with automatic reconnection |
| `node-cache` / `lru-cache` | ETS tables — concurrent, lock-free, built into the VM |
| `pino` logging | `Logger` with structured metadata and configurable backends |
| Single-threaded event loop | Preemptive scheduling across all available cores |
| Process crash = app crash | Supervisor restarts failed children — let it crash |
**Crypto is native too.** All cryptographic primitives (AES, HMAC, SHA, PBKDF2,
Curve25519, Ed25519) use Erlang's built-in `:crypto` module — no external C/Rust
for standard operations. Rust NIFs are used only for the Noise Protocol framework
(`snow`) and XEdDSA signing (`curve25519-dalek`), where no Erlang/Elixir
equivalent exists.
## Quick Start
### Installation
Add `baileys_ex` to your `mix.exs` dependencies:
```elixir
def deps do
[
{:baileys_ex, "~> 0.1.0-alpha.2"}
]
end
```
**Requirements:** Elixir 1.19+, OTP 28, Rust toolchain (for NIF compilation).
### Choose a persistence backend
- `BaileysEx.Auth.NativeFilePersistence.use_native_file_auth_state/1` is the
recommended default for Elixir-first apps. It stores credentials and Signal
keys in durable ETF files with crash-safe writes.
- `BaileysEx.Auth.FilePersistence.use_multi_file_auth_state/1` keeps the
Baileys-compatible multi-file JSON layout when you need that on-disk contract.
Treat it as a compatibility bridge for teams migrating off a Baileys JS
sidecar, not as the long-term Elixir-first default.
- Custom SQL/NoSQL backends remain supported through
`BaileysEx.Auth.Persistence` and `BaileysEx.Signal.Store`.
### Connect and pair
```elixir
alias BaileysEx.Auth.NativeFilePersistence
alias BaileysEx.Connection.Transport.MintWebSocket
# Load or create auth state
{:ok, persisted_auth} =
NativeFilePersistence.use_native_file_auth_state("tmp/baileys_auth")
parent = self()
# Start the connection
{:ok, connection} =
BaileysEx.connect(
persisted_auth.state,
Keyword.merge(persisted_auth.connect_opts, [
transport: {MintWebSocket, []},
on_qr: fn qr -> IO.puts("Scan QR: #{qr}") end,
on_connection: fn update -> send(parent, {:connection_update, update}) end
])
)
# Persist credentials on update
BaileysEx.subscribe_raw(connection, fn events ->
if Map.has_key?(events, :creds_update) do
{:ok, latest} = BaileysEx.auth_state(connection)
:ok = persisted_auth.save_creds.(latest)
end
end)
# Wait for the connection to open
receive do
{:connection_update, %{connection: :open}} -> :connected!
after
30_000 -> raise "timed out waiting for connection"
end
```
If you specifically need Baileys-compatible JSON auth files during a sidecar
migration or compatibility rollout, swap in
`BaileysEx.Auth.FilePersistence.use_multi_file_auth_state/1`.
### Send a message
```elixir
{:ok, _sent} =
BaileysEx.send_message(connection, "15551234567@s.whatsapp.net", %{
text: "Hello from BaileysEx!"
})
```
### Listen for incoming messages
```elixir
BaileysEx.subscribe(connection, fn
{:message, msg} -> IO.inspect(msg, label: "incoming")
{:connection, update} -> IO.inspect(update, label: "connection")
_other -> :ok
end)
```
### Send media
```elixir
{:ok, _sent} =
BaileysEx.send_message(connection, "15551234567@s.whatsapp.net", %{
image: {:file, "photo.jpg"},
caption: "Sent from Elixir"
})
```
## Documentation
Full guides and API reference are available on [HexDocs](https://hexdocs.pm/baileys_ex).
| Section | What you'll learn |
|---------|-------------------|
| [Installation](https://hexdocs.pm/baileys_ex/installation.html) | Prerequisites, dependency setup, compilation |
| [First Connection](https://hexdocs.pm/baileys_ex/first-connection.html) | QR pairing, phone pairing, credential persistence |
| [Send Messages](https://hexdocs.pm/baileys_ex/messages.html) | Text, replies, reactions, polls, forwards, edits |
| [Media](https://hexdocs.pm/baileys_ex/media.html) | Upload images/video/docs, download, stale URL refresh |
| [Groups](https://hexdocs.pm/baileys_ex/groups.html) | Create, manage participants, invite flows, communities |
| [Events](https://hexdocs.pm/baileys_ex/events-and-subscriptions.html) | Subscribe to connection, message, and presence events |
| [Authentication](https://hexdocs.pm/baileys_ex/authentication-and-persistence.html) | Custom credential storage, Signal key management |
| [Configuration](https://hexdocs.pm/baileys_ex/configuration.html) | All connection and runtime options |
| [Event Catalog](https://hexdocs.pm/baileys_ex/event-catalog.html) | Every event type with payload shapes |
| [Message Types](https://hexdocs.pm/baileys_ex/message-types.html) | Complete message payload reference |
## Example
A complete echo bot is included at [`examples/echo_bot.exs`](examples/echo_bot.exs):
```bash
mix run examples/echo_bot.exs -- --help
```
See the [Echo Bot guide](https://hexdocs.pm/baileys_ex/echo-bot.html) for a
walkthrough.
## Telemetry
BaileysEx emits [Telemetry](https://hexdocs.pm/telemetry) events under the
`[:baileys_ex]` prefix — connection lifecycle, message send/receive, media
upload/download, and NIF operations. Attach your handlers for dashboards,
alerting, or tracing.
## Status
BaileysEx is in **alpha**. The API surface is stabilizing but may change before
1.0. The library tracks Baileys `7.00rc9` as its upstream reference for wire
behaviour and feature scope.
## Acknowledgements
- [Baileys](https://github.com/WhiskeySockets/Baileys) — the TypeScript original
that defines the protocol behaviour BaileysEx implements
- [whatsmeow](https://github.com/tulir/whatsmeow) — Go implementation, referenced
for protocol details
- [whatsapp-rust](https://github.com/nicksul/whatsapp-rs) — Rust implementation,
referenced for documentation patterns
## License
MIT — see [LICENSE](LICENSE) for details.