Skip to Content
Client SDKChannels

Client: Channels

Subscribe to real-time messages published by the server to named channels. Supports optional history on initial join.

Subscribing to a channel

const { , } = await .( "news:global", () => { .("Live message:", ); } ); if (!) { .("Subscription failed (guarded?)"); }

The first argument is the channel name. The second is a callback for incoming messages.

With message history

You can optionally request recent messages when subscribing:

const { , } = await .( "events:dashboard", () => { .("Live update:", ); }, { : 5 } ); .(() => { const = .(); renderHistoricalEvent(); });
💡

History is only available if the server explicitly stores it: writeChannel(, , historyLimit).

With message history since a specific point

If persistence is enabled for a channel, you can request messages since a specific timestamp or message ID:

// Get messages since a specific timestamp (milliseconds since epoch) const { , } = await .( "events:dashboard", () => { .("Live update:", ); }, { : 100, : 1682450400000, } ); // Or get messages since a specific message ID const { , } = await .( "events:dashboard", () => { .("Live update:", ); }, { : 100, : "message-id-123", } );

The since parameter requires persistence to be enabled for the channel on the server using enableChannelPersistence().

Retrieving channel history without subscribing

You can retrieve historical messages from a channel without subscribing to it:

// Get the most recent messages const { , } = await .( "events:dashboard", { : 50, } ); // Get messages since a specific timestamp const { , } = await .( "events:dashboard", { : 50, : 1682450400000, } ); // Get messages since a specific message ID const { , } = await .( "events:dashboard", { : 50, : "message-id-123", } ); // Process the historical messages .(() => { const = .(); renderHistoricalEvent(); });

Unsubscribing

To stop receiving updates:

await .("news:global");

Message format

Channel messages are always sent as raw strings.

If your server publishes structured data (e.g. JSON.stringify(...)), you must parse it yourself:

.("alerts", () => { try { const = .(); switch (.type) { case "alert": showAlert(.message); break; case "announcement": renderBanner(.content); break; default: .("Unknown message type:", ); } } catch () { .("Failed to parse channel message:", ); } });

Use cases

  • Notifications
    • Alerts, banners, user-specific pushes
  • Live dashboards
    • Server stats, performance metrics, monitoring feeds
  • Broadcasting
    • Build logs, event updates, task progress
  • Chat applications
    • Message history, pagination, catching up on missed messages
  • Activity feeds
    • Loading historical activities and receiving real-time updates

For presence indicators, typing status, and ephemeral per-user state, use presence instead.

Best practices

  • Unsubscribe when done
    • Frees resources and avoids duplicate subscriptions
  • Parse carefully
    • Messages are strings: use try/catch when parsing JSON
  • Resubscribe on reconnect
    • Keep a list of active channels and restore them after connection loss
  • Use pagination for large history
    • For channels with extensive history, use getChannelHistory with the since parameter to implement pagination
  • Consider timestamp format
    • When using since with a timestamp, use milliseconds since epoch (e.g., Date.now())
  • Error handling
    • Always check the success flag when retrieving history, as persistence might not be enabled for all channels
Last updated on
© 2025