---
title: "Send your first realtime event"
description: "Create a Realtime app, subscribe a web, iOS, or Android client to a channel, and publish a server event that the client receives over WebSockets."
canonical: "https://bird.com/docs/get-started/send-your-first-realtime-event"
---

# Send your first realtime event

Realtime delivers events over WebSockets. Your server publishes to a channel, and each connected client subscribed to that channel receives the event. This guide follows one path: create an app, subscribe a client, and publish from your server.

The free plan covers 100 concurrent connections and 200,000 messages per day, across all of a workspace's apps. Paid plans start at $25 per month; see [Realtime pricing](/products/realtime).

## 1. Create an app

An app is an isolated environment with its own credentials and channels. You choose its region when you create it, and you cannot change that region later.

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. Clients 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 a client

Choose from three clients, one per platform, all speaking the same protocol: [`@messagebird/realtime`](/docs/guides/realtime/overview) for the browser, [`BirdRealtime`](/docs/sdks/swift) for Apple platforms, and [`com.messagebird:bird-realtime`](/docs/sdks/kotlin) for Android and the server JVM.

**TypeScript**

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

Examples: [TypeScript](/docs/get-started/send-your-first-realtime-event.ts.md) · [Swift](/docs/get-started/send-your-first-realtime-event.swift.md) · [Kotlin](/docs/get-started/send-your-first-realtime-event.kotlin.md)

The client identifies the app by its key and picks the edge from the region, so you do not configure a host:

**TypeScript**

```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);
});
```

Examples: [TypeScript](/docs/get-started/send-your-first-realtime-event.ts.md) · [Swift](/docs/get-started/send-your-first-realtime-event.swift.md) · [Kotlin](/docs/get-started/send-your-first-realtime-event.kotlin.md)

All three clients open the socket as they are constructed, so you can subscribe without a separate connection call. Subscribing before the socket is up is fine too: channels are registered locally and sent as soon as the connection is established, and again after every reconnect.

`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 a client, because that would mean shipping the secret.

**TypeScript**

```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" },
});
```

Examples: [TypeScript](/docs/get-started/send-your-first-realtime-event.ts.md) · [Python](/docs/get-started/send-your-first-realtime-event.py.md) · [Go](/docs/get-started/send-your-first-realtime-event.go.md) · [PHP](/docs/get-started/send-your-first-realtime-event.php.md) · [cURL](/docs/get-started/send-your-first-realtime-event.curl.md)

After the edge delivers the event, the subscribed client prints `order changed { id: 42, status: 'shipped' }`. If nothing arrives, check that the client key and server credentials belong to the same app and that the channel names match exactly. One publish can name up to 100 channels. To send up to 10 different events in one request, [publish a batch](/docs/api/reference/publish-realtime-app-batch).

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 peak and average concurrent connections and messages, per app or across the workspace. The charts report daily usage points, so use the client output from step 3 to confirm the event as it arrives.

## 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.

## Related resources

- [Realtime](/realtime-api) (product)
- [Build your first integration](/learn/paths/integration) (course)

[Get an implementation brief](/learn/workspace?topic=realtime)
