# Send your first realtime event

Realtime delivers events over WebSockets. Your server publishes to a channel, and every client subscribed to that channel receives it in milliseconds. This page takes you from zero to a live event in three steps: create an app, subscribe from a page, publish from your server.

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.

## 1. Create an app

An app is an isolated environment with its own credentials and channels, pinned to the region closest to your users. The region is fixed once the app exists.

1. Open [**Realtime → Apps**](https://bird.com/dashboard/w/realtime/apps) in the dashboard.
2. Select **Create app**.
3. Enter a name in **Name**.
4. Select a **Region**: **United States (us1)** or **Europe (eu1)**.
5. Select **Create app**.

**Save your app credentials** then shows three values, once:

- **App ID** is a `rap_…` id that identifies the app in Bird API calls.
- **Key** is public. Browsers connect with it, and it is safe to ship in client code.
- **Secret** pairs with the key to authenticate server-side calls and to sign channel authorization. Treat it like a password.

Copy all three before selecting **I've saved my secret**, because the secret is not shown again. Then create a Bird API key with the `realtime` scope on the [**Developers → API keys**](https://bird.com/dashboard/w/api-keys) page, and export what the next steps need:

```bash
export BIRD_API_KEY="bk_us1_..."
export BIRD_REALTIME_KEY="your-app-key"
export BIRD_REALTIME_SECRET="your-app-secret"
```

## 2. Subscribe from the browser

Install the browser client:

```bash
npm install @messagebird/realtime
```

The client identifies the app by its key and picks the edge from the region, so there is no host to configure:

```typescript
import { BirdRealtime } from "@messagebird/realtime";

const bird = new BirdRealtime({
  appKey: "your-app-key",
  region: "us1",
});

const orders = bird.subscribe("orders");
orders.bind("order-updated", (data) => {
  console.log("order changed", data);
});
```

`orders` is a public channel, so any client with the app key can subscribe. Channels named `private-…` or `presence-…` require your server to authorize each subscription. See [Authorizing channels](/docs/guides/realtime/authorizing-channels).

Channels are not created or configured anywhere. A channel exists while at least one connection is subscribed to it, and disappears when the last one leaves.

## 3. Publish from your server

Publishing is a server-side call. It authenticates with your Bird API key and carries the app's key and secret so the edge accepts it. Never publish from the browser, because that would mean shipping the secret.

```typescript
import { BirdClient } from "@messagebird/sdk";

const bird = new BirdClient({
  apiKey: process.env.BIRD_API_KEY,
  realtime: {
    key: process.env.BIRD_REALTIME_KEY,
    secret: process.env.BIRD_REALTIME_SECRET,
  },
});

await bird.realtime.publish("rap_01krdgeqcxet5s7t44vh8rt9mg", {
  event: "order-updated",
  channels: ["orders"],
  data: { id: 42, status: "shipped" },
});
```

The same call with curl:

```bash
curl -X POST https://us1.platform.bird.com/v1/realtime/apps/rap_01krdgeqcxet5s7t44vh8rt9mg/events \
  -H "Authorization: Bearer $BIRD_API_KEY" \
  -H "X-Realtime-Key: $BIRD_REALTIME_KEY" \
  -H "X-Realtime-Secret: $BIRD_REALTIME_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "order-updated",
    "channels": ["orders"],
    "data": { "id": 42, "status": "shipped" }
  }'
```

The browser console logs `order changed { id: 42, status: 'shipped' }` as the call returns. If nothing arrives, check that the app key in the client and the credentials on the server belong to the same app, and that the channel name matches exactly. One publish can name up to 100 channels, which broadcasts the same event to all of them; [publish a batch](/docs/api/reference/publish-realtime-app-batch) sends up to 10 different events in one request.

Publishing resolves once the edge accepts the event. Delivery to connected clients is asynchronous, so a `200` means accepted rather than received.

## 4. See it in the dashboard

[**Realtime → Metrics**](https://bird.com/dashboard/w/realtime/metrics) shows max and average concurrent connections and messages per day, per app or across the workspace. Usage is aggregated in one-minute buckets, so a single test event appears a few minutes after you publish it.

## Next steps

- [Authorizing channels](/docs/guides/realtime/authorizing-channels) covers private and presence channels, and the signature your backend returns.
- [Publish an event](/docs/api/reference/publish-realtime-app-event) has the full request and response, including per-channel state at publish time.
- [Webhooks & events](/docs/guides/webhooks) explains how to receive `realtime.*` events, such as a channel becoming occupied or a member joining, on your own endpoint.