Skip to content

Recording a room ​

Talkline records a group room as one file per track: each recorded person's microphone, camera and screen, as they sent it, in WebM (Matroska for H.264), with a timeline that says where each file sits in time. Nothing is decoded or mixed on the way, so nothing is lost that could be wanted later.

Only a room in sfu mode can be recorded: in a one-to-one p2p call the media goes straight between the two people, and no server holds it.

Recording is the deployment's choice, and off unless its operator turns it on. On a deployment that does not record, every start is refused recording_unavailable, and a room whose policy is always is held but not recorded. Ask your operator before you rely on it.

Everyone is told ​

Every person in a recorded room is told the moment a recording starts, before anything of theirs is captured, and again when it stops. Your app must show it whenever a recording is active; this is not optional, and a person who is recorded without being told is a person your product deceived.

ts
client.on('recordingChanged', (recording) => {
  // recording.state: 'active' | 'stopped' | 'failed'
  showRecordingBanner(recording.state === 'active');
});
// On joining a room already being recorded, the same event, and:
client.room?.recording; // { sid, state, consentRequired, acknowledged } | null

With React, useRecording() gives the same and re-renders on every change.

Talkline records only people whose app can show this. The web SDK says so to the server on every connection; a client that does not — an older build, another SDK — is told nothing it can show and is never recorded, though others in the room are.

Decide when a room may be recorded ​

A room's recordingPolicy is fixed when it is created:

PolicyThe room is recorded
offNever.
on_demandWhen your backend starts a recording.
alwaysFrom the first person's arrival, and again if the room moves to another media server.

Set it per room, or once for your application in its settings (recordingPolicy); a room created without saying takes the application's, and a room made by a join always does.

ts
const room = await talkline.rooms.create({ name: 'consultation-4821', recordingPolicy: 'on_demand' });

Start and stop ​

Start once someone has joined, from your backend:

ts
const rec = await talkline.recordings.start(room.sid); // rec.sid — RC_…
// …
await talkline.recordings.stop(rec.sid);

Starting is refused conflict for a room whose policy is off, a p2p room, a room nobody has joined yet, or one already being recorded; quota_exhausted when your recordings have reached your maxRecordingGb; recording_unavailable when the deployment does not record rooms, or the recorder beside the room's media server is not running. A recording also stops when its room ends.

For a recording people must agree to, create the room with recordingRequiresConsent: true (or set it for your application). Everyone is still told; each person is recorded only once they have agreed, from that moment on:

ts
client.on('recordingChanged', async (recording) => {
  if (recording.state !== 'active' || !recording.consentRequired || recording.acknowledged) return;
  if (await askUser()) await client.room!.acknowledgeRecording();
});

The SDK never acknowledges on its own: an acknowledgement stands for a person's consent, so it is sent only when your app asks. It covers that person's other devices and a later return to the same room, for that recording only — a new recording asks again. Talkline keeps each acknowledgement, with who and when.

Get the files ​

When the files are uploaded you receive recording.finished — or recording.failed, when a recording stopped because its media server or its recorder went, with whatever it captured before (partial: true). Either carries the recording, with its files. Fetch them with signed URLs, which go straight to the object store:

ts
const { urls } = await talkline.recordings.urls(rec.sid); // [{ file, url }], timeline.jsonl included

Each URL works for five minutes unless you ask for longer (expiresInSec, up to a day), and anyone holding one can fetch the file until it expires.

Each file's offsetMs is when its first media arrived, counted from the recording's start; timeline.jsonl says when each person joined and left, muted and spoke. A file named TR_….webm and another TR_…-2.webm are one track whose stream was replaced mid-recording, as happens when a connection is rebuilt.

Retention ​

A recording's files are deleted 90 days after it ends, or after your application's recordingRetentionDays. The recording itself stays, with deletedAt saying when its files went.

Talkline documentation