Real-time features like instant notifications, live chat, and activity feeds have become standard requirements for modern web applications. For years, Laravel developers relied on third-party SaaS providers like Pusher or self-hosted packages like Soketi and Laravel WebSockets.
With the release of Laravel Reverb, Laravel now provides a first-party, blazing-fast, scalable WebSocket server written purely in PHP that integrates seamlessly with Laravel Echo and Event Broadcasting.
In this guide, we will build a complete, production-ready real-time notification system using Laravel Reverb from scratch.
1. Why Laravel Reverb?
Traditional HTTP polling forces the client to send requests every few seconds, which wastes server resources and introduces unnecessary latency. WebSockets maintain a single, persistent two-way connection between the browser and your server.
Key advantages of Reverb include:
- First-Party Integration: Pre-configured to work directly with Laravel events and broadcasting queues.
- Speed & Concurrency: Built on top of ReactPHP, allowing thousands of active connections without dedicated external binaries.
- Pusher Compatibility: Reverb implements the Pusher protocol, so existing Laravel Echo frontend code works without changes.
- Zero Extra SaaS Costs: Host it on your own server without paying per-connection subscription fees.
2. Installing and Configuring Reverb
To get started, install Reverb via Composer:
composer require laravel/reverb
php artisan reverb:installThe installation command will publish the configuration to config/reverb.php and add the required environment variables to your .env file:
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
REVERB_HOST="localhost"
REVERB_PORT=8080
REVERB_SCHEME=http
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"3. Creating the Broadcast Event
Let's create an event that triggers whenever a user receives a new order notification. Run the following Artisan command:
php artisan make:event OrderPlacedNotificationOpen the generated file at app/Events/OrderPlacedNotification.php and implement the ShouldBroadcast interface:
<?php
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class OrderPlacedNotification implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(public Order $order)
{
}
/**
* Define which channel the event should broadcast on.
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('orders.' . $this->order->user_id),
];
}
/**
* Payload sent to the frontend.
*/
public function broadcastWith(): array
{
return [
'order_id' => $this->order->id,
'amount' => $this->order->total_amount,
'customer_name'=> $this->order->customer_name,
'message' => 'New order #' . $this->order->id . ' received!',
'created_at' => $this->order->created_at->toDateTimeString(),
];
}
/**
* Event broadcast name for Echo listener.
*/
public function broadcastAs(): string
{
return 'OrderPlaced';
}
}4. Authorizing the Private Channel
Because notifications are sensitive, we use a PrivateChannel. Authorize the user in routes/channels.php:
<?php
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('orders.{userId}', function ($user, $userId) {
return (int) $user->id === (int) $userId;
});5. Setting Up the Frontend with Laravel Echo
Install the required JavaScript dependencies:
npm install --save-dev laravel-echo pusher-jsConfigure Echo in your resources/js/bootstrap.js:
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});Now listen for the event inside your Blade view or React/Vue component:
const userId = document.querySelector('meta[name="user-id"]').getAttribute('content');
window.Echo.private(`orders.${userId}`)
.listen('.OrderPlaced', (event) => {
console.log('Notification received:', event);
// Example: Show Toastr / SweetAlert / Popup notification
alert(`${event.message} - Total: $${event.amount}`);
});6. Running and Testing in Production
To start the WebSocket server during local development, run:
php artisan reverb:start --debugIn production, run Reverb under a process supervisor like Supervisor to keep the daemon running continuously:
[program:reverb]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/your-app/artisan reverb:start
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/your-app/storage/logs/reverb.logAlso ensure that your queue worker (php artisan queue:work) is active, because Laravel broadcasts events through your default queue.
Conclusion
Laravel Reverb removes the barrier of third-party pricing tiers and complex setup procedures for real-time applications. By pairing Reverb with private broadcasting channels and Laravel Echo, you can build responsive, scalable notification engines with full control over your server infrastructure.