Types
Option objects and device-info classes passed across the API. All optional fields use sensible defaults β pass only what you want to override.
Device info
Three distinct, nominally-typed classes returned by VideoSDK.getCameras() / getMicrophones() / getSpeakers(). Same shape, different types β strongly-typed languages catch passing the wrong kind to a setter (e.g. a microphone where a camera is expected) at compile time.
CameraDeviceInfo
Returned by VideoSDK.getCameras(). Pass the whole object to setInputDevice, PublishVideoOpts.device, etc.
MicrophoneDeviceInfo
Returned by VideoSDK.getMicrophones(). Pass to setInputDevice, PublishAudioOpts.device, etc.
SpeakerDeviceInfo
Returned by VideoSDK.getSpeakers(). Pass to room.setOutputDevice, VideoSDK.testSpeaker.
kind field, no shared base class. The class identity is the discriminator β cameras[0] instanceof CameraDeviceInfo is the only check needed (and your type system gives it to you for free). Capability fields (e.g. facingMode, maxResolution) can be added per class later as additive non-breaking changes.LocalPublication
Payload of the stream-published event on LocalParticipant. Represents your local stream that just published. Exactly one of video / audio / screen is set, matching kind.
Fires for every publish path: explicit me.publishVideo(), async JoinOptions.publishVideo, and pre-call auto-promote (createVideoStream β join).
Subscription
Payload of the stream-subscribed event on RemoteParticipant. Represents the freshly-subscribed remote stream. Exactly one of video / audio / screen is set, matching kind.
Fires once per kind as that kind's subscribe pipeline becomes ready. Subscribing to [Audio, Video] fires twice β once with kind: Audio, once with kind: Video.
PublishRequest
Payload of the stream-publish-requested event on LocalParticipant. Fires when another participant calls requestPublishX() targeting you. You decide β call accept() to publish (returns a LocalPublication with the published stream) or reject() to silently decline.
accept() takes no parameters β uses SDK defaults. Equivalent to me.publishVideo({}) / me.publishAudio({}) / me.publishScreen({}) based on kind. The Promise rejects with an SDKError on failure (camera busy, permission denied, etc.) β see Errors β stream-publish-failed.
No timer. The request stays pending until you call accept() / reject(), or until either participant leaves the room.
UnpublishRequest
Payload of the stream-unpublish-requested event on LocalParticipant. Fires when another participant calls requestUnpublishX() targeting you. Decline with reject(); honor with accept().
This is not a hard mute. The recipient (you) can decline β there is no force-mute path on this surface. v1 may add moderator/host force-mute APIs later as a separate concern.
PublishFailure
Payload of the stream-publish-failed event on LocalParticipant. Covers both initial publish failures and mid-call runtime failures of a previously-live stream.
For initial publish failures, the corresponding Promise (e.g. me.publishVideo()) also rejects with the same SDKError β both channels deliver the error; app picks. For mid-call failures (camera unplug, encoder die, OS revoke), this event is the only delivery channel since there's no Promise to reject. After the event fires, me.<kind> is null; app can retry. Inventory: Errors β publish-failed.
SDKError
Every error the SDK surfaces β Promise rejections (join, publishVideo, etc.) and event payloads (stream-publish-failed, the cause field on ConnectionEvent) β uses this shape. Codes are stable strings; categorize via kind for handler reuse.
| Field | Description |
|---|---|
code | Stable identifier like 'INVALID_TOKEN' / 'CAMERA_BUSY'. This is what apps switch on. Codes are SCREAMING_SNAKE_CASE and never change between SDK versions; new codes can be added (additive). See the per-method docs for which codes each surface can fire. |
message | Human-readable description. Suitable for logs; not for switching. The wording may improve between SDK versions. |
kind | ErrorKind β coarse category. Lets apps write one handler per category (e.g. if (err.kind === ErrorKind.Auth) showLoginScreen()) without enumerating every code in that group. |
retriable | Optional. true when calling the same method again with the same input has a reasonable chance of succeeding (e.g. NETWORK_ERROR, TIMEOUT, CAMERA_BUSY). false for inherently terminal errors (INVALID_TOKEN, BROWSER_UNSUPPORTED). When omitted, treat as false. |
fatalflag β would be!retriablein 95% of cases. Dropped to keep the surface lean.detailsbag βRecord<string, any>defeats type-safety and the loose shape ends up under-documented in practice. Apps that need structured per-error context can request specific codes get richer payloads as additive changes later.
async function joinWithRetry(opts, maxAttempts = 3) {
for (let i = 0; i < maxAttempts; i++) {
try { return await VideoSDK.join(opts); }
catch (err) {
if (!err.retriable || i === maxAttempts - 1) throw err;
await sleep(2 ** i * 1000); // exponential backoff
}
}
}
try {
const room = await VideoSDK.join({ token, roomId });
} catch (err) {
switch (err.kind) {
case ErrorKind.Auth: return showLoginScreen();
case ErrorKind.Network: return showRetryButton();
case ErrorKind.Media: return showDevicePicker();
case ErrorKind.Permission: return showPermissionUI();
case ErrorKind.Server: return showSupportContact();
case ErrorKind.Config: console.error('SDK misuse:', err); throw err;
}
}
ConnectionEvent
Payload of the connection-state-changed event. Single shape for every transition; per-state data lives in nested optional blocks (reconnecting, disconnected) which are set only when the new state is the matching value.
| Field | When set | Description |
|---|---|---|
state | always | The new ConnectionState after the transition. |
previous | always | The state the room was in before this transition. Useful for distinguishing first connect vs recovery (e.g. previous reconnecting β state connected means recovery). |
reconnecting | iff state === Reconnecting | Per-attempt detail: which attempt this is, the cap, and the underlying cause if known. |
disconnected | iff state === Disconnected | Why the connection ended. reason is one of the v0-parity values in DisconnectReason. |
attempt, maxAttempts, reason, cause would put fields on the event that don't apply to most states. Nesting under reconnecting / disconnected keeps the top-level shape minimal and makes the per-state data discoverable. Translates uniformly across TS / Kotlin / Swift / Dart with native optional / nullable struct support β no discriminated unions or sealed classes required.JoinOptions
Argument to VideoSDK.join().
| Field | Type | Description |
|---|---|---|
token | string | Auth token issued by your backend. |
roomId | string | Room identifier to join. |
name | string? | Display name shown to other participants. |
participantId | string? | Stable participant id supplied by your app (e.g. user id from your DB). SDK generates a random one if omitted. Useful when the app already has user identity. |
metadata | any? | Custom data attached to your participant. Visible to others as p.metadata. |
preferredProtocol | Protocol? | Network transport preference β UdpOnly, UdpOverTcp (default), or TcpOnly. Useful in restrictive networks where UDP is blocked. |
signalingBaseUrl | string? | Override SDK's signaling endpoint. Default "api.videosdk.live". |
autoSubscribe | boolean? | Default false. When true, the SDK auto-subscribes to every remote stream as it appears β bandwidth scales with room size. When false (default), the app subscribes per-stream via stream.subscribe() / stream.attach(el) β bandwidth scales with rendered tiles. Pairs naturally with a subscribe-only token (grant canPublish: false, canSubscribe: true) for viewer-only clients that want every remote without writing per-tile subscribe. |
subscribeEvents | string[]? | List of lazy event names to pre-warm. SDK sends the upstream subscribe as part of the join handshake β eliminates the gap between join completing and your handlers being registered. |
onWaiting | () => void? | Lobby callback β fired exactly once if the joiner is placed in a waiting lobby (token's joinPolicy.mode === 'ask'). Use to render the waiting UI. Never fires for direct tokens or ask tokens admitted instantly. The join() Promise still resolves on admit and rejects on ENTRY_DENIED / ENTRY_TIMEOUT. |
signal | AbortSignal? | For an explicit "Cancel" button in the lobby UI β call controller.abort() and join() rejects with AbortError. Not needed for tab close: the SDK's socket disconnect handles cleanup automatically (server fires entry-canceled with reason: 'disconnected' for moderators). |
publishVideo | PublishVideoOpts? | Publish video as part of the join handshake (one round-trip). Ignored if a local stream from createVideoStream already exists. Throws if both are set for the same kind. Pass {} for defaults; pass { resolution: 'h720', ... } to customize. |
publishAudio | PublishAudioOpts? | Same shape for audio. Pass {} for defaults. |
- Pre-call β call
VideoSDK.createVideoStream(opts)first;join({})auto-promotes it. Same track from preview to publish (no flicker). - One-shot β pass
publishVideo: { ... }directly tojoin({}). SDK acquires + publishes during the join handshake (one round-trip). - Deferred β call
join({})with no publish opts; later callme.publishVideo(...)(two round-trips).
const room = await VideoSDK.join({
token: getAuthToken(),
roomId: 'team-standup',
name: 'Alice',
metadata: { role: 'host', avatarUrl: '...' },
subscribeEvents: ['active-speaker-changed', 'transcription'],
});
Related open questions: Q14 β One-step vs two-step join Q16 β Boolean shortcut for publishVideo / publishAudio Q17 β When does join() Promise resolve? (RESOLVED)
JoinPolicy
Value of the token's joinPolicy claim β a sibling of grant. Decides whether the participant goes straight in or is held in a waiting lobby until a moderator admits them. Default { mode: 'direct' } if the claim is absent.
| Field | Type | Description |
|---|---|---|
mode | 'direct' | 'ask' | 'direct' (default) bypasses the lobby. 'ask' requires a participant with canModerate to admit before the joiner enters. |
ttl | number? | Only valid with mode: 'ask'. How long the joiner waits (seconds) before the server times them out. Default 60; clamped to 10 β€ ttl β€ 600. Setting ttl with mode: 'direct', or outside bounds, is rejected as INVALID_ENTRY_CLAIM. |
mode: 'ask' + canModerate is rejected. A moderator can't knock on their own door. The backend's token-mint helper throws INVALID_ENTRY_CLAIM before signing the JWT (primary path); the server re-validates as a safety net for hand-rolled JWTs.EntryRequest
One pending lobby request, delivered to canModerate holders. Read the fields to render; call the methods to act. The same object appears on the entry-requested event and in the room.entryRequests snapshot β one type for both inline-handler and list-render UIs.
| Member | Type | Description |
|---|---|---|
participantId | string | Stable identity from the joiner's token, or a fresh SDK-generated id if the token omits participantId. |
name | string? | Display name from the joiner's JoinOptions.name. |
metadata | unknown? | Optional app-defined payload from the joiner (shape TBD). |
requestedAt | Date | When the knock landed at the server. |
expiresAt | Date | When the server's ttl will auto-timeout this request β equals requestedAt + ttl. Render a countdown if your UI wants one. |
admit() | Promise<void> | Admit the joiner. Resolves on server ack; the joiner's VideoSDK.join() resolves to a Room. Rejects with INVALID_PERMISSIONS if the caller lacks canModerate. No-op (resolves without effect) if the request was already resolved by another moderator. |
deny() | Promise<void> | Deny the joiner. Resolves on server ack; the joiner's join() rejects with ENTRY_DENIED. Same permission and idempotency rules as admit(). |
See also:
Waiting Lobby
room β entry-requested event
room.entryRequests
GetParticipantsOpts
Argument to room.getParticipants(). All fields optional.
| Field | Type | Description |
|---|---|---|
tier | 'speaker' | 'viewer'? | Filter to one tier. Omit to query both β speakers come first in the result, then viewers. The strings match the keys in participant-count-changed's payload. |
limit | number? | Page size; default 50, max 100. Values outside the range are clamped, not rejected. |
cursor | string? | Opaque token from a previous call's nextCursor. Omit on the first page. |
GetParticipantsResult
Return value of room.getParticipants().
| Field | Type | Description |
|---|---|---|
participants | RemoteParticipant[] | Page of participants. Both speaker- and viewer-tier instances share the RemoteParticipant class β viewer instances have isViewer: true, and calling subscribe() / publishX() on them rejects with INVALID_PERMISSIONS. |
nextCursor | string? | Pass to the next call to fetch the following page. Absent β no more pages in this filter. |
total | number | Total participant count within this filter (not just the current page). With tier: 'viewer', this is the audience count. With no filter, this equals participant-count-changed.total. |
ViewerParticipant class was considered and rejected β the isViewer flag plus permission-aware methods is simpler than two parallel class hierarchies. See MEETING_DECISIONS_V1.md β Large rooms / ILS.PublishVideoOpts
Argument to LocalParticipant.publishVideo().
| Field | Description |
|---|---|
device | CameraDeviceInfo from VideoSDK.getCameras(). Omit for default. Strongly typed β passing a microphone or speaker is a compile-time error. |
resolution | Capture height. Use the named presets ("h720" = 720p tall) or pass any number for custom heights. The SDK derives width = height Γ aspectRatio. |
aspectRatio | Width-to-height ratio (e.g. 16/9, 4/3, 1 for square). Default 16/9. |
facingMode | Mobile camera facing β "user" (front) or "environment" (back). |
frameRate | Target fps. e.g. 30, 60. |
multiStream | Whether to publish multiple simulcast layers (so subscribers can pick high/medium/low). true by default. Set false to publish a single layer (saves CPU + bandwidth on the publisher). |
maxLayer | Number of simulcast layers β 1, 2, or 3. Default 3. Ignored if multiStream is false. |
bitrateMode | Preset bitrate-ladder profile. "bandwidth_optimized" minimizes upload, "balanced" (default) is a sensible middle, "high_quality" uploads more for visual quality. |
maxBitrate | Hard cap (kbps) on the top simulcast layer. Overrides the preset's top if set. Lower layers scale proportionally. |
codec | Preferred video codec β see VideoCodec. Best-effort: if unavailable on the browser/SFU, falls back silently. Apps that need a guarantee check stream.codec after publish. |
degradationPreference | What to drop first under bandwidth pressure β see DegradationPreference. Default Balanced. |
contentHint | Encoder optimization hint β see ContentHint. Motion for high-motion video, Detail for general sharpness, Text for high-detail static content (slides, code). |
processor field. Frame processors are sticky and set globally via VideoSDK.applyVideoProcessor() β they apply automatically to any camera stream of the local participant. Setting once survives publish / unpublish / device swap.const cameras = await VideoSDK.getCameras();
await me.publishVideo({
device: cameras[0], // CameraDeviceInfo, not just an id
resolution: 'h720', // 720p height; default aspectRatio 16/9 β 1280Γ720
aspectRatio: 16/9, // optional; this is the default
facingMode: 'user',
frameRate: 30,
multiStream: true, // simulcast on
maxLayer: 3, // 3 layers
bitrateMode: 'balanced',
maxBitrate: 2500, // 2.5 Mbps cap
codec: VideoCodec.VP9,
degradationPreference: DegradationPreference.Balanced,
contentHint: ContentHint.Motion,
});
PublishAudioOpts
Argument to LocalParticipant.publishAudio().
| Field | Description |
|---|---|
device | MicrophoneDeviceInfo from VideoSDK.getMicrophones(). Omit for default. |
noiseSuppression | Browser-level noise suppression constraint. |
echoCancellation | Browser-level echo cancellation. |
autoGainControl | Browser-level AGC. |
processor field. Audio processors are sticky and set globally via VideoSDK.applyAudioProcessor().PublishScreenOpts
Argument to LocalParticipant.publishScreen(). Triggers the browser's getDisplayMedia picker.
| Field | Description |
|---|---|
audio | If true, capture system audio along with the screen. Browser support varies (Chrome on tab share, etc.). |
resolution | Capture height. Named preset or any number; SDK derives width = height Γ aspectRatio. |
aspectRatio | Width-to-height ratio. Default 16/9. |
frameRate | Target fps. Lower values (e.g. 5β15) save bandwidth for static content like presentations. |
PublishScreenOpts in a future release for parity with PublishVideoOpts β they're intentionally omitted in v1 to keep the screen-share surface minimal:
multiStreamβ simulcast on/offmaxLayerβ number of simulcast layersbitrateModeβ preset bitrate-ladder profilemaxBitrateβ kbps capcodecβ preferred video codecdegradationPreferenceβ what to drop under bandwidth pressurecontentHintβ encoder optimization hint (oftenTextfor screen-share)
StreamElementOpts
Argument to VideoStream.createElement() β controls the SDK-created <video> element.
| Field | Description |
|---|---|
containerStyle | Inline styles applied to the wrapping <div>. |
videoStyle | Inline styles applied to the inner <video> element. |
autoAdaptiveSub | If true (default), the SDK uses an IntersectionObserver to auto-pause the stream when the element scrolls offscreen. |
const tile = p.video.createElement({
containerStyle: { height: '300px', width: '300px', borderRadius: '8px' },
videoStyle: { objectFit: 'cover' },
autoAdaptiveSub: true,
});
document.querySelector('#grid').appendChild(tile);
PreCallTestOpts
Argument to VideoSDK.runPreCallTest(). Selects which phases run, optionally specifies stream config (or reuses pending streams), wires progress / error callbacks.
| Field | Description |
|---|---|
token | Auth token (same as JoinOptions). |
tests | Subset of PreCallPhase values to run. Default runs all. Quality implicitly runs Connectivity and Media internally (it needs the SFU connection and tracks). |
videoOpts | Used only if no pending video stream exists. Same shape as PublishVideoOpts (typed device, height-only resolution, etc.). |
audioOpts | Same for audio. |
audioOnly | If true, skip video entirely β no camera permission requested, video stats not collected. |
preferredProtocol | Network transport preference. Default "UDP_OVER_TCP". |
signalingBaseUrl | Override SDK's signaling endpoint. Default "api.videosdk.live". |
timeoutMs | Per-phase timeout. Default 15000. |
onProgress | Fires once per completed phase with phase-specific data. |
onError | Fires immediately on a non-fatal error in any phase. Same errors are also collected in result.errors[]. |
PreCallTestResult
Resolution value of the StoppablePromise returned by VideoSDK.runPreCallTest(). Per-phase results are present only for phases that ran (or were implicitly run).
media.video / media.audio fields are the same LocalVideoStream / LocalAudioStream instances either reused from pending pre-call streams or freshly created by the test. They remain "pending" β the next VideoSDK.join auto-promotes them. No raw MediaStreamTrack handoff.PubSub types
Types used by PubSub. See PubSub for the methods that use these.
PubSubMessage
Returned by publish and delivered to subscribe handlers. Same shape on both ends β apps don't fork render code.
| Field | Description |
|---|---|
id | Server-assigned globally-unique ID. Snowflake-style (timestamp-prefixed) β sortable and time-orderable across messages. |
topic | The topic this message was published to. Useful when one handler covers messages from multiple topics (future v1.x multi-topic subscribe). |
payload | App-defined message body. Whatever was passed to publish(topic, payload). Generic type T narrows it for type-safe consumers. |
metadata | Optional app-level extras passed via PublishOpts.metadata. Echoed back unchanged to subscribers. Use for routing hints, telemetry IDs, app version, etc. |
from | Sender's participantId. Same as room.localParticipant.id for the sender, or a remote participant's id. |
timestamp | Server-assigned wall clock. Use this for ordering / display β local clocks can drift. |
PublishOpts
Optional argument to publish. All fields optional.
| Field | Description |
|---|---|
persist | If true (default), the message is stored in topic history. Set false for ephemeral topics like cursor positions or signals β won't appear in getHistory, saves storage. |
to | Array of participantIds. Only listed participants receive on their subscribe handlers (and see this message in their history). Other subscribers on the same topic don't see it. Omit for normal broadcast (all subscribers receive). |
metadata | App-level fields separate from payload. Echoed back unchanged on the delivered PubSubMessage. Use for routing, filtering, telemetry, app version β anything that's "about the message" rather than "the message content". Forward-compatible with future server-side filter expressions. |
idempotencyKey in v1. The SDK generates and tracks idempotency keys internally for retry safety. App-level dedup (e.g., double-click guards) is the app's responsibility β disable the Send button while a publish is pending.SubscribeOpts
Optional argument to subscribe. All fields optional.
| Field | Description |
|---|---|
limit | Maximum messages per second delivered to this handler. Server respects max(active subs' limits) on the topic; SDK filters per-sub locally. When burst exceeds cap: drop oldest, keep latest N/sec. Omit (or undefined) for no cap β receive full firehose. |
max across all active subs (so the highest-cap sub gets what it needs). Each subscription's handler is filtered locally to its own limit. If any sub has no limit, the server sends the full firehose for that topic.PubSubSubscription
Returned by subscribe. Each call returns its own handle; multiple subscribes on the same topic create independent subscriptions.
| Member | Description |
|---|---|
topic | The topic this subscription is for. |
unsubscribe() | Stops calling the handler for this subscription. SDK refcountβ; when refcount reaches 0 on a topic, SDK tells server to stop sending. Idempotent β safe to call multiple times; second call is a no-op. |
historyAvailable flag. An earlier draft put a snapshot boolean here so apps could skip getHistory on empty topics. Dropped β it coupled the live-subscription handle to a history concern, and the call it saved parallelizes with subscribe anyway. getHistory is the single source of truth for whether a topic has history (empty messages + hasMore: false). See CHAT_DECISIONS_V1.md Decision 7.HistoryOpts
Optional argument to getHistory. All fields optional. Pass before or after β not both.
| Field | Description |
|---|---|
limit | Maximum messages in the returned page. Default 25, max 50. A value above 50, or ≤ 0, rejects with INVALID_LIMIT β SDK-local, before any round trip. |
before | A message id. Returns the page of messages immediately older than it β scroll-up / load-earlier. Omit (with no after) to get the newest page. |
after | A message id. Returns the page of messages immediately newer than it β reconnect gap-fill. The id can come from any message the client holds: a subscribe callback, a publish return value, or a prior history page. |
from | Server-side filter β restricts the page to messages sent by the listed participantIds. Combines with before/after: the server filters first, then paginates the filtered set, so hasMore and page edges reflect the filtered set. An empty array rejects with INVALID_HISTORY_OPTS. |
id, not an opaque cursor. before / after take a PubSubMessage.id (a snowflake). One anchor concept across the whole API β every message from every source carries an id usable here. Pass before or after, never both β that rejects with INVALID_HISTORY_OPTS. See CHAT_DECISIONS_V1.md Decision 22.HistoryPage
Returned by getHistory. Plain data β no methods. Paginate by re-calling getHistory with a page-edge message id.
| Field | Description |
|---|---|
messages | The page of messages, always oldest-first (chronological) regardless of direction. messages[0] is the oldest, the last element the newest. |
hasMore | true if more messages exist in the direction this call queried β older for a before (or default) call, newer for an after call. |
id. To load the next older page, call getHistory(topic, { before: page.messages[0].id }). To continue newer, use the last message's id as after. There is no Paginator object and no cursor field β the message id already in the page is the anchor.Recording & streaming types
Option objects for the server-side media features on Room β consumed by Room.startRecording(), startHls(), startLivestream(), and startTranscription(). These configure server-side compositors and pipelines β no client tracks are involved.
LayoutConfig
Controls how the server compositor arranges participant tiles for a recording / HLS / livestream feed. Shared by RecordingOptions, HlsOptions, and LivestreamOptions via their layout field. Omit entirely for a sensible default grid.
gridSize caps differ per feature. The maximum is server-enforced, not validated client-side: recording allows up to 4 tiles, HLS up to 25. A value above the feature's cap is clamped server-side. Tune it to the layout β a spotlight layout typically wants a small gridSize, a grid layout the feature maximum.SummaryConfig
Configures the AI summary generated alongside a transcription. Used as the summary field of TranscriptionConfig.
transcription itself. There is no enabled field β the summary object being present on TranscriptionConfig is what turns the AI summary on. Pass summary: {} for the default prompt, or summary: { prompt: '...' } to customize it.TranscriptionConfig
Configures live transcription (and optionally an AI summary). Passed directly to Room.startTranscription(), and reused as the transcription field of RecordingOptions / HlsOptions / LivestreamOptions to transcribe those feeds.
TranscriptionConfig appears as the transcription field of a recording / HLS / livestream option object, its mere presence means transcription is on for that feed β there is no enabled boolean. Likewise the nested summary: present β summary on, absent β off. See SummaryConfig.RtmpOutput
A single RTMP destination for a livestream. LivestreamOptions.outputs is an array of these β one entry per platform you broadcast to.
HlsUrls
The pair of playback URLs produced when HLS streaming is active β surfaced via Room state / events once startHls() has spun up the stream.
playbackUrl exposes a DVR window so viewers can pause and rewind; liveUrl pins playback to the live edge for the lowest latency at the cost of scrub-back. Pick per viewer experience.RecordingOptions
Optional argument to Room.startRecording(). All fields optional β call startRecording() with no argument to record with SDK defaults (grid layout, project default storage).
| Field | Description |
|---|---|
layout | LayoutConfig for the server compositor. Omit for a default grid. The recording gridSize cap is 4. |
templateUrl | URL of a custom layout template page. When set, it overrides layout β the template fully controls composition. |
theme | Visual theme for the composited output β 'dark', 'light', or 'default'. |
mode | 'video-and-audio' records a composited video file; 'audio' records an audio-only file. |
quality | Output quality β see MediaQuality. |
orientation | 'portrait' or 'landscape' aspect for the composited output. |
transcription | TranscriptionConfig. Presence-based β set it to also transcribe the recording; omit to skip transcription. |
webhookUrl | Optional. Bring-your-own webhook for recording lifecycle / result delivery. Omit to use the project default. |
awsDirPath | Optional. Bring-your-own S3 directory path for the stored file. Omit to use the project's default storage. |
preSignedUrl | Optional. Bring-your-own pre-signed storage URL to upload the file to. Omit to use the project's default storage. |
webhookUrl, awsDirPath, and preSignedUrl let you route recordings to your own storage / notification infrastructure. Omit all three to use the project's default storage. HLS and livestream have no storage params β their output is a live stream, not a stored file.HlsOptions
Optional argument to Room.startHls(). All fields optional β call startHls() with no argument to stream with SDK defaults. Output is a live HLS stream (see HlsUrls), not a stored file.
| Field | Description |
|---|---|
layout | LayoutConfig for the server compositor. Omit for a default grid. The HLS gridSize cap is 25. |
templateUrl | URL of a custom layout template page. When set, it overrides layout. |
theme | Visual theme for the composited stream β 'dark', 'light', or 'default'. |
mode | 'video-and-audio' or 'audio'-only HLS. |
quality | Output quality β see MediaQuality. |
orientation | 'portrait' or 'landscape' aspect for the stream. |
transcription | TranscriptionConfig. Presence-based β set it to also transcribe the HLS feed. |
recording | When true, the server also records the meeting to a stored file while HLS-streaming β combining startHls() and startRecording() into one pipeline. |
webhookUrl / awsDirPath / preSignedUrl fields. Set recording: true to also capture a stored recording β that recording uses the project's default storage.autoStart field in the client SDK. v0's autoStartConfig (HLS auto-starts when the first speaker joins) is a REST / project-config concern β set server-side via the management API. The client never initiates auto-start; if the project has it enabled, HLS appears in starting β started β playable exactly as if a client had called startHls(). Intentionally out of HlsOptions.LivestreamOptions
Argument to Room.startLivestream(). Unlike recording and HLS, this argument is required β outputs must list at least one RTMP destination.
| Field | Description |
|---|---|
outputs | Required. Array of RtmpOutput β the RTMP destinations to broadcast to (YouTube, Twitch, etc.). One entry per platform. Must be non-empty. |
layout | LayoutConfig for the server compositor. Omit for a default grid. |
templateUrl | URL of a custom layout template page. When set, it overrides layout. |
theme | Visual theme for the composited stream β 'dark', 'light', or 'default'. |
mode | 'video-and-audio' or 'audio'-only broadcast. |
quality | Output quality β see MediaQuality. |
orientation | 'portrait' or 'landscape' aspect for the broadcast. |
transcription | TranscriptionConfig. Presence-based. Requires recording: true β transcription on a livestream is derived from the stored recording pipeline. |
recording | When true, the server also records the meeting to a stored file while livestreaming. Must be true if transcription is set. |
outputs is required; transcription requires recording: true. startLivestream() must be given a non-empty outputs array of RtmpOutput destinations. Transcription on a livestream rides on the recording pipeline, so setting transcription without recording: true is rejected. Like HLS, livestream has no storage params β set recording: true to also capture a stored file (project default storage).See also: Enums VideoSDK LocalParticipant PubSub Room