Transport Protocols

Relay supports multiple transport protocols beyond WebSockets. Choose the right one for your use case.


WebSockets (Default)

Full-duplex bidirectional communication. Best for interactive real-time apps.

  • Bidirectional: client and server can send messages anytime
  • Lowest latency
  • Persistent connection
  • Uses pusher-js or any Pusher-compatible client
const pusher = new Pusher('your-key', {
    wsHost: 'relay.example.com',
    wsPort: 6001,
    cluster: 'mt1',
});

Best for: Chat, collaboration, gaming, live dashboards


Server-Sent Events (SSE)

Server-to-client only streaming over HTTP. Simpler than WebSockets, with automatic reconnection built into the browser.

  • One-way: server pushes events to the client
  • Automatic reconnection with Last-Event-ID
  • Works through proxies and firewalls that block WebSockets
  • Native browser support via EventSource

Connecting

const source = new EventSource(
    '/api/v1/apps/YOUR_APP_ID/sse?channels=notifications,alerts',
    { headers: { 'Authorization': 'Bearer rly_your_token' } }
);

source.addEventListener('connected', (e) => {
    console.log('Connected:', JSON.parse(e.data));
});

source.addEventListener('new-message', (e) => {
    const data = JSON.parse(e.data);
    console.log('Channel:', data.channel, 'Data:', data.data);
});

source.onerror = () => {
    console.log('Connection lost — reconnecting automatically...');
};

Query Parameters

Param Description
channels Comma-separated channel names (required)
last_event_id Resume from this event ID

Headers

The server sends Last-Event-ID with each event. On reconnection, the browser automatically sends this header so you don't miss events.

Best for: Live feeds, notifications, log streaming, AI token streaming, stock tickers


Long Polling

Client sends a request; server holds it open until events arrive or a timeout expires. Simulates real-time with standard HTTP.

  • Works everywhere (no WebSocket or SSE support needed)
  • Higher latency than WebSockets/SSE
  • Each "connection" is a series of HTTP requests

Usage

async function longPoll(lastEventId = null) {
    const params = new URLSearchParams({
        channels: 'my-channel',
        timeout: 25,
    });
    if (lastEventId) params.set('last_event_id', lastEventId);

    const res = await fetch(
        `/api/v1/apps/YOUR_APP_ID/poll?${params}`,
        { headers: { 'Authorization': 'Bearer rly_your_token' } }
    );

    const { events, last_event_id } = await res.json();

    for (const event of events) {
        console.log('Received:', event.channel, event.event, event.data);
    }

    // Immediately reconnect for next batch
    longPoll(last_event_id);
}

longPoll();

Query Parameters

Param Description
channels Comma-separated channel names (required)
since ISO 8601 timestamp to fetch events from
last_event_id Resume from this event ID
timeout Max hold time in seconds (default 25, max 30)

Best for: Environments where WebSockets and SSE are blocked, legacy browser support


HTTP Polling

Simplest option. Client polls on a regular interval.

Usage

setInterval(async () => {
    const res = await fetch(
        `/api/v1/apps/YOUR_APP_ID/events/poll?channels=my-channel&since=${lastCheck}`,
        { headers: { 'Authorization': 'Bearer rly_your_token' } }
    );
    const { events, timestamp } = await res.json();
    lastCheck = timestamp;

    for (const event of events) {
        console.log(event);
    }
}, 3000); // Poll every 3 seconds

Query Parameters

Param Description
channels Comma-separated channel names (required)
since ISO 8601 timestamp
last_event_id Resume from this event ID
limit Max events per response (default 50, max 200)

The response includes a next_poll_url for convenience.

Best for: Infrequent updates, dashboards that refresh every few seconds, simple integrations


Choosing a Transport

Transport Direction Latency Complexity Browser Support
WebSocket Bidirectional ~1ms Medium Modern browsers
SSE Server → Client ~50ms Low All browsers
Long Poll Server → Client ~100ms Low Everything
HTTP Poll Server → Client Interval-based Minimal Everything

Decision Guide

  • Need bidirectional? → WebSocket
  • Server-to-client only, need low latency? → SSE
  • WebSocket/SSE blocked? → Long Polling
  • Updates every few seconds is fine? → HTTP Polling
  • AI streaming / token-by-token? → SSE

All transports use the same authentication (Bearer token, Key+Secret headers, or HMAC).