Channels
A channel is a name browsers listen to. Your server publishes to it, and browsers on private and presence channels can send each other events too.
Names and kinds
Up to 200 characters of A-Z a-z 0-9 _ - = @ , . ;. The start of the name says its kind, as Pusher's do:
| Kind | Starts with | Who may listen | Sealed |
|---|---|---|---|
| Public | anything else | anyone with your app's key | no: anything there is public |
| Private | private- | whoever your server lets in | yes, with the channel's key |
| Presence | presence- | whoever your server lets in, listed to everyone on it | yes, with the channel's key |
A channel lives within your app: another app's orders is another channel. private-encrypted-… isn't taken.
Owning a channel
Your server owns names by their start, and answers for each user who asks:
- Node
- PHP
- Python
realtime.channel( 'private-orders-', async ( user, channel ) => {
const order = await findOrder( channel.slice( 'private-orders-'.length ) );
return order !== null && order.userId === user;
} );
$realtime->channel( 'private-orders-', function ( $user, $channel ) {
$order = find_order( substr( $channel, strlen( 'private-orders-' ) ) );
return null !== $order && $order->user_id === $user;
} );
// Laravel: routes/channels.php, as for any broadcaster. PrivateChannel( 'orders.42' ) is private-orders.42 here.
Broadcast::channel( 'orders.{id}', fn ( User $user, string $id ) => $user->id === Order::find( $id )?->user_id );
def may_follow_order(user, channel):
order = find_order(channel[len("private-orders-"):])
return order is not None and order.user_id == user
realtime.channel("private-orders-", may_follow_order)
useris the asking user's id, ornull(None) for nobody.- Answer
false(ornull) for no,truefor yes, or for presence{ id, info }(presence). - In Node the callback may be async. In Python it is a plain function, which may query your database the usual way.
- The longest prefix that fits decides. A private or presence channel nobody owns is refused (
forbidden). - The browser asks for every channel it subscribes to in the same moment in one request, and keeps the token across reconnects and moves: your callback runs when a page first subscribes and when its token is renewed (6 hours by default).
Listening
const orders = rt.subscribe( 'private-orders-42' );
orders.on( 'updated', ( data ) => refresh( data ) );
orders.on( 'realtime:subscribed', () => console.log( 'listening' ) );
orders.on( 'realtime:error', ( e ) => console.warn( e.code ) ); // forbidden, expired, auth_failed …
rt.unsubscribe( 'private-orders-42' );
subscribe()gives the same subscription for the same name.- Every tab of the browser rides one connection, each with its own subscriptions.
- Events reach a listener opened: you never handle sealed values.
- The page's own events are named
realtime:…, which nobody can publish.
Publishing
- Node
- PHP
- Python
await realtime.publish( 'private-orders-42', 'updated', { status: 'paid' } );
await realtime.publish( [ 'private-orders-42', 'orders' ], 'updated', { id: 42 } );
await realtime.publish( 'presence-room-7', 'message', { text }, { except: tab } ); // not back to the tab that sent it
$realtime->publish( 'private-orders-42', 'updated', [ 'status' => 'paid' ] );
$realtime->publish( [ 'private-orders-42', 'orders' ], 'updated', [ 'id' => 42 ] );
$realtime->publish( 'presence-room-7', 'message', [ 'text' => $text ], [ 'except' => $tab ] ); // not back to the tab that sent it
realtime.publish("private-orders-42", "updated", {"status": "paid"})
realtime.publish(["private-orders-42", "orders"], "updated", {"id": 42})
realtime.publish("presence-room-7", "message", {"text": text}, except_tab=tab) # not back to the tab that sent it
More in publishing.
Client events
Browsers on a private or presence channel can send each other events named client-…, sealed like the rest:
const room = rt.subscribe( 'presence-room-7' );
await room.trigger( 'client-typing', { on: true } );
room.on( 'client-typing', ( data, { user_id } ) => showTyping( user_id, data.on ) );
A tab doesn't hear its own. At most 10 a second a browser, 10 KB each. They don't go through your server: check anything that matters on your server instead.