onveyor
Site menu
GitHub
Laravel and ecosystem / Laravel Echo / Reverb Pusher/Reverb mode

Laravel Echo / Reverb

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

1Start Conveyor in Pusher mode

server.phppusher/reverb
<?php

use Conveyor\Constants;
use Conveyor\ConveyorServer;

require __DIR__ . '/vendor/autoload.php';

(new ConveyorServer())
    ->host('127.0.0.1')
    ->port(8990)
    ->serverOptions([
        'worker_num' => 1,
        'task_worker_num' => 1,
    ])
    ->conveyorOptions([
        Constants::WEBSOCKET_SUBPROTOCOL => Constants::PUSHER,
        Constants::USE_PRESENCE => true,
        Constants::APPS => [[
            'app_id' => 'local-app',
            'key' => 'local-key',
            'secret' => 'local-secret',
            'enable_client_messages' => true,
            'enabled' => true,
        ]],
    ])
    ->start();

The repository includes the same setup for local smoke testing:

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

2Configure Laravel

Use Reverb-style environment variables and point them at Conveyor, then mirror them into VITE_REVERB_* for the frontend:

.envpusher/reverb
BROADCAST_CONNECTION=reverb

REVERB_APP_ID=local-app
REVERB_APP_KEY=local-key
REVERB_APP_SECRET=local-secret
REVERB_HOST=127.0.0.1
REVERB_PORT=8990
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}"

If you use Laravel's pusher connection, use the equivalent PUSHER_* values.

Install broadcasting

Recent Laravel versions do not enable broadcasting by default. install:broadcasting prompts for a service; --reverb targets Reverb directly.

shell
php artisan install:broadcasting
shell
php artisan install:broadcasting --reverb

The command creates or ensures config/broadcasting.php, routes/channels.php, and the required environment variables and bootstrap wiring. On older Laravel versions or custom setups, publish the broadcasting routes and config manually.

Confirm the broadcasting.auth route is registered:

shell
php artisan route:list --name=broadcasting

Tested versions: this static-site handoff does not record exact tested Laravel, Laravel Echo, pusher-js, PHP, OpenSwoole or Conveyor versions. These examples are configuration guidance; verify your installed combination using the browser smoke test below. See tested-version status.

3Configure Echo

shell
npm install laravel-echo pusher-js
javascriptpusher/reverb
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,
  wssPort: import.meta.env.VITE_REVERB_PORT,
  forceTLS: import.meta.env.VITE_REVERB_SCHEME === 'https',
  enabledTransports: ['ws', 'wss'],
})

Private and presence channels

Keep the WebSocket host on Conveyor and set authEndpoint to your Laravel app's /broadcasting/auth. auth.withCredentials sends session credentials.

.env
VITE_LARAVEL_URL=http://localhost:8000
javascriptpusher/reverb
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,
  wssPort: import.meta.env.VITE_REVERB_PORT,
  forceTLS: import.meta.env.VITE_REVERB_SCHEME === 'https',
  enabledTransports: ['ws', 'wss'],
  authEndpoint: `${import.meta.env.VITE_LARAVEL_URL}/broadcasting/auth`,
  auth: {
    withCredentials: true,
  },
})

4Use Echo normally

javascriptpusher/reverb
window.Echo.channel('orders')
  .listen('.OrderShipped', event => {
    console.log(event)
  })

window.Echo.private('orders.1')
  .listen('.OrderUpdated', event => {
    console.log(event)
  })

window.Echo.join('room.1')
  .here(users => console.log('here', users))
  // ...

Presence methods — .here(), .joining(), .leaving(), .listenForWhisper() — and whispers are covered on Presence.

Define channel authorization in routes/channels.php. Private callbacks return true only when access is allowed; presence callbacks return user data only for authorized members. Return false to deny access.

routes/channels.php
use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('orders.{orderId}', function ($user, int $orderId) {
    return $user->orders()->whereKey($orderId)->exists();
});

Broadcast::channel('room.{roomId}', function ($user, int $roomId) {
    if (! $user->rooms()->whereKey($roomId)->exists()) {
        return false;
    }

    return [
        'id' => $user->id,
        'name' => $user->name,
    ];
});

Signing in alone does not grant channel access. This example assumes orders() contains orders owned by the user and rooms() contains rooms they belong to. Adapt these relationships or use your application’s authorization policies. A user requesting another user’s order, or a room they have not joined, is denied access; presence user data is returned only after membership is confirmed.

Broadcast events normally, and chain toOthers() to exclude the sender:

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

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

Verify with the browser smoke

terminal 1
php examples/pusher-real/run-conveyor.php
terminal 2
php -S 127.0.0.1:8991 examples/pusher-real/router.php

Open:

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

Expected:

  • 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 receives a whisper from the first.

About conveyor-laravel-broadcaster

Pusher/Reverb-compatible Echo usage does not need the native Conveyor Laravel broadcaster. Use Laravel's built-in reverb or pusher driver and point it at Conveyor.

For applications using Conveyor’s native HTTP endpoints and native clients, see the separate Laravel native broadcaster guide.