Self-hosted WhatsApp Web automation dashboard: link one phone via QR, then manage chats and workflows (inbound handling, scheduled outbound, receipt acknowledgements) from a small web UI backed by PostgreSQL.
This build is intentionally single-tenant: no sign-up or login — whoever can reach the server controls that one linked WhatsApp session and the default workspace in the database.
Open source · MIT · feedback and contributions welcome
Try it — follow Quick start and open an issue if you hit setup problems.
Feature requests — describe your use case in a GitHub issue; real-world workflows help prioritize what ships next.
Contributing — PRs welcome for bugs, docs, and improvements. For larger changes, open an issue first so we can align on direction.
- Pair one WhatsApp account per running server process (
whatsapp-web.js/ Puppeteer). - Dashboard with live connection status and chat totals.
- Conversations / chats UI when linked.
- Workflow builder: inbound triggers, scheduled sends, optional acknowledgement messages, media uploads.
- Postgres persistence via Prisma.
- Node.js 20+ (recommended; matches typical
whatsapp-web.jssetups). - PostgreSQL 14+ (or use Docker Compose below).
- A machine with enough RAM for one headless Chromium instance (often ~512 MB–1 GB+ in addition to Node).
git clone <your-fork-or-repo-url> kahwa
cd kahwa
npm installCopy the example env file and edit DATABASE_URL if needed:
cp .env.example .envWith Postgres running:
npm run prisma:generate
npm run prisma:pushnpm run devOpen http://localhost:8080 (or the host/port in your .env). Use Pair WhatsApp on the dashboard and scan the QR code from WhatsApp → Linked devices.
npm run dev:localThis starts Postgres (docker compose up -d db), applies the schema, and runs the API + static UI with tsx watch.
npm run build
npm startSet NODE_ENV=production and ensure DATABASE_URL points at your production database. Do not expose this service to the public internet without reverse-proxy TLS, network restrictions, and an understanding that there is no application-level authentication in this edition.
docker compose up --buildThen open http://localhost:8080 (see docker-compose.yml for published ports).
| Variable | Purpose |
|---|---|
PORT |
HTTP port (default 8080). |
NODE_ENV |
development | production | test. |
DATABASE_URL |
PostgreSQL connection string. |
WHATSAPP_AUTO_RESTORE |
Set false to skip restoring saved WA session on boot. |
Inbound reply delay for the simulated /api/whatsapp/inbound queue is stored in Postgres (WorkspaceSetting.inboundReplyDelayMs, default 5000) and editable from the dashboard — not via environment variables.
| Path | Role |
|---|---|
src/server.ts |
Express API, static hosting, WhatsApp routes. |
src/services/whatsappLinkService.ts |
WhatsApp client lifecycle, sends, mutex-bound workspace operations. |
src/services/workflow*.ts |
Workflow scheduling and inbound automation. |
web/public/ |
Dashboard UI (vanilla JS modules). |
prisma/schema.prisma |
Database models. |
- Treat this as root access to your WhatsApp account for anyone who can use the web UI and API.
Schema changes use prisma db push in this repo (no checked-in migration SQL). After pulling, run npm run prisma:generate and npm run prisma:push. Removing the old User table requires a push against your database; backup first if you had portal accounts stored there.
| Script | Description |
|---|---|
npm run dev |
Dev server with reload. |
npm run dev:local |
Docker Postgres + dev server. |
npm run build |
Compile TypeScript to dist/. |
npm start |
Run compiled server. |
npm run prisma:generate |
Generate Prisma client. |
npm run prisma:push |
Push schema to DB (no migration files). |
MIT — see LICENSE.
WhatsApp automation may violate WhatsApp Terms of Service or Meta policies depending on how you use it. This software is provided as-is for self-hosted experimentation; you are responsible for compliant use.