Skip to content

jeffhuen/baileys_ex

Repository files navigation

BaileysEx

Hex.pm Hex Docs License

WhatsApp Web API client for Elixir — a behaviour-accurate port of 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:

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. Advanced custom store modules must implement Signal.Store.transaction/3 with the explicit transaction-scoped handle passed into the callback; built-in users do not need to care about this.

Connect and pair

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

{:ok, _sent} =
  BaileysEx.send_message(connection, "15551234567@s.whatsapp.net", %{
    text: "Hello from BaileysEx!"
  })

Listen for incoming messages

BaileysEx.subscribe(connection, fn
  {:message, msg} -> IO.inspect(msg, label: "incoming")
  {:connection, update} -> IO.inspect(update, label: "connection")
  _other -> :ok
end)

Send media

{: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.

Section What you'll learn
Installation Prerequisites, dependency setup, compilation
First Connection QR pairing, phone pairing, credential persistence
Send Messages Text, replies, reactions, polls, forwards, edits
Media Upload images/video/docs, download, stale URL refresh
Groups Create, manage participants, invite flows, communities
Events Subscribe to connection, message, and presence events
Authentication Custom credential storage, Signal key management
Configuration All connection and runtime options
Event Catalog Every event type with payload shapes
Message Types Complete message payload reference

Example

A complete echo bot is included at examples/echo_bot.exs:

mix run examples/echo_bot.exs -- --help

See the Echo Bot guide for a walkthrough.

Telemetry

BaileysEx emits 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 — the TypeScript original that defines the protocol behaviour BaileysEx implements
  • whatsmeow — Go implementation, referenced for protocol details
  • whatsapp-rust — Rust implementation, referenced for documentation patterns

License

MIT — see LICENSE for details.

About

WhatsApp Web API client for Elixir — behaviour-accurate port of Baileys with Signal Protocol encryption, multi-device support, and native BEAM fault tolerance

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors