Laravel Echo / Reverb

Socket Conveyor can act as a Pusher/Reverb-compatible WebSocket and REST broadcast server. Laravel keeps using its built-in broadcasting tools.


Start Conveyor in Pusher mode

1<?php
2
3use Conveyor\Constants;
4use Conveyor\ConveyorServer;
5
6require __DIR__ . '/vendor/autoload.php';
7
8(new ConveyorServer())
9    ->host('127.0.0.1')
10    ->port(8990)
11    ->serverOptions([
12        'worker_num' => 1,
13        'task_worker_num' => 1,
14    ])
15    ->conveyorOptions([
16        Constants::WEBSOCKET_SUBPROTOCOL => Constants::PUSHER,
17        Constants::USE_PRESENCE => true,
18        Constants::APPS => [[
19            'app_id' => 'local-app',
20            'key' => 'local-key',
21            'secret' => 'local-secret',
22            'enable_client_messages' => true,
23            'enabled' => true,
24        ]],
25    ])
26    ->start();

The repository includes the same setup for local smoke testing:

1php examples/pusher-real/run-conveyor.php

Configure Laravel

Use Laravel's built-in Reverb-style environment variables and point them at Conveyor:

1BROADCAST_CONNECTION=reverb
2
3REVERB_APP_ID=local-app
4REVERB_APP_KEY=local-key
5REVERB_APP_SECRET=local-secret
6REVERB_HOST=127.0.0.1
7REVERB_PORT=8990
8REVERB_SCHEME=http
9
10VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
11VITE_REVERB_HOST="${REVERB_HOST}"
12VITE_REVERB_PORT="${REVERB_PORT}"
13VITE_REVERB_SCHEME="${REVERB_SCHEME}"

If your app uses Laravel's pusher connection instead of reverb, use equivalent PUSHER_* values with the same app id, key, secret, host, port, and scheme.

Laravel applications created with recent versions do not enable broadcasting by default. Install it with the official Artisan command:

1php artisan install:broadcasting

The command will prompt you for the broadcasting service to use. You can also target Reverb directly:

1php artisan install:broadcasting --reverb

install:broadcasting creates (or ensures) the following:

  • config/broadcasting.php
  • routes/channels.php (for your channel authorization callbacks)
  • The necessary environment variables and bootstrap wiring

If you are on an older Laravel version or have a custom setup, you may need to publish the broadcasting routes and config manually.

Confirm that Laravel registered the authorization route:

1php artisan route:list --name=broadcasting

You should see an entry for broadcasting.auth.

Configure Echo

Install the stock clients:

1npm install laravel-echo pusher-js
1import Echo from 'laravel-echo'
2import Pusher from 'pusher-js'
3
4window.Pusher = Pusher
5
6window.Echo = new Echo({
7  broadcaster: 'reverb',
8  key: import.meta.env.VITE_REVERB_APP_KEY,
9  wsHost: import.meta.env.VITE_REVERB_HOST,
10  wsPort: import.meta.env.VITE_REVERB_PORT,
11  wssPort: import.meta.env.VITE_REVERB_PORT,
12  forceTLS: import.meta.env.VITE_REVERB_SCHEME === 'https',
13  enabledTransports: ['ws', 'wss'],
14})

For private and presence channels, keep the WebSocket host pointed at Conveyor, but point Echo authorization at your Laravel HTTP app:

1VITE_LARAVEL_URL=http://localhost:8000
1window.Echo = new Echo({
2  broadcaster: 'reverb',
3  key: import.meta.env.VITE_REVERB_APP_KEY,
4  wsHost: import.meta.env.VITE_REVERB_HOST,
5  wsPort: import.meta.env.VITE_REVERB_PORT,
6  wssPort: import.meta.env.VITE_REVERB_PORT,
7  forceTLS: import.meta.env.VITE_REVERB_SCHEME === 'https',
8  enabledTransports: ['ws', 'wss'],
9  authEndpoint: `${import.meta.env.VITE_LARAVEL_URL}/broadcasting/auth`,
10  auth: {
11    withCredentials: true,
12  },
13})

Use Echo normally

1window.Echo.channel('orders')
2  .listen('.OrderShipped', event => {
3    console.log(event)
4  })
5
6window.Echo.private('orders.1')
7  .listen('.OrderUpdated', event => {
8    console.log(event)
9  })
10
11window.Echo.join('room.1')
12  .here(users => console.log('here', users))
13  // ...

For the full presence API (.here(), .joining(), .leaving(), .listenForWhisper(), and whispers), see the dedicated Presence page.

Laravel keeps channel authorization in routes/channels.php:

1use Illuminate\Support\Facades\Broadcast;
2
3Broadcast::channel('orders.{orderId}', function ($user, int $orderId) {
4    return true;
5});
6
7Broadcast::channel('room.{roomId}', function ($user, int $roomId) {
8    return [
9        'id' => $user->id,
10        'name' => $user->name,
11    ];
12});

Broadcast events normally:

1broadcast(new OrderShipped($order))->toOthers();

Conveyor receives Laravel's signed Pusher/Reverb REST publish request at /apps/{app_id}/events, delivers the event to connected Echo clients, and honors socket_id exclusion for toOthers().

Verify with the browser smoke

Terminal 1:

1php examples/pusher-real/run-conveyor.php

Terminal 2:

1php -S 127.0.0.1:8991 examples/pusher-real/router.php

Open:

1http://127.0.0.1:8991/echo.html

Expected results:

  • The page reaches connected and shows a socket_id.
  • Public, private, and presence subscriptions succeed.
  • The Public, Private, and Presence buttons log DemoEvent.
  • Public toOthers() does not echo to the current tab.
  • A second tab can receive a whisper from the first tab.

About conveyor-laravel-broadcaster

For Pusher/Reverb-compatible Laravel Echo usage, you should not need the older custom Conveyor Laravel broadcaster. Use Laravel's built-in reverb or pusher driver and point it at Conveyor.

The custom broadcaster package is only relevant for applications that intentionally use Conveyor's native protocol instead of Laravel's Pusher/Reverb protocol.