Realtime overview
Realtime pushes events to connected clients over WebSockets. Your server publishes an event to a named channel, and every client subscribed to that channel receives it within milliseconds. Nothing polls, and no client asks for updates.
Use it when the browser has to learn something it did not ask for: an order changing status, a chat message arriving, a dashboard tile updating, a background job finishing.
Channels, members, and connections
Three words describe the model. They are not interchangeable.
A channel is a named room. It exists while at least one connection is subscribed to it and disappears when the last one leaves, so there is nothing to create, register, or clean up. Names allow letters, digits, and _ - = @ , . ; up to 164 characters.
A connection is one open WebSocket. It gets an id (26896.319537) when it connects, and that id is what authorization signs and what publishing can exclude.
A member is an authenticated identity present in a channel, and only presence channels have them. One member can hold several connections at once. Someone with your app open in three tabs is one member with three connections, and presence events fire once per member rather than once per connection.
The three channel types
The channel name decides how much protection it gets. There is nothing to configure per channel.
| Name | Who can subscribe | Has members |
|---|---|---|
| orders | anyone holding the app key | no |
| private-orders | only clients your backend signs for | no |
| presence-lobby | only clients your backend signs for | yes |
A public channel is readable by anyone who can load your page, because the app key ships in client code. Do not publish anything to a public channel that every visitor should not see. See Public channels.
A private channel asks your backend to approve each subscription. The client posts the connection id and channel name to an endpoint you own, your endpoint decides whether that user may subscribe, and it returns a signature computed with the app secret. See Private channels.
A presence channel does the same and additionally attaches an identity (member_id, plus optional member_info) to the subscriber, so every member can see who else is there and be notified as people come and go. See Presence channels.
Events the client receives
Application events are yours: you pick the name at publish time (order-updated, message.created) and bind a handler to it. Alongside those, the client re-emits lifecycle events under the bird: prefix, which you bind exactly like your own:
- bird:subscription_succeeded fires once per channel when the subscription is live. On a presence channel it carries the current member list, so you can render the room before anyone moves.
- bird:member_added and bird:member_removed fire on presence channels as members arrive and leave. member_added fires when a person's first connection subscribes; member_removed only when their last one goes. A second tab opening and closing produces neither.
- bird:connection_count reports how many connections are subscribed to the channel, if the app has connection counting enabled. It counts connections, so the three-tab member counts three.
- bird:subscription_error fires when a subscription is refused, most often because authorization failed.
Names beginning client- are reserved for events clients send directly to each other, which is a separate app setting and only allowed on private and presence channels.
Your server can also receive events, as webhooks, when a channel becomes occupied or vacated and when members join or leave. Those arrive as realtime.* events through the same webhook endpoints as the rest of Bird.
Apps, keys, and regions
An app is an isolated environment with its own credentials and its own channel namespace. Two apps never see each other's channels, which is what makes an app the right boundary between your staging and production environments.
Each app is pinned to a region, us1 or eu1, chosen at creation and fixed afterwards. Pick the one closest to your users: the region decides which edge their WebSockets terminate on.
Every app carries three values, and it is worth keeping them straight because they are used in different places:
- The app id (rap_…) identifies the app in Bird API calls, and is the value in every /v1/realtime/apps/… path.
- The key is public. Browsers connect with it, and it is safe to ship in client code.
- The secret pairs with the key to authenticate server-side calls and to sign channel authorization. It is shown once, at creation. Anyone holding it can publish to your app and forge presence identities.
Manage all of this on the Realtime → Apps page, which is also where you rotate keys: add a second key, roll it out, then revoke the old one.
Visibility
The Realtime → Metrics page reports three numbers per app, or across the workspace, over a window you choose. The definitions matter, because two of them are not what a first reading suggests:
- Max connections is the highest number of connections open at the same moment inside the window. It is a peak, not a total, and it is the number the connection limit applies to.
- Average connections is the mean of the daily peaks, not the mean of every sample. A workspace that spikes each afternoon and idles overnight shows an average well above its quiet hours.
- Messages counts event deliveries, one per channel: a publish naming 50 channels counts as 50. It also includes the events the protocol sends on your behalf, so presence joins and connection-count updates land in the same number, which is why it can run ahead of the publishes your code made.
Usage is aggregated in one-minute buckets, so numbers appear a few minutes behind live traffic. There is no public usage API yet. If you need usage in your own systems, count publishes as you make them, or derive activity from realtime.* webhooks.
Limits during the preview
Realtime is free to use during the preview. Each workspace is limited to 100 concurrent connections and 200,000 messages per day, across all of its apps. Creating more apps does not raise the ceiling, because it applies to the workspace.
Per-request caps apply regardless of the preview: one publish names at most 100 channels, a batch carries at most 10 events, and an event payload is capped at 10 KB serialized.
Next steps
- Send your first realtime event walks the whole loop end to end.
- Publishing events covers publishing from your server, batching, and excluding the originating client.
- Authorizing channels is the contract your backend implements for private and presence channels.