Alternativesvs whatsapp-web.js

A whatsapp-web.js alternative without a browser for every number

whatsapp-web.js drives WhatsApp Web in a real browser. What running it for customers takes, where it is the right tool, and what wuapi runs in its place.

wuapiAlternativeschecked 27 September 20266 min read
whatsapp-web.js as the browser session alone, with the layers a customer number needs drawn as empty boxes left to build, next to wuapi's stack with every layer run for you: API, signed webhooks, queue, pacing, reconnects, encrypted sessions and a sticky residential exit.[WHATSAPP-WEB.JS]rest api, sdk, mcpsigned webhooks, retriesqueue, idempotencypacing, recipient checkreconnects, healthencrypted sessionssticky residential exitnpm i whatsapp-web.jsTHE SOCKET; THE REST IS YOURS[WUAPI]rest api, sdk, mcpsigned webhooks, retriesqueue, idempotencypacing, recipient checkreconnects, healthencrypted sessionssticky residential exitprotocolRUN FOR YOU[ALTERNATIVES]

whatsapp-web.js is a Node.js library that opens WhatsApp Web in a browser controlled by Puppeteer and calls its internal functions from your code. It is one of the most popular ways to build a WhatsApp bot, with a friendly guide and a large community. It is also the approach with the most moving parts per number, because every number is a browser. This page covers what that means once customers depend on it, and what wuapi runs instead.

Pros and cons
wuapi
Advantages
  • Advantage: No browser per number: a session is a connection, run for you.
  • Advantage: A WhatsApp Web redesign is not your deploy.
  • Advantage: Encrypted sessions that move between workers without a new QR code.
  • Advantage: Signed webhooks, idempotent sends and a REST API.
Disadvantages
  • Disadvantage: It costs money per number, where the library is free.
  • Disadvantage: You get what the API exposes, not everything the web app can do.
  • Disadvantage: Hosted: no fit for software your users run themselves.
whatsapp-web.js
Advantages
  • Advantage: Free and Apache 2.0 licensed.
  • Advantage: Drives the real WhatsApp Web app, so it reaches what the web client does.
  • Advantage: An excellent guide, API docs and a large community.
  • Advantage: Groups, channels, polls and reactions are supported.
Disadvantages
  • Disadvantage: Every number is a Chromium process, with the memory that takes.
  • Disadvantage: WhatsApp Web changes can stop it until a new release.
  • Disadvantage: Local sessions need a persistent disk.

#What whatsapp-web.js is

The project moved to the wwebjs organization on GitHub and is licensed Apache 2.0. On npm it is whatsapp-web.js, at version 1.34.7 when we checked, and it needs Node.js 18 or newer with Puppeteer. It has a guide at wwebjs.dev, API docs and a Discord.

The model is a client object that emits events:

  • `qr` with a code to scan, or requestPairingCode for a code typed on the phone.
  • `ready` when the browser has loaded WhatsApp Web and the session is live.
  • `message` for each incoming message, and `disconnected` when the session ends.

Sessions are kept by an auth strategy. NoAuth, the default, keeps nothing. LocalAuth saves the browser profile to disk and, as the guide notes, does not work on hosts with ephemeral file systems. RemoteAuth backs the session up to a store such as MongoDB or S3, and takes about a minute after the scan to save it.

The feature list covers text, media, replies, reactions, polls, groups with participant management, channels, contacts and locations. Sending video needs Google Chrome rather than bundled Chromium. Buttons and lists are marked deprecated.

The README's disclaimer is plain: the project is not affiliated with WhatsApp, it cannot promise you will not be blocked for using it, and WhatsApp does not allow bots or unofficial clients, so it should not be considered totally safe.

#Who should keep using it

  • One or two bots you run for yourself. A browser per number is fine when there are two of them.
  • You need something only the web client does. Because it drives the real web app, it can reach behaviour a protocol library has not implemented yet.
  • You are learning. The guide is one of the best introductions to how WhatsApp automation works. Reading it first makes every other option, wuapi included, easier to evaluate.

Past a few numbers, or once the numbers belong to customers, the costs below start to dominate.

#A browser per number

This is the part that is specific to whatsapp-web.js.

Memory and CPU. Each session is a Chromium process running the full WhatsApp Web app. Ten numbers is ten browsers. That shapes the server you rent and how many numbers fit on it, and a browser that leaks memory over days has to be restarted, which is a reconnect.

Upgrades track the web app. The library calls WhatsApp Web's internal functions. When WhatsApp ships a new web client, those internals can change, and the library needs a release before your bot works again. You watch for it, test it and deploy it.

Headless servers. The guide notes the sandbox flags a browser needs on a server without a display, or when it runs as root. Video needs a real Chrome install.

Sessions on disk or in a store. LocalAuth needs a persistent disk. RemoteAuth needs a database or bucket, and a new session is not saved until about a minute after the scan.

Proxies through the browser. A proxy is a Chromium flag, with proxyAuthentication for credentials. There is no per-request control, and media travels through the same browser.

Scaling past one machine. When the numbers outgrow a server, you need a second one and a rule for which browser runs where. A session must never be open in two places at once, because WhatsApp treats that as a takeover and logs the device out, so moving a number between machines means stopping it cleanly on one, waiting for RemoteAuth to have saved it, and starting it on the other. Deploys become a careful dance of restarting browsers one at a time, with each restart a reconnect the customer might notice.

#Everything else a customer number needs

The rest is the same on any self-hosted stack. The library gets a session talking. Keeping it connected, well behaved and observable is a service you build. Below, each piece with what wuapi runs for it and the values from our code.

A residential exit per number. Every account is created with a proxyLocation from 134 countries. The engine tests three candidate exits before a number first logs in through a new one, keeps the fastest, and holds it across reconnects. If the proxy is down the number stays offline; it never falls back to a datacenter address. Why WhatsApp bans numbers explains why that matters. 0.5 GB of traffic a month per paid number is included, then $0.99 per GB.

Exit changes on a budget. A number rotates only after 3 failed connects, at most 4 times a day and 6 hours apart, never more than 8. A proxy gateway outage moves new connections to another region and back, without spending any number's budget.

No browser at all. The engine speaks the protocol directly over a WebSocket, so a session is a connection, not a Chromium process, and a WhatsApp Web redesign is not your deploy.

Dead sockets found fast. An adaptive liveness ping with a 6 to 20 second deadline, and a 20 second deadline on each send's acknowledgement, past which the connection is recycled and a pre-dialed one takes over.

Reconnects that know when to stop. Immediate first retry, then jittered backoff capped at 20 seconds, never giving up on a temporary drop, and no reconnect after logged_out, connection_replaced or temporary_ban.

Sends that survive a drop. One message at a time per number. A send made during a drop waits and is retried with the same WhatsApp message id, so it cannot arrive twice, and your own retries are safe with an Idempotency-Key kept for 24 hours.

A recipient check. Before a first message to a contact, the engine confirms the number is on WhatsApp and fails the send with not_on_whatsapp if not.

Pacing when you want it. A per-minute cap, a first-contact cap and a typing indicator sized to the message, per number and off by default. We recommend 12 a minute and 5 to new contacts for outbound; the guide covers when.

Encrypted, movable sessions. Session keys are encrypted with AES-256-GCM, can be restored on another worker without a new QR code, and are protected so two workers never hold the same session.

Webhooks and alerts. Deliveries signed with HMAC-SHA256 over the timestamp and raw body, retried at 30s, 2m, 10m, 1h and 6h, with 30 days of logs. A 20 second grace before account.disconnected, and email or Slack when a number stays offline longer than you allow.

#The work, side by side

piecewhatsapp-web.js on your serverswuapi
a session isa Chromium processa WebSocket connection, run for you
WhatsApp Web updateswait for a library release, redeploynot your concern
session storagedisk, or a store via RemoteAuthencrypted, restorable on another worker
residential exita browser flag and your providerincluded, sticky, fails closed
exit rotationyours3 failures, 4 a day, 6 hours apart
dead session detectionyoursliveness ping, 20 second send deadline
reconnectsyoursjittered backoff, stops on logout or ban
sends through a dropyour queuewait, retry with the same message id
recipient checkyoursalways on, cached
pacing and typingyoursper number, opt-in
HTTP API and webhooksyours to buildREST, signed webhooks, SDK, MCP
pricefree library; servers sized for browsers, proxies, time$6 first number, $4.50 each to 50

#Moving a whatsapp-web.js bot

// whatsapp-web.js
const { Client, LocalAuth } = require("whatsapp-web.js")
const client = new Client({ authStrategy: new LocalAuth() })
client.on("qr", (qr) => console.log("scan", qr))
client.on("message", async (msg) => {
  if (msg.body === "ping") await msg.reply("pong")
})
client.initialize()

// wuapi: a webhook handler
if (event.type === "message.received" && event.data.object.text === "ping") {
  await wuapi.messages.send({ accountId: event.data.object.accountId, to: event.data.object.from, text: "pong" })
}
whatsapp-web.jswuapi
Client with an auth strategyaccount, stored for you
qr eventGET /v1/accounts/{accountId}, read qrCodeUrl
requestPairingCodePOST /v1/accounts/{accountId}/pairing-code
ready eventaccount.connected
message eventmessage.received
disconnected eventaccount.disconnected
client.sendMessage(chatId, text)POST /v1/messages with to, text
5511999999999@c.us+5511999999999

Each number links again with a new QR code or a pairing code. Verify each webhook as the docs show. Try one number on the Free plan: 2,000 messages a month and 0.5 GB of proxy traffic, no card.

#Questions people ask

Is whatsapp-web.js free?

Yes, it is Apache 2.0 licensed. Running it costs a server with enough memory for a browser per number, residential proxies, storage for sessions, and the time to keep up with WhatsApp Web changes and reconnects.

Can whatsapp-web.js get my number banned?

Its own README says there is no promise you will not be blocked, because WhatsApp does not allow bots or unofficial clients. The same is true of every linked-device approach, wuapi included. What you send and how people react decides most of it.

Why does whatsapp-web.js use so much memory?

Each session runs WhatsApp Web inside a Chromium browser controlled by Puppeteer, so every number carries a full browser. A client that speaks the protocol over a WebSocket, as wuapi's engine does, has no browser to run.

Does wuapi support groups like whatsapp-web.js?

Yes. A linked number can create groups, add, remove, promote and demote participants, manage invite links and join requests, and post, all through the REST API.

How do I move from whatsapp-web.js to wuapi?

Create an account with a proxy location, link the number with a QR code or pairing code, point a webhook endpoint at your server, and replace client calls with REST calls. Session files cannot be imported, so each number links again.

wuapi is an independent service. It is not affiliated with, endorsed or sponsored by WhatsApp. WhatsApp is a trademark of its respective owner.

03/What to read next

Try it

Link a number and send your first message.

One REST call, a typed SDK, and webhooks signed with HMAC-SHA256 over the raw body. No per-message fees.

The whole API is in the docs, and the docs are in one file if you are handing the work to a coding agent.

All alternatives · openapi.json