Broadcasting lets a server-side event — a new order, a chat message, a notification — reach a connected browser instantly, without the browser having to poll for updates. Laravel's broadcasting system is the glue between an Eloquent/application event and a WebSocket connection; it doesn't run the WebSocket server itself.
1. Make an event broadcastable
class OrderShipped implements ShouldBroadcast
{
public function __construct(public Order $order) {}
public function broadcastOn(): Channel
{
return new PrivateChannel('orders.'.$this->order->user_id);
}
}
Implementing ShouldBroadcast (instead of just firing a normal event) is what tells Laravel this event should also go out over the configured broadcast driver, not just trigger local listeners.
2. Choose a broadcast driver
Laravel doesn't host WebSocket infrastructure itself — BROADCAST_CONNECTION in .env points to an actual driver: Pusher (hosted), Ably (hosted), or a self-hosted option like Laravel Reverb (first-party, added in Laravel 11) or soketi. The application code above is identical regardless of which driver is behind it.
3. Listen on the frontend
Echo.private('orders.' + userId)
.listen('OrderShipped', (e) => {
console.log('Order shipped:', e.order);
});
Laravel Echo is the JavaScript counterpart that subscribes to the channel and receives the event — it needs to be configured with the same driver credentials as the backend.
Private channels and authorization
A PrivateChannel requires the connecting user to be authorized for that specific channel — defined in routes/channels.php:
Broadcast::channel('orders.{userId}', function ($user, $userId) {
return (int) $user->id === (int) $userId;
});
Without this authorization callback returning true, the private channel subscription is rejected — this is the actual access-control boundary, not just a naming convention.
Firing the event
event(new OrderShipped($order));
From here it behaves like any other Laravel event — the broadcasting happens automatically because the event implements ShouldBroadcast, with no extra call needed beyond the normal event() dispatch.