many-forest-60185
12/22/2025, 4:34 AMtall-airline-16756
12/22/2025, 4:34 AMtall-airline-16756
12/22/2025, 4:34 AMroomRecord permission when starting egress.
How to connect each storage type
• S3-compatible:
◦ Provide access_key, secret, region, and bucket. For non-AWS endpoints include endpoint.
◦ For some providers (MinIO, R2) set force_path_style: true.
◦ Example snippet:
"s3": {
"access_key": "your-access-key",
"secret": "your-secret",
"region": "us-west-2",
"bucket": "your-bucket",
"force_path_style": true
}
• Google Cloud Storage:
◦ Provide the service account JSON in credentials (account needs Storage Object Creator) and bucket.
◦ Example:
"gcp": {
"credentials": "{...service account JSON...}",
"bucket": "your-gcp-bucket"
}
• Azure Blob Storage:
◦ Provide account_name, account_key, and container_name.
◦ Example:
"azure": {
"account_name": "your-account",
"account_key": "your-key",
"container_name": "your-container"
}
How to start egress
• Use one of:
◦ LiveKit CLI (example below)
◦ SDKs (Go, JS, Python, Ruby, Java)
◦ Direct HTTP/Twirp API calls
• CLI example to start a room composite recording to S3:
a. Create a JSON egress request with type: "room-composite", room_name, and file output configured with your S3 object and credentials.
b. Run:
lk egress start --file request.json
(You can also call the Egress API directly with an authenticated request; ensure token includes roomRecord.)
Key features and tips
• AutoEgress: optionally start recordings automatically when rooms are created.
• You can update streams (add/remove RTMP) during an active egress session.
• Use HLS output for adaptive streaming; use MP4/WebM for single-file archives.
• For raw audio processing, use WebSocket track egress (sends PCM frames).
Links for implementation details
• Egress overview and types: https://docs.livekit.io/home/egress/overview/
• Egress outputs (file, HLS, RTMP, WebSocket): https://docs.livekit.io/home/egress/outputs/
• Egress API reference: https://docs.livekit.io/home/egress/api/
• AutoEgress: https://docs.livekit.io/home/egress/autoegress/
Next step — what I need from you
• Which egress type do you want (room composite, participant, track, or web)?
• Which storage provider are you using (AWS S3 / S3-compatible, GCP, or Azure)?
• Do you want a one-off manual start or AutoEgress (automatic recording when rooms start)?
Tell me those three items and I’ll give a ready-to-run example request (CLI/JSON or SDK code) tailored to your setup.
Sources: Recording and export | LiveKit docs | Track egress | LiveKit docs | Egress output types | LiveKit docs | Egress API | LiveKit docs | Auto egress | LiveKit docsmany-forest-60185
12/22/2025, 4:37 AMtall-airline-16756
12/22/2025, 4:37 AMroomRecord permission.
• The egress request must include valid storage credentials (S3/GCP/Azure) or a stream URL so LiveKit can write to your destination.
Operational notes
• No server configuration on LiveKit Cloud is required — just send the egress request and credentials.
• For compliance/security, use least‑privilege credentials (e.g., bucket write permissions only).
• Use AutoEgress if you want recordings to start automatically; otherwise start egress programmatically when needed.
If you’d like, I can next:
• Show a minimal example egress request for your storage provider, or
• Explain how AutoEgress is enabled and what the Console shows when an egress job runs.
Which would you prefer next?many-forest-60185
12/22/2025, 4:41 AMtall-airline-16756
12/22/2025, 4:41 AMegress object). This ensures recording starts as soon as the room exists.
2. Use room (composite) egress for full-session archive + monitoring, or tracks if you need per-participant raw files.
3. Provide storage credentials (S3/GCP/Azure) in the egress payload so LiveKit can upload recordings.
4. Ensure the token used to create rooms has both roomCreate and roomRecord permissions.
5. Test with a sample room, then roll out for production.
Concrete next steps for you
1. Decide output type: single MP4 (composite) for archive and checks, or HLS if you need live monitoring during sessions.
2. Pick storage provider and prepare least-privilege credentials:
◦ S3: access_key, secret, bucket, region, (optional endpoint, force_path_style)
◦ GCP: service account JSON with Storage Object Creator
◦ Azure: account_name, account_key, container_name
1. Add egress to your CreateRoom request. Example pattern (composite → S3):
{
"name": "room-name",
"egress": {
"room": {
"file": {
"filepath": "recordings/{room_name}-{time}.mp4",
"s3": {
"access_key": "...",
"secret": "...",
"bucket": "my-bucket",
"region": "us-west-2"
}
}
}
}
}
1. Ensure your CreateRoom JWT grants roomCreate and roomRecord.
2. Test:
◦ Create a room (or have a participant join).
◦ Verify egress job appears/activates in the Console or via ListEgress.
◦ Confirm the file lands in your bucket.
1. Iterate: tweak layout, filename patterns, retention in your storage, and monitoring alerts.
Operational tips
• If you need recordings to start immediately without waiting for CreateRoom to finish, you can start egress directly; LiveKit will handle room creation if needed.
• Use AutoEgress for consistent, automated behavior; use separate manual egress calls only for ad‑hoc jobs.
• Monitor egress status in the Console and via the Egress API for failures or retries.
• Use least‑privilege credentials for uploads.
Would you like:
• A ready-to-run CreateRoom JSON tailored to your storage provider (S3/GCP/Azure), or
• A short SDK example (Node/Go/Python) to create rooms with AutoEgress?
Tell me which provider and which code language and I’ll generate the exact payload or snippet.
Sources: Auto egress | LiveKit docs | Recording and export | LiveKit docs | Egress API | LiveKit docs | Self-hosting the Egress Service | LiveKit docs | CreateRoom() is Taking Too Longmany-forest-60185
12/22/2025, 4:45 AMtall-airline-16756
12/22/2025, 4:46 AMegress object on the CreateRoom call so the room starts recording automatically when created.
Below is a minimal Python example using the LiveKit Python SDK style (construct the request payload JSON and call CreateRoom). Replace the auth and storage fields with your values.
import json
from livekit import RoomServiceClient # example import; use your SDK client
from google.auth import jwt as google_jwt # only if needed for auth
# Example: composite room recording to S3
create_room_payload = {
"name": "my-room",
"egress": {
"room": {
"file": {
"filepath": "recordings/{room_name}-{time}.mp4",
"s3": {
"access_key": "YOUR_ACCESS_KEY",
"secret": "YOUR_SECRET",
"bucket": "your-bucket",
"region": "us-west-2",
"force_path_style": True # set for non-AWS S3-compatible providers
}
}
}
}
}
# Create a client (instantiate with your LiveKit Cloud host and API key/secret or token)
client = RoomServiceClient("<https://cloud.livekit.io>", api_key="API_KEY", api_secret="API_SECRET")
# Call CreateRoom (method name may vary by SDK; pass the payload or mapped fields)
response = client.create_room(create_room_payload) # or client.create_room(**create_room_payload)
print("CreateRoom response:", response)
Notes:
• The egress object in the payload defines what to record (room, tracks, web) and the output destination (S3/GCP/Azure/RTMP).
• Ensure the token or credentials used have roomCreate and roomRecord permissions.
• For GCP, include service account JSON under gcp.credentials and `bucket`; for Azure, use azure.account_name, account_key, and container_name instead of s3.
• You can also start AutoEgress by adding similar egress fields when your app programmatically creates rooms on participant join.
Would you like a tailored snippet for GCP or Azure, or the exact call signature for the Python SDK you’re using?many-forest-60185
12/22/2025, 4:51 AMtall-airline-16756
12/22/2025, 4:51 AMegress settings before or immediately when the first participant joins. Implicit room creation by the client does not include egress parameters unless you create the room yourself or start egress afterward.
Options (pick one)
1) Pre-create the room from your backend (recommended)
• Your backend calls CreateRoom (include the egress object) before issuing the join token to the iOS client.
• The iOS client receives the token and joins the already-created room; AutoEgress starts automatically.
• Where to do it: your backend service that issues tokens (same place that should call CreateRoom).
2) Start egress immediately after room creation (server-side reactive)
• Detect room creation via your backend (e.g., webhook, room lifecycle event, or when you sign the first token) and call StartEgress or CreateRoom with egress.
• This is useful if you prefer not to pre-create rooms but still want egress started programmatically.
3) Use Console AutoEgress (if available)
• If LiveKit Console supports global AutoEgress configuration in your Cloud plan, enable it there so new rooms get the egress policy automatically. (Console is for observability and simple configs; programmatic control is still via CreateRoom/StartEgress.)
Implementation notes
• Tokens the client uses to join only carry permissions (e.g., roomRecord) — they do not carry full egress configs. Egress parameters belong in the CreateRoom/StartEgress request payload.
• Ensure the JWT used to call CreateRoom/StartEgress has roomCreate and roomRecord grants.
• If you prefer minimal latency, your backend can call CreateRoom with egress right before issuing the token; LiveKit handles cross-region creation, but avoid blocking token issuance on long CreateRoom calls — instead create room asynchronously or start egress after the participant joins.
Next step I can help with
• Show a minimal backend flow (Python) that: 1) creates room with egress, 2) issues a join token to iOS, or
• Provide a StartEgress example you can call after detecting a room was auto-created.
Which would you like?many-forest-60185
12/22/2025, 4:55 AMtall-airline-16756
12/22/2025, 4:55 AMegress parameters (or start egress) reliably.
• Tokens issued to the iOS client only carry permissions; they do not include egress configuration.
• Server creation avoids race conditions and ensures recordings/monitoring start immediately.
Minimal flow to implement
1. Backend: call CreateRoom with an egress object (or call StartEgress) and ensure the call uses a JWT that has roomCreate and roomRecord.
2. Backend: generate a join token for the iOS client (normal flow).
3. iOS client: use the token and call joinRoom as usual — no client changes required.
Practical tips
• Don’t block user signup on CreateRoom latency: create the room just before issuing the token, or create it asynchronously and start egress on first join.
• Use least-privilege storage credentials for uploads.
• Verify in Console or via ListEgress that the egress job is active after the room is created.
• If you want every room recorded without server calls, ask about Console-level AutoEgress (may be limited); otherwise server creation is the reliable approach.
Would you like a small Python backend example that (1) calls CreateRoom with egress, (2) mints a join token, and (3) returns it to your iOS client? If so, tell me which storage provider (S3/GCP/Azure) and I’ll give the exact snippet.many-forest-60185
12/22/2025, 4:56 AMtall-airline-16756
12/22/2025, 4:57 AMfile.filepath + one of file.s3 / file.gcp / file.azure
◦ HLS (segments): `segments.playlistName`/`segments.filepath` + segments.s3 / segments.gcp / segments.azure
◦ stream (RTMP/SRT): stream.urls: string[]
• Storage credentials:
◦ S3: accessKey, secret, bucket, region, optional endpoint, optional forcePathStyle
◦ GCP: credentials (service account JSON string), bucket
◦ Azure: accountName, accountKey, containerName
• Optional egress options: layout (grid/speaker), audioOnly, filename patterns (use {room_name}, {time}, {timestamp})
• API auth: LiveKit API key/secret (server) with roomRecord permission
• Optionally: webhook URL to receive egress completion events
Minimal Node.js flow (summary)
1. Create room (optional) via RoomServiceClient or let room exist.
2. Call EgressClient.startRoomCompositeEgress with the outputs and options above.
3. Monitor status via ListEgress or webhooks.
Minimal example (RoomComposite → S3)
import { EgressClient, RoomServiceClient } from "livekit-server-sdk";
const LIVEKIT_URL = "https://<your-livekit-host>";
const API_KEY = "your-api-key";
const API_SECRET = "your-api-secret";
const roomService = new RoomServiceClient(LIVEKIT_URL, API_KEY, API_SECRET);
const egressClient = new EgressClient(LIVEKIT_URL, API_KEY, API_SECRET);
async function createAndStartEgress(roomName) {
// 1. Create room (optional)
await roomService.createRoom({ name: roomName });
// 2. Start room composite egress (HLS segments example)
const outputs = {
segments: {
// HLS playlist name/path written to bucket
playlistName: "stream.m3u8",
filepath: `recordings/${roomName}/{timestamp}/`, // optional path pattern
s3: {
accessKey: "AWS_ACCESS_KEY",
secret: "AWS_SECRET",
region: "us-west-2",
bucket: "your-bucket",
forcePathStyle: true // for non-AWS providers
}
}
};
const opts = {
layout: "grid", // or "speaker"
audioOnly: false
};
const info = await egressClient.startRoomCompositeEgress(roomName, outputs, opts);
console.log("egress started:", info.egressId);
}
MP4 file variant (single file)
• Use file instead of `segments`:
const outputs = {
file: {
filepath: `recordings/${roomName}-{time}.mp4`,
s3: { accessKey: "...", secret: "...", bucket: "...", region: "..." }
}
};
GCP variant
gcp: {
credentials: JSON.stringify(serviceAccountJson),
bucket: "your-gcp-bucket"
}
Azure variant
azure: {
accountName: "your-account",
accountKey: "your-key",
containerName: "your-container"
}
Permissions & tokens
• Calls from your backend must use API key/secret that permit roomRecord.
• iOS clients need no change; they will receive a join token and simply join the pre-created room.
Operational notes
• If you pre-create the room, issue the join token after CreateRoom (or start egress right after creating room).
• If you prefer not to pre-create, call startRoomCompositeEgress when your backend detects the first participant joined.
• Monitor egress via Console, ListEgress, or egress completion webhooks.
If you want, I can:
• Produce a full Express.js endpoint that (a) creates room, (b) starts egress, and (c) returns a join token, or
• Generate the exact outputs object for your chosen provider (S3/GCP/Azure). Which would you prefer? Sources: RoomComposite Egress | LiveKit Docs | Egress API | LiveKit docsmany-forest-60185
12/22/2025, 4:57 AMtall-airline-16756
12/22/2025, 4:58 AMstartRoomCompositeEgress from your Node.js backend.
Key requirements
• gcp.credentials must be the service account JSON string (service account needs Storage Object Creator on the bucket).
• Use {room_name}, {time}, or {timestamp} in filepath for predictable names.
• Backend calls must use API key/secret that include roomRecord.
MP4 file output (single file)
const outputsFile = {
file: {
filepath: "recordings/{room_name}-{time}.mp4",
gcp: {
credentials: JSON.stringify(serviceAccountJson), // service account JSON object/string
bucket: "your-gcp-bucket"
}
}
};
HLS segments output (streamable)
const outputsHls = {
segments: {
playlistName: "stream.m3u8",
filepath: `recordings/${roomName}/{timestamp}/`, // folder prefix for segments
gcp: {
credentials: JSON.stringify(serviceAccountJson),
bucket: "your-gcp-bucket"
}
}
};
Minimal Node.js usage example
const { EgressClient } = require("livekit-server-sdk");
const egressClient = new EgressClient(LIVEKIT_URL, API_KEY, API_SECRET);
async function startGcpEgress(roomName) {
const outputs = {
// pick one:
// ...outputsFile
// or
// ...outputsHls
};
const opts = { layout: "grid" };
const info = await egressClient.startRoomCompositeEgress(roomName, outputs, opts);
console.log("egress started:", info.egressId);
}
If you want, tell me:
• whether you prefer MP4 or HLS, and
• paste (or confirm) whether your service account JSON is available so I can show the exact credentials format to embed.many-forest-60185
12/22/2025, 4:58 AMtall-airline-16756
12/22/2025, 4:58 AMfile output and set audioOnly: true (or pick an audio‑only format like Ogg if you prefer).
Below is the exact GCP MP4 output object for audio‑only and a minimal Node.js example to start a room composite egress that records audio only.
GCP MP4 (audio‑only) output object
const outputsFileAudioOnly = {
file: {
filepath: "recordings/{room_name}-{time}.mp4",
gcp: {
credentials: JSON.stringify(serviceAccountJson), // service account JSON string
bucket: "your-gcp-bucket"
}
}
};
Node.js example (audioOnly flag)
const { EgressClient } = require("livekit-server-sdk");
const egressClient = new EgressClient(LIVEKIT_URL, API_KEY, API_SECRET);
async function startAudioOnlyEgress(roomName) {
const outputs = outputsFileAudioOnly; // from above
const opts = {
layout: "speaker", // optional; layout used for rendering (ignored for audio-only)
audioOnly: true
};
const info = await egressClient.startRoomCompositeEgress(roomName, outputs, opts);
console.log("egress started:", info.egressId);
}
Notes
• MP4 container will contain only audio when audioOnly: true.
• If you prefer pure audio formats, you can use WebM/Ogg outputs for smaller audio-only files.
• Ensure the GCP service account has Storage Object Creator on the bucket and your backend API key has roomRecord permission.
Would you like the Ogg/WebM variant or a full Express endpoint that (1) creates the room, (2) starts audio egress, and (3) returns a join token?many-forest-60185
12/22/2025, 5:41 AMtall-airline-16756
12/22/2025, 5:42 AM// server.js
const express = require("express");
const bodyParser = require("body-parser");
const { RoomServiceClient, EgressClient, AccessToken, grants: { VideoGrant } } = require("livekit-server-sdk");
const app = express();
app.use(bodyParser.json());
// === CONFIG (set these in environment variables, not in code) ===
const LIVEKIT_URL = process.env.LIVEKIT_URL; // e.g. "<https://cloud.livekit.io>"
const LIVEKIT_API_KEY = process.env.LIVEKIT_API_KEY; // server API key (has roomRecord permission)
const LIVEKIT_API_SECRET = process.env.LIVEKIT_API_SECRET; // server API secret
const GCP_SERVICE_ACCOUNT_JSON = process.env.GCP_SA_JSON; // full JSON string (base64 if you prefer)
const GCP_BUCKET = process.env.GCP_BUCKET; // target bucket name
const JOIN_TOKEN_TTL = 60 * 60; // seconds (adjust as needed)
// instantiate clients
const roomService = new RoomServiceClient(LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
const egressClient = new EgressClient(LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
// === Helper: generate join token for iOS client ===
function generateJoinToken(identity, roomName) {
const at = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, { identity });
const grant = new VideoGrant({ room: roomName, roomJoin: true });
// include roomRecord? not required for client join, server starts egress
at.addGrant(grant);
at.setValidFor(JOIN_TOKEN_TTL);
return at.toJwt();
}
// === Endpoint: create room, start audio-only egress, return join token ===
<http://app.post|app.post>("/create-room-and-token", async (req, res) => {
try {
const { roomName, identity } = req.body;
if (!roomName || !identity) return res.status(400).json({ error: "roomName and identity required" });
// 1) Create room (idempotent)
await roomService.createRoom({ name: roomName });
// 2) Start room composite egress (audio-only MP4 → GCP)
const outputs = {
file: {
filepath: `recordings/${roomName}-{time}.mp4`,
gcp: {
credentials: GCP_SERVICE_ACCOUNT_JSON, // must be the JSON string
bucket: GCP_BUCKET
}
}
};
const opts = {
audioOnly: true,
// layout ignored for audioOnly, but you can set other options if needed
};
const egressInfo = await egressClient.startRoomCompositeEgress(roomName, outputs, opts);
// 3) Generate join token for client
const token = generateJoinToken(identity, roomName);
return res.json({
token,
roomName,
egressId: egressInfo.egressId
});
} catch (err) {
console.error("create-room-and-token error:", err);
return res.status(500).json({ error: err.message || "internal error" });
}
});
// start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`listening on ${PORT}`));
Secrets & information your backend needs (and where to store them)
• LIVEKIT_URL: LiveKit Cloud base URL.
• LIVEKIT_API_KEY & LIVEKIT_API_SECRET: your server API key/secret. Must have roomRecord permission so the server can start egress. Store in environment variables or a secrets manager (do NOT check into source).
• GCP_SERVICE_ACCOUNT_JSON: service account JSON (string). The service account must have the "Storage Object Creator" role on your bucket. Store this in a secrets manager or environment variable (consider base64 encoding it).
• GCP_BUCKET: destination bucket name.
• Optional: webhook endpoint URL if you want egress completion notifications (configure in LiveKit egress call or your account settings).
Permissions & best practices
• Use least-privilege credentials:
◦ LiveKit API key: grant only the server privileges needed (roomCreate, roomRecord).
◦ GCP service account: only Storage Object Creator on the specific bucket.
• Keep secrets in environment variables or a managed secrets store (AWS Secrets Manager, GCP Secret Manager, Vault).
• Do not embed secrets in client code (iOS app should only receive the join token).
• Rotate keys periodically and monitor access logs.
Operational notes
• startRoomCompositeEgress is idempotent per egress job; you’ll get an egressId to track the job.
• Monitor status via ListEgress or configure webhooks to be notified of completion/failure.
• If you prefer not to block token issuance, call create/start egress right before issuing token or in background; creating room is fast but can involve cross-region delays.
• If you ever want per-participant audio files instead of a composite, use tracks egress instead.
Would you like:
• The same endpoint but returning the egress status URL or hooking up an egress completion webhook handler?
• The Express example with GCP JSON read from a file (if you prefer that over env var)?