Channels
Subscribe, publish, replay with rewind, and what happens to a publish made while the connection is down.
Getting a channel
const channel = realtime.channels.get('chat:lobby');Local and free — it returns a handle and touches no network. The wire work
happens on the first subscribe or publish.
Call it before you connect if you need listeners ready for early messages.
The client dispatches an incoming Message frame by looking the channel up in
its own map; a frame for a channel it has never been asked about is dropped,
because there is nothing to hand it to.
Subscribing
channel.subscribe(message => {
console.log(message.name, message.data);
});A message carries channel, an optional name, optional JSON data, the
connectionId that published it and a timestamp.
Filtering by name
channel.subscribe('order.created', message => {
console.log(message.data);
});This filter is client-side. The server delivers every message on the channel and the SDK discards what does not match — it saves you a branch, not bandwidth.
Both forms can coexist; each subscribe call adds a listener.
Publishing
await channel.publish('order.created', { id: 7 });
await channel.publish({ name: 'order.created', data: { id: 7 } });The promise resolves when the server Acks the frame, and rejects on a Nack or
after realtimeRequestTimeout (10s). Await it — it is the only signal that the
message was accepted rather than merely written into a socket.
publish never throws synchronously, even when the connection is not open. A
caller who wrote publish(...).catch(...) would not catch a synchronous throw,
and the failure would surface as an unhandled error somewhere else in their app.
Publishing while offline
By default a publish made while the connection is down is held and sent on reconnect:
new Blackevin.Realtime({
key,
queueMessages: true,
maxQueuedMessages: 100,
});The queue is in memory, so a closed tab loses it. This buys you a network blip, a laptop lid, a tunnel — not durability.
When the queue is full the oldest frame is dropped and its promise rejects with
queue full: oldest message dropped. A queue that grows without bound during a
long outage is a memory leak that ends as a tab crash, which loses strictly more
than dropping the oldest would.
close() and a failed connection both reject what is queued rather than holding
it forever. A connection that hit its ceiling is the exception — see
connection state.
Replaying with rewind
A late subscriber can be handed the last N persisted messages the moment it subscribes:
const channel = realtime.channels.get('chat:lobby', { params: { rewind: 20 } });
channel.subscribe(message => {
console.log(message.data);
});- The server caps
rewindat 100. - Rewound messages arrive as ordinary
Messageframes, oldest first, before any live one. Your callback cannot tell them apart, which is the point. - They go to that connection only. Nothing is re-published, re-persisted, or forwarded to integrations or cluster peers.
- The same
rewindis re-sent on reconnect, so a restored subscription catches up on what it missed while it was down.
rewind: '20' works too — Ably accepts the string form, so this does.
Wildcards
Channel matching on the server supports * for one segment and > for the rest
of the tree. Today the SDK subscribes with the exact channel name, so wildcards
reach you through capabilities — where
metrics.> grants a whole subtree — rather than through channels.get.
Naming
A channel name is any string. Two conventions are worth following:
- Separate scopes with
:—chat:lobby,orders:new. It reads well and it is what the capability examples use. - URL-encode it in REST calls. A channel is a path segment, so
:becomes%3A. The SDK does this for you; hand-writtencurldoes not.
Tenancy
With auth on, every channel name is scoped to the calling key's account before
it reaches a store. Two accounts publishing to chat:lobby are on two different
channels and cannot see each other, and there is no way to ask for another
account's channel — the scope comes from the credential, never from the request.