Recipes← all recipesView on GitHub

Add a group chat to a video room

Videoin-room text chat

Let everyone in a video room send text beside the video. The room owns one chat thread that outlives the call, and the browser reads and writes it with a token your server mints.

Also called video room chat, in-meeting chat, in-call messaging

browser-sdkchatcall-fabric

The claim

In a room call the Browser SDK v4 exposes the room as call.address. Text sent to that address reaches everyone in the room’s conversation. The room keeps one thread across sessions, per the Messaging and chat guide. A group chat is not a second service with a second token. It is the room’s own conversation, read and written by the client that already carries the video.

Why it holds

Two pieces. A Flask route mints a Subscriber Access Token per user with POST /api/fabric/subscribers/tokens. Each message carries a fromAddress$, the sender’s address, so the token decides who a message is from. The page dials the room with audio and video, subscribes to call.address$, reads textMessages$ and posts with sendText().

How it works

Server (python/app.py):

client.fabric.tokens.create_subscriber_token(reference=user_id, display_name="Dana")

Browser (typescript/index.ts):

const call = await client.dial("/public/team-standup", { audio: true, video: true });
call.address$.subscribe((address) => {
  address?.textMessages$.subscribe((thread) => {
    thread?.values$.subscribe(render);        // the room's thread
    thread?.hasMore$.subscribe(...);           // older pages, via loadMore()
  });
  send.onclick = () => address?.sendText(input.value);
});

textMessages$ emits a collection: values$ is the messages, hasMore$ says whether older pages exist and loadMore() fetches one. The guide’s example uses one Subscriber Access Token per person. It notes that one token in two tabs logs stale-event errors, so the server mints one per reference.

Limitations

The Browser SDK this uses is a release candidate, 4.0.0-rc.2. sendText() resolves when the platform accepts the message; there is no delivered or read signal, so that state is yours to keep if you need it. The guide documents the thread with Subscriber Access Tokens. Whether a Guest token can post to it is not documented, so this recipe does not claim it. A private message between two participants goes to that participant’s own address, which the page does not show. The verifier proves the token request and the page’s use of the documented members; what the thread does on a live call is live behaviour.

What to change first

Subscribe to each message’s fromAddress$ and render its displayName beside the text, so the log shows who typed. Then give the token an expire_at a few minutes out and let the page refresh it, which is call-from-a-browser’s job.