BIRD Realtime

Realtime API for your apps. Subscribe, publish, scale.

Set up in:
Cursor

Live chat, presence, in-app notifications, and real-time dashboards, without running the WebSocket infrastructure yourself.

app.ts
connected
import { BirdRealtime } from "@messagebird/realtime";

const bird = new BirdRealtime({
  appKey: APP_KEY,
  region: "us1",
});

const channel = bird.subscribe("orders-42");

channel.bind("order-shipped", (data) => {
  render(data);
});
Order BRD-49217Placed
ETAThursday, May 22

5 minutes from npm install to first event

Publish your first event from the language you already use.

Server SDKs for Node, Python, and Go, a browser client for the subscribe side, and plain HTTP when you would rather not add a dependency. A channel needs no provisioning: it exists as soon as something subscribes to it.

1
2
3
4
5
6
const result = await bird.realtime.publish("rap_01krdgeqcxet5s7t44vh8rt9mg", {
  event: "order.updated",
  channels: ["orders", "presence-lobby"],
  data: { order_id: "ord_123", status: "shipped" },
});
console.log(result.data?.length); // one entry per channel

What you can build with Realtime

Bring live updates to every corner of your product, from chat and dashboards to tracking and games, all through one simple API.

  1. 01

    Live scores and results

    Match updates, poll results, election nights: one publish call fans the new number out to every subscribed screen at once.

  2. 02

    In-app chat

    A channel per room, presence for who's online, and client events for typing indicators, with no server round-trip.

  3. 03

    Online collaboration

    Client events fan cursor positions, selections, and co-editing signals between peers through the channel, no backend hop in the loop.

  4. 04

    Multiplayer games

    Presence fills the lobby, client events carry the moves, and a channel per match keeps the state in front of every player.

  5. 05

    Live charts and dashboards

    Publish metrics as they change. A cache channel hands the current value to every late joiner, so charts never render empty.

  6. 06

    Presence indicators

    Presence channels track members as they join and leave; webhooks keep your backend's roster in sync.

  7. 07

    Live location tracking

    A courier on the customer's map, friends sharing a route, a fleet on the dispatch screen: publish coordinates and every watcher follows, with the last known position cached for late joiners.

  8. 08

    Order and delivery status

    A cache channel per order holds the current status, so the subscription doubles as the initial state fetch.

  9. 09

    Auctions and bidding

    Every bid lands on every bidder's screen together, and a cache channel hands the current high bid to anyone who joins mid-auction.

  10. 10

    Per-user notification feeds

    One private channel per user, subscriptions signed by your backend, so only the right client can listen.

Why Realtime

Live UX is the part that breaks first when you scale. We've been running it for over a decade.

Connection state, presence, fan-out, reconnection backoff, and the capacity to absorb a traffic spike are the parts of a live feature that are easy to prototype and hard to operate. Realtime runs them as a managed service inside the Bird API, so a live channel shares the auth, observability, and webhooks you already use for email and SMS.

presence.ts
18 members
const room = bird.subscribe("presence-room-42");

room.bind("bird:subscription_succeeded", () => {
  const members = [...room.members.values()];
  render({ me: room.myId, members });
});

room.bind("bird:member_added", (member) => {
  addToRoster(member.member_id);
});

room.bind("bird:member_removed", (member) => {
  removeFromRoster(member.member_id);
});

Every state change is a webhook.

Clients come and go without ever touching your backend. These are how it finds out: start the expensive job when the first subscriber arrives, stop it when the last one leaves, and keep your own view of who is in a room.

POST /webhooks/bird
signed
{
  "type": "realtime.member_added",
  "timestamp": "2026-05-19T15:42:01.221Z",
  "data": {
    "channel": "presence-room-42",
    "member_id": "usr_4hQ2m"
  }
}
  • realtime.channel_occupiedFirst subscriber joined a previously empty channel.
  • realtime.channel_vacatedThe last subscriber left; the channel is now empty.
  • realtime.member_addedA member joined a presence channel.
  • realtime.member_removedA member left a presence channel.
  • realtime.connection_countA channel's connection count changed.

If you've integrated email, you've integrated Realtime.

Same auth, same idempotency contract, same error envelope, same webhook shape. The difference is the transport: a long-lived WebSocket connection instead of a one-shot REST send.

Realtime.

realtime
await bird.realtime.members.send(APP_ID, "usr_4hQ2m", {
  event: "order-shipped",
  data:  { status: "shipped" },
});

Reaches the person wherever they are connected, every tab and device at once. No channel to name, no connection to track.

SMS.

sms
await bird.sms.send({
  from:     "Bird",
  to:       "+15005550006",
  text:     `Your order has shipped.`,
  category: "transactional",
});

The same call, one channel over. For when the update needs to land on a phone instead of a connected client.

Start with one channel.
Add the others when you're ready.

A test API key is yours immediately. Production unlocks when you add a payment method and verify a sender.

Using Claude Code, Cursor, or Codex? Copy a setup prompt and your agent installs the Bird CLI and skills for you. Pick yours:

Cursor