Send without getting banned
OpenWA is unofficial. It drives WhatsApp through reverse-engineered clients — the whatsapp-web.js and baileys engines — not Meta's official Cloud API, so every number you connect carries a non-zero risk of restriction or ban. Connect a dedicated number you can afford to lose, never your primary personal or business number — and if you run OpenWA for paying clients, pass the same guidance on to them.
WhatsApp's anti-abuse systems actively look for unofficial automation. The practices below materially reduce the chance of the account being flagged; they cannot eliminate it.
Pick an engine: ban risk vs resource cost
The two engines sit at opposite ends of the safety–density trade-off:
| Engine | Ban-risk profile | Resource cost |
|---|---|---|
whatsapp-web.js | Lower — drives a real headless Chromium that looks like genuine WhatsApp Web traffic. | High RAM (~300–500 MB per session). |
baileys | Higher — speaks the multi-device WebSocket protocol directly and is easier for WhatsApp to fingerprint. | Low RAM (~30–80 MB per session). |
If account safety is your top priority and you can afford the memory, set ENGINE_TYPE=whatsapp-web.js. If you need session density and accept the trade-off, use baileys. See Configuration.
Follow the safe-sending guardrails
- Warm up fresh numbers. For the first several days, behave like a normal human user: scan the QR, exchange a handful of messages with saved contacts, join a group or two, set a profile photo. Do not blast on day one.
- Never cold-blast strangers. Sending the first-ever message to a large batch of numbers that have never messaged you is the single most reliable way to get restricted — on either engine.
- Rate-limit your sends. OpenWA ships a configurable rate limiter, controlled by the
RATE_LIMIT_*environment variables — see Configuration. A few messages per minute per session is sustainable; thousands in an hour is not. - Message only opted-in recipients. The safest workloads are replies and alerts to people who already expect to hear from you: OTPs for your own users, order updates, support replies.
- Keep a fallback channel. For anything auth-critical or revenue-critical, keep an SMS, email, or official Cloud API path. Do not bet a login flow solely on an unofficial client.
- Mind the hosting IP. Datacenter IPs are flagged more aggressively than residential ones. A residential proxy per session — set
proxyUrlandproxyTypewhen you create the session, see Sessions — can help; it is not a license to spam.
Enforce opt-in send pacing
The guardrails above are manual. Send pacing makes the risky ones mechanical: it refuses a send that exceeds a budget before it reaches WhatsApp, so a misconfigured job or a runaway script cannot blast a number into a restriction on its own. It is off by default — nothing is refused unless you opt in with SEND_PACING_ENABLED=true.
Pacing has four knobs, all per session and per UTC day:
| Variable | What it bounds | Default |
|---|---|---|
SEND_PACING_WARMUP_SCHEDULE | Per-day send allowance by session age. A comma-separated list where the first entry is the session's first day and the last applies to every day after. Starts small because a brand-new account that immediately sends at volume is the pattern that gets numbers banned. | 20,40,80,160,320,640,1000 |
SEND_PACING_COLD_DAILY_CAP | Cold-reachout allowance — the first message to a chat this account has no history with in either direction. Same by-age shape as the schedule; a single number is a flat cap; empty disables the rule. | 5,10,20,40,60,80,100 |
SEND_PACING_BREAKER_THRESHOLD | Consecutive send failures that trip the breaker. Only failures that reached WhatsApp count — a client-fault 400, a disconnected socket, or a capability the engine lacks does not accumulate toward it, so one bad caller can no longer 429 every send on a healthy session. | 5 |
SEND_PACING_BREAKER_COOLDOWN_MS | How long the breaker pauses sends once tripped. | 900000 (15 min) |
The cold-reachout budget also bounds group participant adds, since adding strangers to a group is the same risk signal as messaging them. Counts come from the messages table, so they survive a restart. A malformed SEND_PACING_WARMUP_SCHEDULE entry falls the whole schedule back to the default rather than sending more than you asked for.
Replying to someone who wrote to you first today is not a risk at all, so it is never counted against the cold budget — only opens count. The same applies to a forwarded send routed to the owning node in a multi-node setup: it passes through the cold-reachout gate like any local send.
When pacing refuses a send, the response is HTTP 429 with code: "SEND_PACING_LIMITED" and a retryAfterSeconds field — that code is what tells it apart from the global rate limiter's own 429. Inside a bulk batch the refused item is recorded as SEND_PACING_LIMITED rather than a generic SEND_FAILED, so a pacing cap does not pollute your delivery-failure metrics. Every enforcement decision is written to the audit log.
Pacing stops a script from exceeding a budget. It does not make cold-blasting safe — a schedule that lets you send 1000 on day seven is still dangerous if those 1000 are strangers. Keep warming up the number, keep recipients opted in, and treat pacing as the backstop that catches a mistake.
Know what is WhatsApp policy, not an OpenWA bug
Two behaviors look like OpenWA defects but are server-side WhatsApp policy:
- A first message to a brand-new contact sometimes never arrives. The API returns success because the message leaves OpenWA, but WhatsApp's server-side reach-out and trust policy drops it at delivery. OpenWA tracks this in core issue #830.
- A banned account cannot be unbanned by OpenWA. If WhatsApp disables a number, appeal through WhatsApp's channels — OpenWA has no lever to pull.
Use the official API for regulated workloads
For any deployment where legal or regulatory compliance matters — healthcare, finance, large-scale commercial messaging, anything touching end users in the EU/EEA under DMA/GDPR — treat OpenWA as not approved and use Meta's official WhatsApp Business Cloud API. OpenWA fits personal projects, internal tooling, and automation; it is not a drop-in replacement for the official API in regulated environments.
Next steps
- Sending messages — every send route, including paced bulk broadcasts.
- Sessions — per-session proxy settings and the full lifecycle.
- Configuration —
ENGINE_TYPE, theRATE_LIMIT_*variables, and theSEND_PACING_*knobs described above.