Skip to main content
The console screens that follow live activity — flow sessions and flow logs — stay current either by polling or over a websocket. Polling is the default and needs nothing. With BROADCAST_CONNECTION=null the application broadcasts nothing, and each live screen reloads its data every few seconds. Turn websockets on when you want changes to show as they happen, or when many people keep those screens open and the polling adds up. Nothing about the installation changes when it is off: Reverb ships with Core but does not run, and the browser never downloads the websocket client.

How it works

After a flow step is committed, the application announces it on a private channel of the assistant, at most once every couple of seconds. Each open screen listens on that channel and reloads its own data when it hears something. The announcement carries no data; the reload goes through the normal authorized request, so the websocket never sees what the screen shows. Who may listen is checked by the application at /broadcasting/auth, on the tenant’s own host, with the same session and account checks as the console. The websocket server only relays. The browser learns whether to connect, and where, from the page itself at runtime — nothing is compiled into the front end, so the prebuilt images work on any domain.

Docker Compose

Reverb runs as the reverb service behind the realtime profile. It uses the application image, and nginx (the web service) forwards browsers to it at /app/ on the site’s own origin, so TLS in front covers the websocket too and no extra port or certificate is needed.
  1. Generate three values — any random strings will do:
  2. Add them to the .env beside compose.yaml, and switch the broadcaster:
    REVERB_HOST, REVERB_PORT and REVERB_SCHEME are set by compose.yaml to the reverb service; leave them out of the .env.
  3. Start the stack with the profile — together with any other profiles you use:
    Configuration is cached when the containers start, so app, horizon and scheduler must be recreated to pick up the new values; up -d does that when the .env changed.
Open the flow sessions screen: its hint changes from “Refreshes every N s” to “Live”. To turn it off again, set BROADCAST_CONNECTION=null, recreate the containers, and stop reverb.

Bare metal

Run the server under your process supervisor next to Horizon:
Set the same BROADCAST_CONNECTION and REVERB_APP_* values as above, plus where the application publishes to it:
Then forward the websocket path in your web server, so browsers reach it on the site’s own origin. For nginx, inside the site’s server block:
Like Horizon, Reverb is a long-running PHP process holding the previous release in memory: restart it on every deploy (php artisan reverb:restart).

Configuration

Reverb’s own settings — connection limits, ping interval, scaling across several servers through Redis — are read from the REVERB_* variables described in the Reverb documentation. One Reverb process is plenty for a single installation.

Pusher, Soketi and other servers

The browser speaks the Pusher protocol, so any server that does works in place of Reverb:
  • Pusher: BROADCAST_CONNECTION=pusher with PUSHER_APP_ID, PUSHER_APP_KEY, PUSHER_APP_SECRET and PUSHER_APP_CLUSTER. No other setting is needed.
  • Soketi or another self-run Pusher-protocol server: the same pusher connection, with PUSHER_HOST, PUSHER_PORT and PUSHER_SCHEME for the application, and BROADCAST_CLIENT_HOST (and port and scheme) for browsers.
Other Laravel broadcasters (redis, ably) deliver on the server side, but the console has no client for them and keeps polling.

Troubleshooting

The live hint still says it refreshes. The page decides when it loads: check that php artisan config:show broadcasting.default prints reverb inside the app container, and that the containers were recreated after the .env change. REVERB_APP_KEY must be set — without it the browser has nothing to connect with and polls. The browser console shows a failed websocket connection. reverb is not running (nginx answers 502 at /app/), or a proxy in front does not pass websocket upgrades. Caddy does by default; other proxies need it enabled for /app/. Subscribing fails with 403. The private channel was refused at /broadcasting/auth: the user is signed out, or no longer has access to the assistant. The screen falls back to its periodic reload.