Getting Started
Get Relay running and publishing your first real-time event in under 5 minutes.
Prerequisites
You'll need Docker (recommended) or Go 1.22+ to run the server, a backend framework (Laravel, Node.js, Rails, or Django), and a browser-based frontend for the JS client.
1 Run the Server
Docker (recommended)
docker run -d -p 6001:6001 \
-e RELAY_APP_KEY=my-key \
-e RELAY_APP_SECRET=my-secret \
relayhq/relay:latest
Download the binary
Download the latest release for your platform from the releases page, then run:
RELAY_APP_KEY=my-key RELAY_APP_SECRET=my-secret ./relay
Build from source
git clone https://github.com/DarkNautica/Relay.git
cd Relay/relay-server
go build -o relay ./main.go
RELAY_APP_KEY=my-key RELAY_APP_SECRET=my-secret ./relay
The server starts on port 6001 by default. The built-in dashboard is at http://localhost:6001/dashboard.
2 Connect the JavaScript Client
npm install @relayhq/relay-js
import Relay from '@relayhq/relay-js'
const relay = new Relay('my-key', {
host: 'localhost',
port: 6001,
logToConsole: true, // helpful during development
})
// Monitor connection state
relay.connection.bind('connected', () => {
console.log('Connected! Socket ID:', relay.connection.socket_id)
})
// Subscribe to a channel and listen for events
const channel = relay.subscribe('chat')
channel.bind('new-message', (data) => {
console.log('New message:', data.text)
})
// Debug: log all events on this channel
channel.bindAll(({ event, data }) => {
console.log(`Event: ${event}`, data)
})
3 Publish from Your Backend
Choose your framework:
composer require relayhq/relay-php
// config/broadcasting.php
'default' => 'relay',
'connections' => [
'relay' => [
'driver' => 'relay',
'host' => env('RELAY_HOST', '127.0.0.1'),
'port' => env('RELAY_PORT', 6001),
'key' => env('RELAY_APP_KEY'),
'secret' => env('RELAY_APP_SECRET'),
'app_id' => env('RELAY_APP_ID'),
],
],
// Publish an event
broadcast(new MessageSent($message));
npm install @relayhq/relay-node
import { RelayClient } from '@relayhq/relay-node'
const relay = new RelayClient({
host: '127.0.0.1',
port: 6001,
appId: 'my-app',
key: 'my-key',
secret: 'my-secret',
})
await relay.publish('chat', 'new-message', { text: 'Hello!' })
# Gemfile
gem 'relay-ruby'
# config/cable.yml
production:
adapter: relay
host: 127.0.0.1
port: 6001
app_id: my-app
key: my-key
secret: my-secret
# Publish
ActionCable.server.broadcast('chat', { text: 'Hello!' })
pip install relay-python
from relay import RelayClient
relay = RelayClient(
host='127.0.0.1',
port=6001,
app_id='my-app',
key='my-key',
secret='my-secret',
)
relay.publish('chat', 'new-message', {'text': 'Hello!'})
4 Private Channels
Private channels require server-side authentication. The channel name must start with private-.
// Client side — subscribe to a private channel
const orders = relay.subscribe('private-orders.42')
orders.bind('update', (data) => console.log('Order update:', data))
The JS client will automatically POST to your auth endpoint (/broadcasting/auth by default). Your backend verifies the user and returns a signed token.
5 Presence Channels
Presence channels track which users are online. The channel name must start with presence-.
const room = relay.subscribe('presence-room.1')
// Fires when subscription succeeds with the initial member list
room.bind('relay:subscription_succeeded', (data) => {
console.log('Members online:', data.presence.count)
})
// Fires when a new member joins
room.bind('relay:member_added', (member) => {
console.log(`${member.info.name} joined`)
})
// Fires when a member leaves
room.bind('relay:member_removed', (member) => {
console.log(`${member.info.name} left`)
})
Your auth endpoint must return channel_data containing the user's ID and info for presence channels. All server SDKs handle this automatically.
Common Issues
1. BROADCAST_CONNECTION vs BROADCAST_DRIVER
Laravel 11+ renamed the environment variable from BROADCAST_DRIVER to BROADCAST_CONNECTION. Make sure you set the correct one in your .env:
# Laravel 11+
BROADCAST_CONNECTION=relay
# Laravel 10 and below
BROADCAST_DRIVER=relay
2. CSRF Exemption for /broadcasting/auth
The /broadcasting/auth endpoint must be excluded from CSRF verification. Without this, private and presence channel authentication will fail with a 419 status code.
Laravel 11+ — in bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'broadcasting/auth',
]);
})
Laravel 10 and below — in app/Http/Middleware/VerifyCsrfToken.php:
protected $except = [
'broadcasting/auth',
];
3. Event Name Prefixes
The Relay JS client uses relay: prefixed internal events (e.g. relay:subscription_succeeded, relay:member_added). If you are migrating from Pusher, note that the client automatically handles both relay: and pusher: prefixed events, so no changes are needed in your event listeners.
When binding to channel events in your frontend code, use the relay: prefix:
channel.bind('relay:subscription_succeeded', (data) => { /* ... */ })
channel.bind('relay:member_added', (member) => { /* ... */ })
channel.bind('relay:member_removed', (member) => { /* ... */ })