kstmostofa/laravel-whatsapp
Dual-backend WhatsApp for Laravel: a pure-PHP Meta Cloud API client plus a whatsapp-web.js sidecar for personal-number access, unified under one WhatsApp:: facade, with a Livewire admin UI, Eloquent models, webhooks, and health checks.
Dual-backend WhatsApp integration for Laravel — Meta Cloud API (pure PHP) +
whatsapp-web.jssidecar (full personal-account access), with a polished Livewire admin UI and a singleWhatsApp::facade across both.
📖 Full documentation: kstmostofa.github.io/laravel-whatsapp
| Layer | What it does |
|---|---|
| Cloud API client | Pure PHP. Templates, media, business profile, phone-number management, webhooks with HMAC verification. |
| Web sidecar (~300 LOC Node) | whatsapp-web.js wrapped in a thin HTTP service. Personal-number QR pairing, groups, status, free-form messages anytime, contact lookup. |
| Unified facade | WhatsApp::messages()->sendTemplate(...) for Cloud, WhatsApp::web('main')->messages()->sendText(...) for sidecar. WhatsApp::send($to, $body) auto-picks. |
| Livewire + Flux UI | Drop-in admin at /whatsapp — Dashboard, Sessions+QR, Compose, Conversations (chat-bubble UI with media, edit/delete, search, sound, ack ticks), Groups, Contacts, Webhooks log, Status. Works with Tailwind, Bootstrap, or no CSS framework at all. |
| Eloquent models | Opt-in WaSession / WaMessage / WaContact with separate-DB support via WHATSAPP_DB_CONNECTION. |
| Background bridge | whatsapp:web:listen daemon turns sidecar SSE events into Laravel events. |
| Health monitoring | WhatsApp::status page + php artisan whatsapp:health [--json] for CI/monitoring. |
composer require kstmostofa/laravel-whatsapp
php artisan vendor:publish --tag=laravel-whatsapp-config
php artisan vendor:publish --tag=laravel-whatsapp-migrations
php artisan migrate
For the Cloud API — set in .env:
WHATSAPP_ACCESS_TOKEN=EAAG...permanent-token
WHATSAPP_PHONE_NUMBER_ID=123456789012345
WHATSAPP_BUSINESS_ACCOUNT_ID=987654321098765
WHATSAPP_APP_SECRET=your-meta-app-secret
WHATSAPP_VERIFY_TOKEN=any-string-you-make-up
For the Web sidecar — pair your phone:
composer require livewire/livewire livewire/flux # for the UI
php artisan whatsapp:sidecar:install # one-time, ~600 MB Chrome download
php artisan whatsapp:sidecar:start # boots in background
php artisan whatsapp:web:listen main & # SSE → Laravel events (run under Supervisor in prod)
# Open http://your-app.test/whatsapp/sessions and click "Start" → scan QR with your phone
use Kstmostofa\LaravelWhatsApp\Facades\WhatsApp;
use Kstmostofa\LaravelWhatsApp\Jobs\SendMessage;
// One-line send — picks backend by recipient shape
WhatsApp::send('+9665XXXXXXXX', 'Hello from Laravel'); // → Cloud API
WhatsApp::send('[email protected]', 'Hello via personal number'); // → Web sidecar
// Templated business message (Cloud API)
WhatsApp::messages()->sendTemplate('+9665XXXXXXXX', 'order_ready', 'en_US', [
['type' => 'body', 'parameters' => [['type' => 'text', 'text' => 'Munir']]],
]);
// Personal-number flow (Web sidecar — works for any chat your paired phone can see)
WhatsApp::web('main')->groups()->create('Project X', ['[email protected]']);
WhatsApp::web('main')->messages()->sendImage('[email protected]', ['url' => 'https://…/photo.jpg', 'caption' => 'Hi']);
// Or queue it
SendMessage::dispatch('+9665XXXXXXXX', 'Queued hello');
// Inbound — listen via Laravel events
Event::listen(\Kstmostofa\LaravelWhatsApp\Events\Web\MessageReceived::class, function ($event) {
Log::info('Got message', ['from' => $event->from(), 'body' => $event->body()]);
});
| Feature | Cloud API | Web sidecar |
|---|---|---|
| Personal-number QR pairing | ❌ | ✅ |
| Send to / receive from groups | ❌ | ✅ |
| Status / Stories | ❌ | ✅ |
| Free-form messages anytime | ❌ (templates outside 24h) | ✅ |
| Approved business templates | ✅ | ❌ |
| Official, no ban risk | ✅ | ❌ (browser automation — ToS gray area) |
| Scalable to millions | ✅ | ⚠️ session-bound |
| No extra runtime on host | ✅ | ❌ (Node + Chromium) |
Most apps use both — Cloud API for transactional/template sends at scale, Web sidecar for the features Cloud API doesn't expose.
The admin UI under /whatsapp works on whatever your app already uses:
| Your app uses… | Set in .env |
What you get |
|---|---|---|
| Tailwind v4 + Vite | WHATSAPP_UI_CSS_MODE=vite (default) |
Smallest tree-shaken bundle. Add 3 @source lines to your app.css. |
| Anything else (Tailwind v3 / Bootstrap / plain CSS / nothing) | WHATSAPP_UI_CSS_MODE=standalone |
Pre-compiled CSS shipped with the package, served from /whatsapp/_assets/laravel-whatsapp.css (~32 KB gz). No npm/Tailwind needed. Loads only on /whatsapp/* pages — your main app stays untouched. |
| No UI at all | skip composer require livewire/flux |
Headless. Full access to WhatsApp:: facade, Events, Jobs, webhook receiver, all CLI commands. |
Full setup details + dark mode + screenshots → docs site.
| Command | Purpose |
|---|---|
whatsapp:sidecar:install |
Clone whatsapp-web.js, npm ci, download Chromium |
whatsapp:sidecar:start / :stop / :status |
Lifecycle of the Node process |
whatsapp:web:listen [session] |
Long-running: sidecar SSE → Laravel events |
whatsapp:health [--json] [--exit-code] |
Health probe — pipe into cron / monitoring |
WHATSAPP_WEB_TOKEN (shared secret between PHP and sidecar)WHATSAPP_APP_SECRET (HMAC for Cloud webhook signatures)/whatsapp/* routes in your own auth middleware: config/laravel-whatsapp.php → ui.middlewarewhatsapp:web:listen under Supervisor / systemd, one process per sessionWHATSAPP_DB_CONNECTION=whatsapp)WHATSAPP_BROADCAST=true) + run Laravel Reverb for instant UI updatesDetailed deployment guide → docs/production.
Echo channel listenersMIT. See LICENSE.
Issues + PRs welcome at github.com/kstmostofa/laravel-whatsapp. Please run vendor/bin/phpunit locally before submitting.
How can I help you explore Laravel packages today?