BaileysEx

Hex.pmHex DocsLicense

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

Messaging

Media

Groups and Communities

Presence and Status

Newsletters

App State Sync

Analytics

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

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

License

MIT — see LICENSE for details.