Multi-tenant SaaS · Messaging

WhatsApp Broadcast Platform

Businesses link their own WhatsApp number by QR and send personalised broadcasts from a spreadsheet, paced to stay safe, with a full admin console for the operator.

Role
Full-stack engineering
Platforms
Client web app · Admin console · Worker
Stack
Node.js · Express · SQLite · WhatsApp gateway (REST) · ExcelJS · libphonenumber
  • Queue design
  • Circuit breakers
  • Rate limiting
  • Anti-ban pacing
  • Excel import
  • Crash recovery
  • Audit trail
Delivery and safety log with a paused broadcast, and the personalised message a customer receives

Product screens with sample data. Names and figures inside the screens are illustrative.

01

The problem

Small businesses want to message their customers on WhatsApp without getting their number banned or sending the same message twice.

~45
HTTP routes
5,000
Recipients per sheet
5
Failures before auto-pause
02

What I built

01

The shop's own number, linked in a minute

Clients scan a QR code with their WhatsApp, and the session moves from starting to ready on its own. Every row in the sheet is checked on WhatsApp before sending, so invalid numbers never count as failures.

QR linking screen with session states and number checks
02

Write once, personalise for everyone

Upload an .xlsx or .csv of up to 5,000 rows; any column becomes a {{variable}}. Numbers are normalised and de-duplicated. Media up to 16 MB is supported, and captions over 1,024 characters are split cleanly.

Broadcast composer
03

It reads like a message from the shop

Customers get a personal message with their name, store and code, from the number they already know, with the catalogue attached.

04

Paced like a person, not a script

Batches of 10–100, gaps of 5–120 s with up to 50% random jitter, breaks between batches and a daily cap per client. Progress, failures and the next batch are visible live.

Running broadcast with batch progress
05

An operator console

Clients, limits, suspensions, gateway health and a 'needs your attention' list, with every action recorded in an audit trail.

Admin overview

03 Advanced engineering

A sending queue built to protect the number

The risky part of broadcasting isn't the sending; it's what happens when things go wrong. The queue is designed so that throttling, gateway errors and server restarts never ban a number or message someone twice.

  1. 01Upload checked by file signature
  2. 02Normalise and de-duplicate numbers
  3. 03Check each number on WhatsApp
  4. 04Queue in SQLite
  5. 05Batch, jittered gap, break
  6. 06Send through the gateway
  7. 07429: wait retryAfter
  8. 085 failures in a row: auto-pause
Delivery and safety log showing auto-pause, rate-limit backoff and crash recovery

Delivery and safety log with sample data.

Circuit breaker

Five consecutive failures pause the broadcast and keep the queue intact. The client sees a plain note: check the WhatsApp number, then resume.

Respecting throttling

A 429 from the gateway is honoured with its retryAfter delay before the batch continues, instead of hammering the number.

Crash-safe by design

After a restart, anything stuck mid-send is marked 'delivery unknown' rather than retried, so no customer gets a duplicate.

Daily caps that hold

Each client has a hard daily limit set by the operator; the broadcast stops for the day and resumes on its own the next morning.

Uploads checked by content

Files are validated by their bytes, not their extension, behind CSP and strict session cookies.

Locked-down admin

Five wrong passwords lock sign-in for 15 minutes, and every admin action lands in the audit trail.

Server
Node.js · Express · ~45 routes
Data
SQLite · 7 tables
Sheets
ExcelJS · 5,000 rows · 5 MB
Numbers
libphonenumber · WhatsApp check
Pacing
Batch 10–100 · gap 5–120 s · jitter ≤ 50%
Limits
Daily cap per client · break 1–120 min
Media
Up to 16 MB · captions split at 1,024
Security
CSP · signature checks · lockout · audit
04

Key decisions

  1. Unknown beats duplicate

    When the system can't be sure a message went out, it says so instead of guessing and sending it again.

  2. Validate before you queue

    Numbers are checked on WhatsApp first, so failure rates reflect real problems and the circuit breaker trips only when it should.

  3. Plain-language states

    Clients see 'Paused for safety' and 'Daily limit reached, resumes tomorrow', not error codes.