Appearance
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 } | nullWith 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:
| Policy | The room is recorded |
|---|---|
off | Never. |
on_demand | When your backend starts a recording. |
always | From 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.
Consent
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 includedEach 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.