open-wa logoopen-wa
DocsGuides

Rate Limits and Ban Risk

Control queue pressure, handle provider rejection, and understand what this project can and cannot promise about WhatsApp restrictions.

Rate Limits and Ban Risk

open-wa does not expose a WhatsApp rate-limit guarantee. WhatsApp does not publish a stable per-chat or per-group rate table, and provider restrictions can change without notice, so a local queue is a pacing control rather than a ban avoidance mechanism.

What is known and what is not

The client and schema define how open-wa validates and dispatches a send. They do not define WhatsApp's server-side quota, rolling window, account-age rule, or restriction duration. Treat community measurements as dated observations that need their own evidence; this guide does not turn them into defaults.

Provider rejection can happen even when a local queue is obeying its schedule. Handle the rejected operation, stop or slow the relevant workflow, and record the provider error before deciding whether a retry is appropriate. Do not retry in a short loop, and do not assume that a random delay makes a pattern safe.

Queue concurrency and rate are different

concurrency limits how many queue tasks run at the same time. It does not set the time between tasks. In p-queue, intervalCap and interval implement an interval window; omitting intervalCap leaves the cap at its default of Infinity. The following example uses strict rolling-window mode to allow no more than one queued send in any 15-second span, runs one task at a time, and records rejected jobs:

import PQueue from 'p-queue';
import { Client, createClient } from '@open-wa/wa-automate';
import { PuppeteerDriver } from '@open-wa/driver-puppeteer';

const runtime = await createClient({
  sessionId: 'paced-sender',
  driver: new PuppeteerDriver(),
});
const client = new Client({
  client: runtime,
  transport: runtime.getTransport(),
});

const sendQueue = new PQueue({
  concurrency: 1,
  intervalCap: 1,
  interval: 15_000,
  strict: true,
});

async function enqueueSend(chatId: string, text: string) {
  try {
    const result = await sendQueue.add(() => client.sendText(chatId, text));
    if (result === false) {
      console.error('WhatsApp did not accept the send request', { chatId });
      return false;
    }
    return result;
  } catch (error) {
    console.error('WhatsApp rejected a queued send', { chatId, error });
    throw error;
  }
}

await client.start();
await enqueueSend('447700900000@c.us', 'Hello');

Install the example dependencies with npm install @open-wa/wa-automate@5.1.0 @open-wa/driver-puppeteer@5.1.0 p-queue. Complete the normal client authentication when it starts. This is a process-local schedule: it does not coordinate other sessions or senders and does not establish a provider quota. Choose the interval for your workflow, consent model, and operational budget, then stop or reclassify work when WhatsApp reports a restriction.

Safer workflow boundaries

  • Accept messages or jobs only from a bounded source so a traffic spike cannot create an unbounded backlog.
  • Keep consent and opt-out state beside the job, and remove opted-out recipients before enqueueing a send.
  • Keep one clear owner for retries. A queue retry and an application retry can multiply traffic if both act on the same rejection.
  • Record the chat ID, operation, result, and provider error without logging message contents or credentials by default.
  • Stop or pause the queue after repeated rejections and require an operator to decide whether the workflow should resume.

Handling a restriction

There is no documented universal wait time for a WhatsApp restriction. Stop the automation, retain the provider warning or error, and review consent, queue depth, duplicate sends, retry behavior, and account context. Resume only after you have a bounded plan and a reason to believe the provider state allows it; timing alone cannot establish that the account is clear.

Was this helpful?

Your answer includes the page path and docs version.

On this page