• Home
  • Blog
  • What Is Baileys? The Complete Guide to the WhatsApp Library
Libraries
12 min read Jun 19, 2026

What Is Baileys? The Complete Guide to the WhatsApp Library

A deep, developer-focused guide to Baileys (@whiskeysockets/baileys): how the browserless WhatsApp library works, install, QR vs pairing code, sending messages, and ban risk.

Key takeaways
  • Baileys is an open-source, MIT-licensed TypeScript library that re-implements the WhatsApp Web (multi-device) API directly over a WebSocket — no browser, no Puppeteer, no Selenium.
  • It authenticates as a linked companion device using the Noise Protocol for transport and the Signal Protocol for end-to-end message encryption.
  • Install @whiskeysockets/baileys (or the unscoped baileys), require Node 20+, connect with makeWASocket, link via QR or pairing code, and send with sock.sendMessage(jid, { text }).
  • It is unofficial and not endorsed by Meta. Automating a personal/business number can trigger bans, and bulk or cold messaging violates WhatsApp's Terms of Service.
  • For compliant bulk messaging use the official WhatsApp Business Cloud API; for verifying numbers or fetching public profiles, use a hosted profile API instead of running a risky linked session.

What is Baileys?

Baileys is an open-source, TypeScript/JavaScript library that re-implements the WhatsApp Web (multi-device) protocol. Instead of automating a real browser, it opens a raw WebSocket connection straight to WhatsApp's servers and speaks the same binary protocol that the official WhatsApp Web client uses. There is no Selenium, no Chromium, no Puppeteer, and no phone emulator anywhere in the stack. That single design decision is why developers reach for it: a headless-browser approach can consume hundreds of megabytes of RAM per session, while a Baileys socket is a lightweight Node process you can run several of at a time on a modest VPS.

Functionally, Baileys lets your code do most of what a linked WhatsApp Web device can do: receive and send text, media, reactions, and presence updates; read group metadata; and check whether numbers are registered on WhatsApp. It is the foundation under a large share of the Node.js WhatsApp bots you find on GitHub. Crucially, it is an unofficial client — it is not the WhatsApp Business Cloud API and it is not affiliated with or endorsed by Meta. It works by impersonating a companion device, which is both its superpower and the root of its biggest risks.

Who makes it, and the package-name confusion

Baileys was originally created by Adhiraj Singh (GitHub user adiwajshing) and published under the npm namespace @adiwajshing/baileys. The project has since moved to the WhiskeySockets organization, where it is actively maintained by Rajeh Taher with contributions from a wider community of developers. The repository lives at github.com/WhiskeySockets/Baileys, has on the order of ~10k stars and ~3k forks (the exact figures drift over time), and is MIT licensed. There is an active Discord community, and the lead maintainer offers paid support.

The package naming trips up almost everyone. Two npm packages are kept in sync at the same version: the scoped @whiskeysockets/baileys and the unscoped baileys. The GitHub README imports from the scoped package; the official docs site (baileys.wiki) installs the unscoped one. Both resolve to the same source code, so pick whichever you like — this guide uses the scoped name as the canonical choice. The one package you should never install is the legacy @adiwajshing/baileys, which is deprecated and abandoned.

PackageStatusNotes
@whiskeysockets/baileysMaintainedCanonical scoped package; used in the README
baileysMaintainedUnscoped mirror, same version & source; used in official docs
@adiwajshing/baileysDeprecatedLegacy namespace — do not use

Versions and maintenance status (2026)

Version state matters here because Baileys has an irregular release cadence with occasionally long gaps, and version-sensitive details change quickly. The notes below were last verified in mid-2026; always confirm the live numbers on npm and the GitHub releases page before pinning a dependency. As of that check, the maintained stable line is 6.7.x — 6.7.23 (May 2026) is the current stable/legacy npm dist-tag — and the newer 7.x line is still published only as release candidates. The npm latest tag points at a 7.0.0 release candidate (7.0.0-rc13 at the time of writing), which the team described as the largest release since the WhiskeySockets fork began. Because the latest tag is a release candidate rather than a final 7.0.0, read the migration guide and test before adopting it in production.

The v7 line brings two changes worth planning for. First, it is published as an ES module (the package's type field is module), so a CommonJS project will likely need configuration changes — adopting ESM yourself, or using dynamic import() — to consume it cleanly; verify the exact packaging for the version you pick. Second, and more importantly, the redesign is fully event-driven: the socket is an EventEmitter and Baileys no longer keeps internal state of chats, contacts, or messages. The event stream is the single source of truth, which means you are responsible for persisting everything you care about. There is an official migration guide at baileys.wiki for the move to 7.0.0.

How it works under the hood

Baileys layers two well-known cryptographic protocols. The transport handshake uses the Noise Protocol (the XX pattern) to encrypt the initial WebSocket frames between your client and WhatsApp's servers. On top of that, end-to-end encryption of actual message content is handled by the Signal Protocol via the libsignal package — the same protocol family that secures WhatsApp itself. Newer versions add a Rust bridge for performance-optimized cryptographic primitives.

Authentication happens as a linked device under WhatsApp's multi-device protocol. In practice your Baileys process behaves like a second WhatsApp client paired to a real phone number, exactly as WhatsApp Web does in a browser. That is the mental model to keep: you are not calling a business API with an access token; you are operating a companion of someone's actual WhatsApp account.

There is one licensing wrinkle to be aware of. Baileys itself is MIT, but libsignal is GPLv3. The maintainers have publicly stated they are working to migrate away from the libsignal dependency to their own Rust-based equivalent as soon as possible. That migration has been rolling out across recent releases rather than landing in a single version, so if license compatibility matters for your distribution, check the dependency tree of the exact version you ship and track the changelog for the current status.

Install, connect, and link a device

Baileys requires Node.js 20 or newer (the package's engines field is set to >=20.0.0 on both the 6.7.x and 7.x lines). There is also community-reported support for Bun and Deno. Install it from npm:

BASH
npm install @whiskeysockets/baileys   # or: npm install baileys

The minimal connection flow creates a socket, surfaces a QR code for you to scan, and persists the resulting credentials so you do not have to re-link on every restart. Note that the old printQRInTerminal option is deprecated and removed in current Baileys — the supported pattern is to read the QR string off the connection.update event and render it yourself (here with the qrcode-terminal package). The useMultiFileAuthState helper handles credential storage for the demo, and the creds.update event tells you when to save:

TS
import makeWASocket, { useMultiFileAuthState, Browsers } from '@whiskeysockets/baileys'
import qrcode from 'qrcode-terminal'

const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
const sock = makeWASocket({
  auth: state,
  browser: Browsers.ubuntu('My App'),
})

sock.ev.on('creds.update', saveCreds)

sock.ev.on('connection.update', (update) => {
  const { connection, qr } = update
  if (qr) qrcode.generate(qr, { small: true }) // render the QR to scan
  if (connection === 'open') console.log('connected')
})

Scan the printed QR from WhatsApp on your phone under Settings, Linked Devices. Once linked, the saved credentials in the auth_info_baileys folder let the socket reconnect silently. From here you subscribe to events on sock.ev for incoming messages, connection updates, and the rest of the protocol stream.

Pairing code and sending messages

If scanning a QR is impractical — for example on a headless server — Baileys supports pairing codes. Build the socket on a real auth state (the same useMultiFileAuthState from the previous example), then request an alphanumeric code for a specific phone number in E.164 format without the leading plus, and type it into WhatsApp under Linked Devices, Link with phone number:

TS
import makeWASocket, { useMultiFileAuthState } from '@whiskeysockets/baileys'

const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
const sock = makeWASocket({ auth: state })
sock.ev.on('creds.update', saveCreds)

if (!sock.authState.creds.registered) {
  const number = 'XXXXXXXXXXX' // E.164, no '+'
  const code = await sock.requestPairingCode(number)
  console.log(code) // enter this in WhatsApp > Linked Devices
}

Without that auth state the creds.registered check has nothing meaningful to read, so always pair on top of a real, persisted auth store. Once a session is established, sending a message is a single call. Messages are addressed to a JID (WhatsApp's internal identifier, typically the number plus an @s.whatsapp.net suffix for individuals):

TS
await sock.sendMessage(jid, { text: 'hello world' })

The same sendMessage call handles images, documents, locations, reactions, and replies by passing different content objects. Because the socket is event-driven, your bot logic usually lives inside a messages.upsert listener, where you inspect incoming messages and respond.

Auth state and common pitfalls

The biggest production mistake is shipping useMultiFileAuthState as-is. The official docs are blunt about it: DO NOT rely on it in production — it is very inefficient and is purely for demo purposes. It writes many small files to disk and does not scale across processes or restarts gracefully. For anything real, implement your own auth-state store backed by a database or Redis, persisting credentials and the signal key store yourself.

  • Treating Baileys like a stateless API. In v7 it keeps no internal chat/contact/message state — you must persist the event stream or you lose history on restart.
  • Not handling connection.update reconnects. WhatsApp drops sockets; you need logic to reconnect and to detect a logged-out (401) state versus a transient disconnect.
  • Forgetting to save creds on every creds.update. Skip this and your session silently dies after key rotation.
  • Using the removed printQRInTerminal option. Current Baileys no longer renders the QR for you — read update.qr from connection.update and render it with a package like qrcode or qrcode-terminal.
  • Hardcoding JIDs incorrectly. Individuals use @s.whatsapp.net; groups use @g.us — mixing them up causes silent failures.
  • Running multiple sockets on the same auth folder. The signal session keys will desync and you will see decryption errors.

Ban risk, ethics, and the legal line

Be honest with yourself before deploying: because Baileys automates a real account as a linked device, using it for automation can violate WhatsApp's Terms of Service, and the ban risk is real and unpredictable. Reported ban windows range from within days to months without issues, with no reliable pattern. WhatsApp's anti-abuse systems reportedly weigh signals like a low reply ratio, messaging strangers far from you in the contact graph, robotic timing, and traffic from datacenter or VPS IP ranges. There are open GitHub issues describing near-instant bans after a QR scan (for example issues #225 and #1869). So-called anti-ban wrappers and random delays reduce some signals but guarantee nothing.

The maintainers state they do not condone use that violates WhatsApp's Terms of Service, and explicitly discourage stalkerware, bulk, or automated messaging.

The honest framing is this: Baileys is a great fit for personal automation, hobby bots, prototyping, and integrations on a number you own and control. It is the wrong tool for bulk marketing, cold outreach, or any messaging-strangers-at-scale use case — that belongs on Meta's official WhatsApp Business Cloud API, which is the ToS-compliant, ban-resistant path for businesses. Choosing the official API is not just safer legally; it is operationally more reliable because it will not break when the unofficial protocol shifts.

There is also a category Baileys solves badly: you do not need a risky linked session just to verify whether a number is on WhatsApp or to read a public profile picture and display name. A hosted profile API does that with a simple HTTP request, no session, no QR, and no account to get banned.

When Baileys is not the right tool

A lot of projects reach for Baileys when their actual requirement is much narrower. If all you need is to confirm a number exists on WhatsApp, enrich a lead with a public profile picture and display name, or flag whether an account is a WhatsApp Business profile, you can do that with a stateless REST endpoint instead of operating and babysitting a linked session.

You need to...Best fit
Build a personal bot on your own numberBaileys (own-number, ToS-aware)
Send bulk/marketing messages compliantlyWhatsApp Business Cloud API (official)
Just verify a number is on WhatsAppHosted profile/validation API
Fetch public profile pic, name, business flagHosted profile API (no session)
Enrich CRM leads at scaleHosted bulk-check API

The WhatsApp Profile API covers that last set of needs directly: it returns whether a number is registered, the public profile picture, display name, about text, and the business-account flag from a single request — no QR, no auth state, no ban exposure. For lead enrichment or anti-fraud checks across many numbers, the bulk checker handles lists without you managing a single socket.

Frequently asked questions

Verify numbers without running a Baileys session

Skip the QR codes, auth state, and ban risk. The WhatsApp Profile API tells you if a number is registered and returns the public profile picture, name, about, and business flag from one HTTP call.

Explore the API
Sponsored

Need cheap numbers to create, verify or warm up WhatsApp accounts for testing? GrizzlySMS rents virtual numbers for WhatsApp verification from under $1.

Get a WhatsApp number

Sources & further reading

Related

More from the blog

Written by
Eduardo Airaudo

Developer and founder of the WhatsApp Profile API. Building WhatsApp tooling and APIs since 2022.

What Our Users Say

Real reviews from our satisfied customers

4.5/5 (170 reviews)