# Real-time features in Laravel: WebSocket and broadcasting

> Adding live updates with Laravel Broadcasting: event-driven publishing, Pusher integration, and listening on the client side.

- Published: 2023-04-02
- Category: Web Development
- Tags: Laravel
- Reading time: 3 min read
- Source: https://www.muhammetsafak.com.tr/en/blog/real-time-features-in-laravel-websocket-and-broadcasting/
- Language: en-US
- Author: Muhammet Şafak

---
Implementing real-time updates in an application means stepping outside HTTP's request-response cycle. Having the user refresh the page to see new data is no longer good enough — when something changes on the server, the client needs to know immediately. Notifications, live counters, transaction status updates: they all share the same underlying requirement.

Laravel addresses this through its **Broadcasting** layer. The model is event-driven: you fire an event on the PHP side, and that event is delivered to the client over a WebSocket channel. For the transport layer you can use Pusher, Ably, or a self-hosted Soketi instance.

## How broadcasting works

The basic flow looks like this:

1. You create an `Event` class in PHP and implement the `ShouldBroadcast` interface.
2. When you fire the event, Laravel sends a message to the configured broadcast driver.
3. On the client side (JavaScript) you subscribe to the same channel using the `Echo` library.
4. When the message arrives, your listener runs.

```php
// app/Events/OrderStatusUpdated.php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class OrderStatusUpdated implements ShouldBroadcast
{
    public function __construct(
        public readonly int $orderId,
        public readonly string $status
    ) {}

    public function broadcastOn(): Channel
    {
        return new Channel('orders.' . $this->orderId);
    }

    public function broadcastAs(): string
    {
        return 'status.updated';
    }
}
```

Dispatching the event is identical to [any other Laravel event](/en/blog/events-and-listeners-in-laravel/):

```php
broadcast(new OrderStatusUpdated($order->id, 'shipped'));
```

## Listening on the client side

Laravel Echo is the official library for managing WebSocket channels in JavaScript. To work with Pusher you also need the `pusher-js` package:

```bash
npm install --save laravel-echo pusher-js
```

```javascript
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

const echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
});

echo.channel('orders.' + orderId)
    .listen('.status.updated', (data) => {
        console.log('Order status:', data.status);
        // Update the UI
    });
```

## Channel types

Laravel offers three channel types:

**Public Channel:** Any client can subscribe. Suitable for general notifications and live counters.

**Private Channel:** Authentication is required before subscribing. You use `PrivateChannel` instead of `Channel`, and define the authorization rule in `routes/channels.php`.

```php
// routes/channels.php
Broadcast::channel('orders.{orderId}', function ($user, $orderId) {
    return $user->id === Order::findOrNew($orderId)->user_id;
});
```

**Presence Channel:** Builds on top of the private channel and adds awareness of who is currently subscribed. Used for collaborative spaces and "who's online" type features.

## broadcastWith and shaping the payload

You can use the `broadcastWith` method to customize the data your event carries. By default Laravel sends all `public` properties of the class, but sometimes that means too much data or you want to include a related model:

```php
public function broadcastWith(): array
{
    return [
        'order_id' => $this->orderId,
        'status'   => $this->status,
        'label'    => __('order.status.' . $this->status),
    ];
}
```

If you forget to add this method and there is a sensitive field among your `public` properties (say, a user ID or pricing information), that data can leak to the client. Defining `broadcastWith` explicitly on every event eliminates that risk.

## Soketi: the self-hosted option

If you would rather not depend on a third-party service like Pusher or Ably, you can host Soketi yourself — a Node-based WebSocket server that speaks the Pusher protocol.

For those who want to manage their own infrastructure, the `beyondcode/laravel-websockets` package is still a valid choice. Because it is compatible with the Pusher protocol, the client-side code remains unchanged.

## WebSocket vs. polling: when to use which

WebSocket is not the best solution for every scenario. Infrastructure costs scale with the number of concurrent connections. If "instant" delivery is not critical and updates are infrequent, simple polling often achieves the same result with far less complexity.

The rule of thumb I use in my own projects: if an update only concerns the user who triggered an action and a few seconds of delay is acceptable, polling is sufficient. If multiple users need to see the same data in real time, or if the server is the one initiating the push, WebSocket is the better fit.

Where WebSocket clearly wins is in scenarios that require messages to flow from the server to the client unprompted: instant notifications, live progress bars, multi-user interactions — polling simply does not feel responsive enough for these. The choice should always be proportional to the actual requirement.

The Broadcasting layer removes the unnecessary friction of wiring this infrastructure into a Laravel application. Fire an event, define a channel, listen on the client. Everything beyond that is largely handled by the framework.
