> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Broadcasting

> Leer realtime WebSocket-communicatie implementeren met Laravel broadcasting en Laravel Reverb.

## Wat is broadcasting

Met WebSockets kun je in realtime data van de server naar de client sturen.
Laravel broadcasting is een mechanisme dat serverside events via WebSockets aflevert bij de JavaScript in je frontend.

Wanneer bijvoorbeeld de status van een bestelling verandert, kun je die update direct in de browser tonen zonder de pagina te herladen.
De kracht van Laravel broadcasting is dat je de serverside eventnamen en data één-op-één deelt met de clientside.

<Info>
  Broadcasting is gebouwd bovenop het eventsysteem van Laravel.
  We raden aan om eerst de basis van [events en listeners](/nl/events) te begrijpen.
</Info>

```mermaid theme={null}
flowchart LR
    A["Serverside<br>event afvuren<br>dispatch()"] --> B["Broadcast-<br>driver<br>(Reverb e.d.)"]
    B --> C["WebSocket-<br>server"]
    C --> D["Kanaal-<br>autorisatiecheck"]
    D --> E["Client<br>Laravel Echo"]
    E --> F["Realtime<br>UI-update"]
```

## Setup

In een nieuwe Laravel-applicatie is broadcasting standaard uitgeschakeld.
Je schakelt het in met het Artisan-commando `install:broadcasting`.

```shell theme={null}
php artisan install:broadcasting
```

Bij het uitvoeren van dit commando word je gevraagd welke broadcastdienst je wilt gebruiken.
Ook worden `config/broadcasting.php` en `routes/channels.php` gegenereerd.

## Laravel Reverb

Vanaf Laravel 11 wordt de officiële WebSocket-server **Laravel Reverb** aanbevolen.
Reverb is selfhosted en maakt realtime communicatie mogelijk zonder extra externe diensten.

### Installatie

Voeg je de optie `--reverb` toe aan het commando `install:broadcasting`, dan worden de benodigde Composer- en NPM-packages voor Reverb geïnstalleerd en wordt `.env` in één keer geconfigureerd.

```shell theme={null}
php artisan install:broadcasting --reverb
```

Wil je handmatig installeren, voeg dan de package toe via Composer en voer daarna het installatiecommando uit.

```shell theme={null}
composer require laravel/reverb

php artisan reverb:install
```

### De belangrijkste instellingen in .env

```ini theme={null}
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}"
```

### De Reverb-server starten

```shell theme={null}
php artisan reverb:start
```

In productie beheer je Reverb als daemon met een procesmanager zoals Supervisor.

<Tip>
  Broadcast-events worden via de queue verwerkt.
  Naast de Reverb-server moet je dus ook een queueworker draaien.

  ```shell theme={null}
  php artisan queue:work
  ```
</Tip>

## Een broadcast-event maken

### De eventklasse genereren

```shell theme={null}
php artisan make:event OrderShipmentStatusUpdated
```

Implementeer de interface `ShouldBroadcast` in de gegenereerde eventklasse.

```php theme={null}
<?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\Queue\SerializesModels;

class OrderShipmentStatusUpdated implements ShouldBroadcast
{
    use InteractsWithSockets, SerializesModels;

    public function __construct(
        public Order $order,
    ) {}

    /**
     * Het kanaal teruggeven waarop het event wordt gebroadcast
     */
    public function broadcastOn(): Channel
    {
        return new PrivateChannel('orders.' . $this->order->id);
    }
}
```

Door alleen `ShouldBroadcast` te implementeren, wordt het event bij het afvuren automatisch via de queue gebroadcast.

### De broadcastdata aanpassen

Standaard worden alle `public` properties van de eventklasse opgenomen in de broadcast-payload.
Wil je de te versturen data beperken, definieer dan de methode `broadcastWith`.

```php theme={null}
public function broadcastWith(): array
{
    return [
        'order_id' => $this->order->id,
        'status'   => $this->order->status,
    ];
}
```

### De broadcastnaam aanpassen

Standaard wordt de klassenaam de eventnaam.
Met de methode `broadcastAs` kun je een eigen naam opgeven.

```php theme={null}
public function broadcastAs(): string
{
    return 'order.status.updated';
}
```

Bij het luisteren in de frontend zet je een `.` vooraan om het namespaceprefix van je app uit te schakelen.

```js theme={null}
Echo.private(`orders.${orderId}`)
    .listen('.order.status.updated', (e) => {
        console.log(e);
    });
```

## Soorten kanalen

| Kanaal       | Klasse            | Beschrijving                                                                |
| ------------ | ----------------- | --------------------------------------------------------------------------- |
| **Public**   | `Channel`         | Geen authenticatie nodig. Iedereen kan zich abonneren                       |
| **Private**  | `PrivateChannel`  | Alleen geauthenticeerde gebruikers. Autorisatielogica vereist               |
| **Presence** | `PresenceChannel` | Uitbreiding van Private. Je kunt de deelnemerslijst van het kanaal opvragen |

```php theme={null}
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;

// Public kanaal
public function broadcastOn(): Channel
{
    return new Channel('posts');
}

// Private kanaal
public function broadcastOn(): Channel
{
    return new PrivateChannel('orders.' . $this->order->id);
}

// Presence kanaal
public function broadcastOn(): Channel
{
    return new PresenceChannel('rooms.' . $this->room->id);
}
```

Om naar meerdere kanalen te broadcasten, geef je een array terug.

```php theme={null}
public function broadcastOn(): array
{
    return [
        new PrivateChannel('orders.' . $this->order->id),
        new Channel('admin.orders'),
    ];
}
```

## Kanaalautorisatie

Bij Private- en Presence-kanalen vindt vóór het abonneren een autorisatiecheck plaats aan de serverkant.

### routes/channels.php

Definieer autorisatiecallbacks in het bestand `routes/channels.php` dat door het commando `install:broadcasting` wordt gegenereerd.

```php theme={null}
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Broadcast;

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

Het eerste argument van de callback is de geauthenticeerde gebruiker; de argumenten daarna zijn de wildcards uit de kanaalnaam.
Geef je `true` of een truthy waarde terug, dan slaagt de autorisatie; geef je `false` terug, dan wordt geweigerd.

<Info>
  Route model binding werkt hier ook.
  Noem je het kanaal `orders.{order}`, dan krijg je een instantie van het `Order`-model doorgegeven.
</Info>

```php theme={null}
Broadcast::channel('orders.{order}', function (User $user, Order $order) {
    return $user->id === $order->user_id;
});
```

### Autorisatie via channel-klassen

Krijg je steeds meer kanalen, dan kun je de boel organiseren met channel-klassen.

```shell theme={null}
php artisan make:channel OrderChannel
```

```php theme={null}
<?php

namespace App\Broadcasting;

use App\Models\Order;
use App\Models\User;

class OrderChannel
{
    public function join(User $user, Order $order): bool
    {
        return $user->id === $order->user_id;
    }
}
```

Registreer de klasse in `routes/channels.php`.

```php theme={null}
use App\Broadcasting\OrderChannel;

Broadcast::channel('orders.{order}', OrderChannel::class);
```

## Events afvuren

Events die `ShouldBroadcast` implementeren, vuur je af zoals gewone events.

```php theme={null}
use App\Events\OrderShipmentStatusUpdated;

OrderShipmentStatusUpdated::dispatch($order);
```

Wil je alleen naar andere gebruikers broadcasten, met uitzondering van jezelf, gebruik dan `toOthers`.

```php theme={null}
broadcast(new OrderShipmentStatusUpdated($order))->toOthers();
```

<Warning>
  Om `toOthers` te gebruiken, moet de eventklasse de trait `InteractsWithSockets` gebruiken.
</Warning>

## Ontvangen in de frontend

### Laravel Echo instellen

Gebruik je Reverb, dan configureer je de Echo-instantie in `resources/js/bootstrap.js`.

```shell theme={null}
npm install --save-dev laravel-echo pusher-js
```

```js theme={null}
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'],
});
```

### Luisteren naar events

```js theme={null}
// Public kanaal
Echo.channel('posts')
    .listen('PostPublished', (e) => {
        console.log(e.post);
    });

// Private kanaal
Echo.private(`orders.${orderId}`)
    .listen('OrderShipmentStatusUpdated', (e) => {
        console.log(e.order);
    });

// Presence kanaal
Echo.join(`rooms.${roomId}`)
    .here((users) => {
        console.log('Huidige leden:', users);
    })
    .joining((user) => {
        console.log(user.name, 'is erbij gekomen');
    })
    .leaving((user) => {
        console.log(user.name, 'is vertrokken');
    })
    .listen('MessagePosted', (e) => {
        console.log(e.message);
    });
```

### React- / Vue-hooks gebruiken

Gebruik je een starter kit voor React of Vue, dan kun je het compacter schrijven met de speciale hooks.

```js theme={null}
import { useEcho } from "@laravel/echo-react";

// Private kanaal
useEcho(
    `orders.${orderId}`,
    "OrderShipmentStatusUpdated",
    (e) => {
        console.log(e.order);
    },
);

// Public kanaal
import { useEchoPublic } from "@laravel/echo-react";

useEchoPublic("posts", "PostPublished", (e) => {
    console.log(e.post);
});
```

De `useEcho`-hook verlaat het kanaal automatisch wanneer de component wordt geünmount.

<Tip>
  Controleer voordat je de frontend-assets bouwt of de `VITE_REVERB_*`-variabelen in `.env` correct zijn ingesteld.

  ```shell theme={null}
  npm run build
  ```
</Tip>

## Praktijkvoorbeeld: bestelstatus in realtime bijwerken

<Steps>
  <Step title="Broadcasting inschakelen">
    ```shell theme={null}
    php artisan install:broadcasting --reverb
    ```

    Start de Reverb-server en een queueworker.

    ```shell theme={null}
    php artisan reverb:start
    php artisan queue:work
    ```
  </Step>

  <Step title="De eventklasse maken">
    ```shell theme={null}
    php artisan make:event OrderShipmentStatusUpdated
    ```

    Bewerk `app/Events/OrderShipmentStatusUpdated.php`.

    ```php theme={null}
    <?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\Queue\SerializesModels;

    class OrderShipmentStatusUpdated implements ShouldBroadcast
    {
        use InteractsWithSockets, SerializesModels;

        public function __construct(
            public Order $order,
        ) {}

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

        public function broadcastWith(): array
        {
            return [
                'order_id' => $this->order->id,
                'status'   => $this->order->status,
            ];
        }
    }
    ```
  </Step>

  <Step title="Kanaalautorisatie definiëren">
    Voeg de autorisatielogica toe aan `routes/channels.php`.

    ```php theme={null}
    use App\Models\Order;
    use App\Models\User;
    use Illuminate\Support\Facades\Broadcast;

    Broadcast::channel('orders.{order}', function (User $user, Order $order) {
        return $user->id === $order->user_id;
    });
    ```
  </Step>

  <Step title="Het event afvuren">
    Vuur het event af in de controller of job die de bestelstatus bijwerkt.

    ```php theme={null}
    use App\Events\OrderShipmentStatusUpdated;

    $order->update(['status' => 'shipped']);

    OrderShipmentStatusUpdated::dispatch($order);
    ```
  </Step>

  <Step title="Luisteren in de frontend">
    Ontvang het event met een inline script in je Blade-template of in een React/Vue-component.

    ```js theme={null}
    Echo.private(`orders.${orderId}`)
        .listen('OrderShipmentStatusUpdated', (e) => {
            document.getElementById('status').textContent = e.status;
        });
    ```
  </Step>
</Steps>

## Volgende stappen

<Card title="Laravel Reverb" href="/nl/reverb">
  Lees meer over het opzetten van de Reverb-server, het draaien in productie en schalen.
</Card>

<Card title="Queues en jobs" href="/nl/queues">
  Broadcasting wordt via de queue verwerkt. Bekijk hoe je queues configureert en beheert.
</Card>

<Card title="Events en listeners" href="/nl/events">
  Leer meer over het Laravel-eventsysteem, de basis van broadcasting.
</Card>


## Related topics

- [Laravel AI SDK](/nl/ai-sdk.md)
- [FAQ over de nieuwe appstructuur van Laravel 11+](/nl/advanced/app-structure-faq.md)
- [SessionEvent](/nl/packages/laravel-copilot-sdk/session-event.md)
- [Laravel Reverb](/nl/reverb.md)
- [Redis](/nl/redis.md)
