

# Conventions & Limits (v28)

Encoding
- URL parameters that carry freeform text or URLs should be URL‑encoded. Examples: `label`, `password`, `endpage`, `avatarimg`, `bgimage`, `overlayimage`, `discordwebhook`, WHIP/WHEP URLs.
- The app decodes many fields internally via `decodeURIComponent(...)` (e.g., images, webhooks, endpage) and encodes some (e.g., password) before transport. When in doubt, encode.
- Booleans accept: `true` (presence), or strings `true/1/yes/on`; falsy strings `false/0/no/off` disable.
- Lists: comma‑separated (e.g., `view=SID1,SID2`, `include=SID3,SID4`).

IDs and Names
- Stream ID (`push`/`id`/`permaid`):
  - Allowed chars: A‑Z, a‑z, 0‑9, `_` (non‑word characters are replaced by `_`).
  - Max length: trimmed to 70 characters (practical cap ~64 before internal salting).
  - Auto‑generation: if empty, an 8‑char ID is generated. IDs shorter than 3 or `test` are warned as insecure on vdo.ninja if using default password.
  - Screenshare ID (`screenshareid`) follows the same sanitization.
- Room name (`room`/`r`/`roomid`):
  - Allowed chars: A‑Z, a‑z, 0‑9, `_` (non‑word characters become `_`).
  - Max length: 30 characters (longer names are trimmed with a warning).
- Label (`label`/`l`): sanitized HTML‑safe and truncated to 100 chars.
- Passwords: accepted as provided; internally `encodeURIComponent` is applied. Hash/CRC checks use a maximum of 6 characters.

Viewer selection & suffixes
- `view` accepts multiple IDs, comma‑separated.
- `:s` suffix on an ID allows only its screen‑share track (e.g., `view=ID1,ID2:s`).
- `include` can add allowed IDs on top of `view`.

LAN, STUN/TURN, and relays
- LAN by default: WebRTC negotiates host candidates automatically; peers on the same network typically connect over LAN without extra parameters.
- Force LAN only: `&lanonly` prefers local/host candidates and avoids external routes.
- Force relays/turn: `&privacy`/`&relay` sets `iceTransportPolicy=relay` and throttles bitrate caps to protect shared TURN. Use only with your own TURN if possible.
- Candidate filtering/tcp: `&and-icefilter` and `&and-tcp` can restrict candidate types.

Timing and limits
- `retrytimeout`: reconnect delay; clamped to a minimum of 5000 ms.
- `whipwait`/`whepwait`: default 2000 ms; clamped to ≥0.
- `autoend`: defaults to 10 minutes when present without a value.
- `audiobitrate`: clamped to 510 kbps max; disabled on iOS.
- `maxvideobitrate`/`bitrate`: auto‑adaptation may further constrain; privacy/relay mode caps to 4000–6000 kbps depending on context.

Boolean defaults by context
- `stats`: on by default in some program views; passing `0/false/off` disables.
- `showdirector`: when numeric `2`, forces video‑only; otherwise A/V.
- IFrames: `nohistory` defaults to true inside IFRAME embeds.

Misc
- Discord webhook: accepts full or shortened form; code normalizes to `https://discord.com/api/webhooks/...`.
- Endpage redirect: use `endpage` with a URL‑encoded link; optional `endpagetimer` delay (ms).
- OBS fixes: `obsfix` is numeric (default 1) for progressively stronger workarounds.

FAQ (canonical answers)
- Does VDO.Ninja support H.265/HEVC?
  - Yes, when the sending and receiving environments expose HEVC in WebRTC. Safari commonly supports HEVC publishing; modern Chrome can decode HEVC on many platforms. You can hint with `&codec=h265` (or `hevc`). Actual selection depends on encoder/decoder availability. Test page: https://vdo.ninja/h265
- Should I URL‑encode parameters?
  - Yes for free‑form strings and URLs (display names, passwords, image/overlay URLs, webhooks, redirect targets). The app decodes many of these; when in doubt, encode.
- How long can stream IDs be, and what characters are allowed?
  - IDs are sanitized to alphanumerics and `_`; non‑word characters become `_`. IDs longer than ~64 are trimmed to 70; very short IDs (<3) or `test` warn as insecure when using default password.
- Does it work automatically over LAN?
  - Yes. WebRTC will use local/host candidates by default when available; peers on the same network generally connect via LAN without flags. Use `&lanonly` to force LAN only; use `&privacy`/`&relay` to force relays (TURN).




# Core Concepts

- Purpose: VDO.Ninja provides ultra‑low latency, peer‑to‑peer WebRTC links to capture and route audio/video between browsers and production apps (e.g., OBS) with minimal infrastructure.
- Topologies: Direct peer links, group rooms (director orchestrated), and optional relays/SFU helpers for scale or NAT traversal.
- Entities: Sources (publishers), Viewers (subscribers), Rooms (collections orchestrated by a director), Director/Co‑Director (control plane), and External APIs (iframe/remote).
- Identity: Streams use IDs (push/view). Rooms optionally use passwords/realms. Links encode behavior via URL parameters.
- Media pipeline: Browser getUserMedia → WebRTC PeerConnection → ICE/STUN/TURN → remote peer. Codecs and bitrates adjust per constraints; stats are available live.
- Latency vs resilience: Parameters trade off end‑to‑end latency, quality, and robustness (buffer, bitrate caps, codec choices, SVC/simulcast where available, packet loss strategies).
- Hostnames: Production instances include `vdo.ninja` and alternates. Self‑hosting handshake servers is possible; peer traffic remains P2P unless relayed.

Key Terms
- Stream ID: Unique identifier for a published stream; viewers subscribe via this ID. Auto‑generated if not provided for guests.
- Room: Named space for multi‑party sessions managed by a director; can apply room‑wide settings (bitrate, permissions).
- Director: Room controller; can configure layout, permissions, and visibility; supports co‑director.
- Realm/Password: Namespace fence for stream/room IDs; the same ID in different realms does not collide.
- Remote control: Optional API/iframe mechanisms to observe stats and invoke actions when permitted.

Notes
- v28 is the basis for behavior; when docs conflict, prefer `source-code/main.js` and `source-code/webrtc.js`.




# Code Insights (v28)

This page summarizes implementation details from `source-code/main.js` and `source-code/webrtc.js` that inform behavior beyond parameter descriptions.

- Controls persistence and sticky sessions
  - `sticky`: Saves full URL to storage with a `permission` cookie and auto-redirects on load if accepted. Clears when declined.
  - UI logic avoids sticky in iframes/OBS and hides Save Room when in studio software.

- Preview and autoplay nuances
  - `nopreview` flips to `minipreview=3` on iOS to comply with autoplay/device policies; `forcecontrols` repeatedly re-applies `<video controls>` for stubborn UIs.
  - `cleanviewer`/`cleanoutput` disable some visual meters by design (e.g., `audioMeterGuest=false`).

- Director quality and motion controls
  - `showdirector`: numeric value `2` locks video-only; otherwise enables both A/V.
  - `bitratecutoff` defaults to 300 kbps for low-bitrate handling; quality buttons toggle `directorViewBitrate` and pressed states.
  - `motionswitch`/`motionrecord`: motion thresholds (default 15) drive scene switching and motion-triggered recording.

- Stats, connections, and overlays
  - `showconnections` enables remote guest connection counts as a stat; `showlist` toggles side list visibility in broadcast/program.
  - `obsfix` integer level (default 1) applies workarounds optimized for OBS Browser Source playback.

- Reconnect and timers
  - `retrytimeout` has a floor of 5000 ms; `autoreload` (minutes) and `autoreload24` (HH:MM) schedule a hangup/reload.
  - `autoend` defaults to 10 minutes if present with no value.

- WHIP/WHEP and relays
  - `whipwait`/`whepwait` default to 2000 ms and clamp to 0 minimum; Cloudflare token helper (`cftoken`) rewrites to `https://cloudflare.vdo.ninja/...`.
  - `nomeshcast` also toggled by `nowhep`; `meshcastcode` short alias `mccode`.

- History and embedding behavior
  - `nohistory` default in iframes to reduce back/forward pollution; `iframetarget` controls postMessage origin enforcement.
  - `transparent` sets several CSS variables for full alpha compositing and removes margins in director layout.

- Audio pipeline notes
  - Stereo/pro-audio modes disable `echoCancellation`, `autoGainControl`, and `noiseSuppression` automatically; `mono` coerces stereo modes and often sets `audiobitrate=128`.
  - `micsamplerate` and `micsamplesize` can override capture settings but are bound by device/browser support.
  - `latency`/`micdelay` enable WebAudio path and offset playout; `panning` triggers WebAudio spatialization.

- Scene/view composition
  - `include` supports `:s` suffix to selectively allow screenshares; `directoronly` restricts views to director.
  - `fakeguests`/`fakefeeds`/`fakeusers` create test video elements sourced from `./media/fakesteve.webm` for layout validation.

- Security and auth
  - `password` + `hash`/`crc`/`check` perform a short hash verification (max 6 chars). Legacy salt `obs.ninja` is still supported as fallback.
  - `requireencryption` and `secure` affect UI/security posture; `unsafe` unlocks advanced operations.

- Electron integration
  - When running in Electron, `window.prompt` is overridden via contextBridge if available; version updates are sent to the host.
  - `deleteWhipOnLoad` sessionStorage entry triggers a DELETE to a WHEP endpoint on load to clean up previous sessions.

- Codec preferences (webrtc.js)
  - Viewers and iframe API can request codec preferences; H.264 gets special handling on Android/hardware encoders.
  - `nacks_per_second` and other stats are propagated for diagnosing packet loss; availableOutgoingBitrate informs adaptation.

Use these notes to augment parameter guidance with real behavior and defaults when clarifying with users.




# Quick Start

Direct Link: Publish → View
- Publish camera/mic: `https://vdo.ninja/?push=MYID&label=Guest+1`
- View in OBS: `https://vdo.ninja/?view=MYID&stats&buffer=0`
- Optional password realm: add `&password=ROOMPASS` to both links.

Room Workflow (Director + Guests)
- Director: `https://vdo.ninja/?director=myshow&password=ROOMPASS`
- Guest invite (auto-join): `https://vdo.ninja/?room=myshow&password=ROOMPASS&label=Guest+1&autostart`
- Program view (scene/composite): `https://vdo.ninja/?scene&room=myshow&password=ROOMPASS&stats`

Screen Share With System Audio
- Publisher: `https://vdo.ninja/?push=SCREEN1&screenshare&label=Screen&autostart`
- Viewer: `https://vdo.ninja/?view=SCREEN1&buffer=0&stats`

Low Bandwidth / CPU Mode
- Publisher: `&bitrate=800&frameRate=15&width=640&height=360`
- Viewer: `&buffer=150&stats`

Remote Monitoring / Control
- Enable remote: add `&remote` to the target link.
- Monitor stats: use the speed test monitor link or a remote panel configured with the same API key if applicable.




# Examples Library

Direct Publish/View
- Publish: https://vdo.ninja/?push=GUEST1&label=Guest+1&autostart
- View: https://vdo.ninja/?view=GUEST1&stats&buffer=0

Program/Scene in Room
- Director: https://vdo.ninja/?director=show&password=PASS
- Guest: https://vdo.ninja/?room=show&password=PASS&label=Cam+1&autostart
- Program: https://vdo.ninja/?scene&room=show&password=PASS&stats

Screen Share with Stereo System Audio
- Source: https://vdo.ninja/?push=SCREEN1&screenshare&screensharestereo=1&label=Screen&autostart
- View: https://vdo.ninja/?view=SCREEN1&buffer=120&stats

Low‑Bandwidth Interview
- Source: https://vdo.ninja/?push=G1&label=Guest&bitrate=1200&maxbitrate=1500&frameRate=24&width=960&height=540
- View: https://vdo.ninja/?view=G1&buffer=120&stats

Pro‑Audio Music Jam
- Source: https://vdo.ninja/?push=BAND&label=Guitar&stereo=1&audiobitrate=192&autostart
- View: https://vdo.ninja/?view=BAND&buffer=0&stats

Director Remote Monitoring
- Guest: https://vdo.ninja/?room=show&password=PASS&remote
- Monitor: Use speed test monitor link or API controller with same key.

Meshcast for Larger Audience
- Program: https://vdo.ninja/?scene&room=show&meshcast=any
- Viewer: https://vdo.ninja/?view=MCID&buffer=150&stats (service‑dependent)




# Advanced Examples

Remote API (iframe postMessage)
- Mute a specific stream ID:
  - parent.postMessage({ mute: { streamID: "SID123", state: true } }, "*")
- Change layout to grid-4:
  - parent.postMessage({ layout: { name: "grid", slots: 4 } }, "*")
- Request continuous stats to parent:
  - parent.postMessage({ requestStatsContinuous: { intervalMs: 1000 } }, "*")
- Set target video bitrate for a connection:
  - parent.postMessage({ targetBitrate: { streamID: "SID123", kbps: 2500 } }, "*")
- Fetch device list:
  - parent.postMessage({ getDeviceList: true }, "*")

HTTP/WSS Remote API (keyed)
- Enable: add `&api=MYKEY` to session URLs and use a controller with the same key.
- Example POST webhook on event (using &postapi):
  - ?postapi=https%3A%2F%2Fwebhook.site%2FMYID
  - Payloads include connection and stat updates; use to monitor and orchestrate.

Co‑Director Workflow
- Create director link: https://vdo.ninja/?director=show&password=PASS
- In the director UI, generate a co-director invite and select permissions (mute, remove, solo, scene control).
- Share the co-director link with trusted operator; revoke by changing room/password.

Complex Multi‑Input Audio Routing
- Two local mics and one USB interface into one guest:
  - ?push=BAND&adevice=USB+Mic,Line+In&channelcount=2&stereo=1&audiobitrate=192&autostart
  - Viewer: ?view=BAND&buffer=0&stats
- Screen-share stereo DAW output while keeping mic mono for talkback:
  - ?push=LIVE&screenshare&screensharestereo=1&adevice=USB+Mic&monomic&autostart
  - Viewer: ?view=LIVE&buffer=120&stats




# Global Parameters

Name: password | pass | pw | p
- Scope: global/room
- Type/Default: string | default per instance; may be absent
- Description: Sets the realm/room password; impacts stream/room ID namespace and access validation. Supports hash checks via `&hash`.
- Interactions: `&hash`, `&salt`, room/director links, guest auto‑generation of stream IDs.
- Examples: `?room=show&password=ROOMPASS` | `?view=ID&password=ROOMPASS`
- Source: main.js search: `session.password = urlParams.get("password")`

Name: hash | crc | check; salt
- Scope: global/room
- Type/Default: string (hash prefix) | optional `salt`
- Description: Validates realm/room password via short hash; if mismatch, session is tainted and UI restricted.
- Interactions: requires password. Legacy salt `obs.ninja` supported.
- Examples: `?room=r1&password=pass&hash=abcd`
- Source: main.js search: `generateHash(session.password + session.salt, 6)`

Name: label | l | defaultlabel | labelsuggestion | ls
- Scope: global
- Type/Default: string | prompt if required
- Description: Display name used in UI and director view; sanitized. `defaultlabel` prompts with suggestion.
- Interactions: `&showlabels`, `&sizelabel`, director/scene labels.
- Examples: `?label=Guest+One`, `?defaultlabel=Jane`
- Source: main.js search: `session.label = urlParams.get("label")`

Name: remote | rem
- Scope: global/viewer
- Type/Default: boolean | false
- Description: Grants permission for remote stat access and limited control by authorized tools.
- Interactions: Speedtest monitor; remote control integrations.
- Examples: `?view=ID&remote`
- Source: main.js search: `session.remote = urlParams.get("remote")`

Name: stats
- Scope: viewer/global
- Type/Default: boolean | true (varies by view)
- Description: Enables/disables on‑screen stats overlay. `0/false/off` disables.
- Interactions: `&remote`, director view, program scene.
- Examples: `?view=ID&stats`
- Source: main.js search: `if (urlParams.get("stats") == "0")`

Name: buffer | buffer2
- Scope: viewer
- Type/Default: number (ms) | 0
- Description: Adds playback buffer to reduce glitching at the cost of latency. `buffer2` includes RTT component.
- Interactions: `&sync`, network jitter; OBS vs browser decoding differences.
- Examples: `?view=ID&buffer=120`, `?view=ID&buffer2=80`
- Source: main.js search: `session.buffer = parseFloat(urlParams.get("buffer"))`

Name: frameRate | fr | fps; maxframerate | mfr | mfps
- Scope: source
- Type/Default: number | defaults per device
- Description: Requests capture/encode frame rate; `maxframerate` caps it.
- Interactions: `&bitrate`, `&width/height`, CPU/GPU limits; Chrome may constrain.
- Examples: `?push=ID&frameRate=30`, `?push=ID&maxframerate=30`
- Source: main.js search: `session.frameRate = urlParams.get("frameRate")`

Name: videobitrate | bitrate | vb; maxvideobitrate | maxbitrate | maxvb | mvb
- Scope: source
- Type/Default: number (kbps) | 8000 default; max unset
- Description: Target video bitrate and hard cap. Values may be adjusted by bandwidth estimation.
- Interactions: Room bitrate controls; outbound overrides.
- Examples: `?push=ID&bitrate=2500&maxbitrate=3000`
- Source: main.js search: `session.bitrate = urlParams.get("videobitrate")`

Name: audiobitrate | ab
- Scope: source/viewer
- Type/Default: number (kbps) | false (auto)
- Description: Sets Opus target bitrate. iOS disables custom audio bitrates due to distortion risk.
- Interactions: Echo/noise cancellation settings; stereo/mono.
- Examples: `?push=ID&audiobitrate=128`
- Source: main.js search: `session.audiobitrate = urlParams.get("audiobitrate")`

Name: codec | codecs | videocodec
- Scope: source
- Type/Default: string | auto
- Description: Preferred video codec selection (e.g., h264, vp9, av1) subject to browser support.
- Interactions: Simulcast/SVC, hardware acceleration, OBS decoder.
- Examples: `?push=ID&codec=h264`
- Source: main.js search: `session.codecs = urlParams.get("codec")`

Name: secure; requireencryption; unsafe
- Scope: global
- Type/Default: boolean | off
- Description: Security toggles; `secure` enables enhanced UI guards, `requireencryption` enforces DTLS‑SRTP only, `unsafe` permits advanced operations.
- Interactions: Iframe/script injections, device prompts, warnings.
- Examples: `?secure`, `?requireencryption`
- Source: main.js search: `if (urlParams.has("secure"))`

Name: retrytimeout
- Scope: global
- Type/Default: number (ms) | min 5000
- Description: Sets reconnection retry timeout; values <5000 are clamped to 5000.
- Examples: `?retrytimeout=8000`
- Source: main.js search: `session.retryTimeout`

Name: tz
- Scope: interop/relay
- Type/Default: number | false
- Description: Legacy flag used with meshcast/turn; parsed as integer or false.
- Examples: `?tz=2`
- Source: main.js search: `session.tz`

Name: random | randomize
- Scope: global
- Type/Default: boolean | off
- Description: Enables randomization behaviors in some UI/flows.
- Examples: `?random`
- Source: main.js search: `session.randomize`

Name: ln | language
- Scope: global
- Type/Default: string | auto
- Description: Override the UI language template. Accepts language codes; falls back based on stored preference.
- Examples: `?ln=de`, `?language=es`
- Source: main.js translation block near startup.

Name: notios; notmobile
- Scope: global/platform
- Type/Default: boolean | off
- Description: Override platform detection to treat the environment as non‑iOS or non‑mobile.
- Source: main.js search: `notios`, `notmobile`.

Name: clearstorage | clear
- Scope: global
- Type/Default: boolean | off
- Description: Clear local/session storage and cached flags for a clean start.
- Source: main.js search: `clearstorage`.

Name: locksize
- Scope: global/viewer
- Type/Default: boolean/string | on
- Description: Prevent resizing of the window/canvas to stabilize layout.
- Source: main.js search: `locksize`.

Name: auth | requireauth
- Scope: global/room
- Type/Default: boolean | off
- Description: Enables authentication mode. `&auth` enables optional sign‑in UI; `&requireauth` enforces sign‑in for protected rooms and director actions when the auth service indicates it’s required.
- Interactions: `&authtoken`, `&universaltoken`, room/director links; auth UI may prefill `&label` and avatar on success.
- Examples: `?room=show&auth`, `?room=show&requireauth`.
- Source: auth-client.js search: `session.authMode`, `session.requireAuth`.

Name: authtoken
- Scope: global
- Type/Default: string (JWT) | none
- Description: Injected by the auth service on redirect; persists to `localStorage` and used to fetch user info, assign stream IDs, and authorize room access.
- Interactions: `&auth`/`&requireauth`; cleans itself from URL after storing.
- Examples: `?authtoken=...` (not user‑set; comes from OAuth redirect).
- Source: auth-client.js search: `session.authToken = urlParams.get("authtoken")`.

Name: universaltoken
- Scope: global/viewer/scene
- Type/Default: string (token) | none
- Description: Grants room‑scoped viewing privileges without per‑user authentication. Useful for sharing view/scene links; can bypass `&requireauth` for viewing.
- Interactions: Room access checks; used by scenes and solo links; directors can mint via UI.
- Examples: `?view=ID&universaltoken=...`
- Source: auth-client.js search: `urlParams.has("universaltoken")` and `validate-universal` endpoint usage.




# Networking & Handshake

Name: proxy
- Scope: global
- Type/Default: boolean | off
- Description: Route WSS via proxy path when `session.wss` is overridden.
- Source: `main.js` search: `session.proxy`.

Name: pie
- Scope: global (deprecated)
- Type/Default: string/boolean | off
- Description: PieSocket support (deprecated); may set custom WSS URL.
- Source: `main.js` search: `session.customWSS`, `session.wssSetViaUrl`.

Name: apiserver
- Scope: global
- Type/Default: string | none
- Description: Override API server base for remote control/backends.
- Source: `main.js` search: `session.apiserver`.

Name: speedtest
- Scope: global/networking
- Type/Default: boolean/string | off
- Description: Enables speed test mode (may force UDP‑like behavior and apply bitrate limits). In privacy/relay mode, speedtest adjusts bitrate caps (e.g., 6000 kbps) and sets relay policy.
- Source: main.js search: `setupSpeedtest()`, `session.speedtest`, relay caps

Name: secure; requireencryption; unsafe
- Scope: global
- Description: Security posture toggles; may affect ICE transport policy and UI.
- Source: `main.js` search around security flags.

Notes
- TURN/relay usage is negotiated via ICE; session may set `iceTransportPolicy = "relay"` under certain conditions.
- For self‑hosting signaling, see `general-settings/pie.md` and the websocket server repo referenced there.

Additional Networking Flags
- Name: bundle
  - Scope: networking
  - Type/Default: string | browser default
  - Description: Set RTCPeerConnection bundle policy (e.g., `max-bundle`).
  - Source: main.js search: `session.bundlePolicy`.
- Name: addstun
  - Scope: networking
  - Type/Default: string (STUN URL) | none
  - Description: Append a STUN server to the ICE server list.
  - Examples: `?addstun=stun:stun.example.com:3478`
  - Source: main.js search: `urlParams.get("addstun")`.
- Name: lanonly
  - Scope: networking
  - Type/Default: boolean | off
  - Description: Prefer local/LAN candidates only; useful for on-prem setups.
  - Source: advanced-settings/turn-and-stun-parameters/and-lanonly.md

- Name: privacy
  - Scope: networking
  - Type/Default: boolean | off
  - Description: Enhance privacy of ICE candidates/addresses where supported.
  - Source: advanced-settings/turn-and-stun-parameters/and-privacy.md

- Name: tcp | and-tcp; icefilter
  - Scope: networking
  - Type/Default: boolean/list | off
  - Description: Restrict candidate types or prefer TCP-only flows; filter ICE candidates.
  - Source: general-settings/and-tcp.md, general-settings/and-icefilter.md




# Source Parameters

Name: push | id | permaid
- Scope: source
- Type/Default: string | auto‑generated if not set via UI
- Description: Declares the stream ID for publishing. If omitted, guests auto‑generate one and URL updates include `&push`.
- Interactions: `&password`, `&label`, device and encoding settings.
- Examples: `?push=GUEST123`
- Source: main.js search: `session.permaid = urlParams.get("push")`

Name: videodevice | vdevice | vd | device | d | vdo
- Scope: source
- Type/Default: string/number | 1 (default camera)
- Description: Selects camera by label/index; supports `0/false/off` to disable video.
- Interactions: `&width/&height`, `&frameRate`, facing mode on mobile.
- Examples: `?vdevice=Logitech`, `?vdo=0`
- Source: main.js block near video device parsing

Name: audiodevice | adevice | ad | device | d | ado
- Scope: source
- Type/Default: string/list/index | 1 (default mic)
- Description: Selects microphone(s) by label/index; supports comma‑separated list, `0/false/off` disables.
- Interactions: Echo/noise cancellation, stereo, mixdown.
- Examples: `?adevice=USB+Mic`, `?ado=Line+In,USB+Mic`
- Source: main.js search: `session.audioDevice = urlParams.get("audiodevice")`

Name: facing
- Scope: source (mobile)
- Type/Default: string | false
- Description: Hints front/back camera selection on mobile devices.
- Interactions: `&vdevice` may override.
- Examples: `?facing=user` or `?facing=environment`
- Source: main.js search: `session.facingMode = urlParams.get("facing")`

Name: width | w; height | h
- Scope: source
- Type/Default: number | device default
- Description: Capture constraint hints for resolution.
- Interactions: `&frameRate`, `&bitrate`, device capability; browser may downscale.
- Examples: `?width=1280&height=720`
- Source: main.js search: `session.width = urlParams.get("width")`

Name: frameRate | fr | fps
- Scope: source
- See global page for details.

Name: screenshare | ss; smallshare | smallscreen
- Scope: source
- Type/Default: boolean | off
- Description: Enables display/window/tab capture; `smallshare` suppresses notify banner.
- Interactions: `&audiodevice` for system audio; browser permissions.
- Examples: `?push=ID&screenshare`
- Source: main.js search: `screensharesupport` and related flags

Name: preview | showpreview | nopreview | np | minipreview | mini | largepreview | minipreviewoffset | mpo
- Scope: source UI
- Type/Default: boolean/number | varies
- Description: Controls pre‑publish local preview visibility and size.
- Interactions: Autostart, mobile constraints, OBS/browser differences.
- Examples: `?minipreview=1`, `?nopreview`
- Source: main.js search: `session.nopreview`, `session.minipreview`

Mute/Unmute at Source
- Name: mute | muted | m
  - Scope: source
  - Type/Default: boolean | off
  - Description: Start with microphone muted.
  - Source: main.js search around `urlParams.has("mute")`.

- Name: videomute | videomuted | vm
  - Scope: source
  - Type/Default: boolean | off
  - Description: Start with camera video muted.
  - Source: main.js search around `urlParams.has("videomute")`.

Name: autostart | autojoin | aj | as

Additional Source/Session Controls
- Name: nopush | viewonly | viewmode
  - Scope: source
  - Type/Default: boolean | off
  - Description: Disable publishing and join in view-only mode for test/monitoring.
  - Source: main.js search: `nopush`, `viewonly`, `viewmode`

- Name: maxconnections | mc; maxviewers
  - Scope: source
  - Type/Default: number | unlimited
  - Description: Limit number of peer connections/viewers from this publisher.
  - Source: source-settings/and-maxconnections.md, source-settings/and-maxviewers.md

- Name: queuetransfer | queue | audience
  - Scope: room/director
  - Type/Default: boolean/number | off
  - Description: Enable audience/queue flows, including transfer of queued guests to the stage.
  - Source: general-settings/queue.md, advanced-settings/settings-parameters/and-queuetransfer.md

- Name: allowedscenes
  - Scope: director/room
  - Type/Default: list | all
  - Description: Restrict which scenes a guest may appear in; useful in director workflows.
  - Source: advanced-settings/settings-parameters/and-allowedscenes.md

- Name: framegrab
  - Scope: source
  - Type/Default: string (image URL) | none
  - Description: Publishes a still-image based source using a frameshare pipeline. Loads the image and exposes it as a video stream; useful for slates/standby.
  - Examples: `?framegrab=https://example.com/standby.png`
  - Source: main.js search: `session.publishFrameSource`; lib.js `CanvasStreamSource`.

- Name: overlayimage | overlayimg | userforegroundimage
  - Scope: source/viewer
  - Type/Default: URL | none
  - Description: Overlay a foreground image above the video; useful for logos/watermarks. Accepts direct URLs.
  - Examples: `?overlayimg=https://example.com/logo.png`
  - Source: main.js search: `userforegroundimage`/`overlayimage`/`overlayimg` handling.

Sensors
- Name: sensors | sensor; gyro | gyros | accelerometer
  - Scope: source/global
  - Type/Default: number (Hz) | 30
  - Description: Enable sensor data capture (orientation/position/gyro/accel) and set update rate.
  - Source: main.js/webrtc.js/lib.js search: `session.sensorData`.

- Name: sensorfilter | sensorsfilter | filtersensor | filtersensors
  - Scope: source/global
  - Type/Default: CSV list | all
  - Description: Limit which sensor streams send (e.g., `pos,lin,ori,mag,gyro,acc`).
  - Source: main.js/webrtc.js search: `session.sensorDataFilter`.

Mic‑Only Option
- Name: miconlyoption | moo
  - Scope: source UI
  - Type/Default: boolean | off
  - Description: Expose a “mic‑only” option in UI for simplified audio‑only publishing.
  - Source: main.js search: `optionalMicOnly`.
- Scope: source
- Type/Default: boolean | off
- Description: Auto‑start publishing (and screenshare) without additional clicks.
- Interactions: `&consent` shows director control notice; browser autoplay policies may still gate audio.
- Examples: `?push=ID&autostart`
- Source: main.js search: `session.autostart = true`
- Name: feedbackbutton | fb
  - Scope: source UI
  - Type/Default: number (%) | none
  - Description: Adds a UI button to locally unmute and hear your own mic at a given percentage; sets tooltips accordingly.
  - Source: main.js search: `unmuteSelf`, `session.selfVolume`

Diagnostic Push Flags
- Name: pusheffectsdata
  - Scope: source/diagnostics
  - Type/Default: boolean | off
  - Description: Enable pushing effects data to connected peers/IFRAME for diagnostics.
  - Source: main.js search: `session.pushEffectsData`

- Name: pushloudness | getloudness
  - Scope: source/diagnostics
  - Type/Default: boolean | off
  - Description: Push audio loudness metering for remote monitoring.
  - Source: main.js search: `session.pushLoudness`

- Name: pushfaces | getfaces
  - Scope: source/diagnostics
  - Type/Default: boolean | off
  - Description: Push face detection data to connected peers/IFRAME where supported.
  - Source: main.js search: `session.pushFaces`




# Video Capture & Constraints

Name: videodevice | vdevice | vd | vdo
- Scope: source
- Type/Default: string/index | 1
- Description: Select camera by label/index; `0/false/off` disables.
- Source: `main.js` (video device parsing section).

Name: width | w; height | h; frameRate | fr | fps; maxframerate | mfr | mfps
- Scope: source
- Type/Default: number | device/browser defaults
- Description: Capture constraints and caps. Actual values depend on device and browser negotiation.
- Source: `main.js` search: `session.width`, `session.height`, `session.frameRate`, `session.maxframeRate`.

Name: codec | codecs | videocodec
- Scope: source
- Type/Default: string | auto
- Description: Preferred codec hint (h264/vp9/av1/hevc|h265) subject to support. Notes:
  - HEVC/H.265: Safari commonly supports HEVC encode/decode; modern Chrome builds can decode HEVC natively on many platforms. Chrome HEVC encode is still limited; don’t assume Chrome can publish HEVC.
  - Negotiation picks the first mutually supported codec regardless of hint if encode/decode are not available.
- Source: `main.js` search: `session.codecs`.

Name: videobitrate | bitrate | vb; maxvideobitrate | maxbitrate | maxvb | mvb; outboundvideobitrate | outboundbitrate | ovb
- Scope: source
- Type/Default: kbps | defaults vary; 8000 typical starting point
- Description: Target and cap video bitrate; outbound variants affect sender encoder directly.
- Source: `main.js` search: `session.bitrate`, `session.maxvideobitrate`, `session.outboundVideoBitrate`.

Name: obsfix
- Scope: viewer
- Type/Default: boolean/number | 1
- Description: Apply workarounds for OBS browser source playback quirks; numeric levels for intensity.
- Source: `main.js` search: `session.obsfix`.

Name: preview | showpreview | nopreview | np | minipreview | mini | largepreview | minipreviewoffset | mpo
- Scope: source UI
- Description: Control local preview size/visibility and offset.
- Source: `main.js` search: `session.nopreview`, `session.minipreview`, `session.leftMiniPreview`.

Name: screenshare | ss; smallshare | smallscreen

Screen Share Tuning
Name: aspectratio | ar
- Scope: source (camera capture)
- Type/Default: number/string | auto
- Description: Force camera capture aspect ratio. Accepts numbers (e.g., 1, 1.0, 1.333, 1.777), or keywords `portrait` (9/16), `landscape` (16/9), `square` (1/1). Parsed to a float.
- Examples: `?push=ID&aspectratio=1.333`, `?ar=portrait`
- Source: main.js search: `session.forceAspectRatio`.

Name: screenshareaspectratio | ssar
- Scope: source (screen share capture)
- Type/Default: number/string | 16/9
- Description: Force screen share capture aspect ratio to a ratio or keyword (`portrait`/`landscape`/`square`).
- Examples: `?push=ID&ssar=1.777`, `?screenshareaspectratio=square`
- Source: main.js search: `session.forceScreenShareAspectRatio`.
- Name: screensharetype; displaysurface
  - Scope: source
  - Type/Default: string | browser default
  - Description: Hint the share surface type (tab/window/screen) or direct display surface constraints when supported.
  - Source: newly-added-parameters/and-screensharetype.md; advanced-settings/screen-share-parameters/and-displaysurface.md

- Name: screensharecontenthint
  - Scope: source
  - Type/Default: string | motion/text
  - Description: Set content hint (e.g., motion vs text) to guide encoder/scaler.
  - Aliases: sscontenthint; screensharecontenttype; sscontent; sshint
  - Source: main.js search: `screensharecontenthint`, `sscontenthint`, `screensharecontenttype`, `sscontent`, `sshint`.

- Name: contenthint | contenttype | content | hint
  - Scope: source (camera capture)
  - Type/Default: string | `detail`
  - Description: WebRTC content hint for the camera track. Common values: `detail` (text), `motion` (video).
  - Source: main.js search: `session.contentHint`.

- Name: audiocontenthint | audiocontenttype | audiocontent | audiohint
  - Scope: source (audio capture)
  - Type/Default: string | `music`
  - Description: WebRTC content hint for the audio track. Common values: `speech`, `music`.
  - Source: main.js search: `session.audioContentHint`.

- Name: prefercurrenttab; selfbrowsersurface
  - Scope: source
  - Type/Default: boolean | off
  - Description: Prefer the current tab when starting capture; allow capturing the app’s own tab surface where supported.
  - Source: advanced-settings/screen-share-parameters/and-prefercurrenttab.md; advanced-settings/screen-share-parameters/and-selfbrowsersurface.md

- Name: sharperscreen
  - Scope: source
  - Type/Default: boolean | off
  - Description: Bias capture and scaling toward sharp text rendering for screen shares.
  - Source: advanced-settings/screen-share-parameters/and-sharperscreen.md

- Name: systemaudio
  - Scope: source
  - Type/Default: boolean | off
  - Description: Request system/application audio with screen share where supported.
  - Source: advanced-settings/screen-share-parameters/and-systemaudio.md

- Name: screensharebitrate | ssbitrate
  - Scope: source (screen share)
  - Type/Default: kbps | 2500
  - Description: Target bitrate specifically for the screen-share track.
  - Examples: `?screensharebitrate=3500`
  - Source: main.js search: `session.screenShareBitrate`.

Encoder Hints
- Name: h264profile
  - Scope: source
  - Type/Default: string | auto
  - Description: Request an H.264 profile (e.g., baseline/main/high) when using H.264.
  - Source: newly-added-parameters/and-h264profile.md

- Name: screensharestyle | ssstyle
  - Scope: source (screen share)
  - Type/Default: number | 1
  - Description: Selects a screenshare styling preset for layout/composition of the shared surface.
  - Source: main.js search: `session.screenshareStyle`.

Viewer Display for Screen Share
- Name: screensharelabel | sslabel
  - Scope: source/viewer
  - Type/Default: string | empty
  - Description: Label shown for screen-share stream tiles; can be used to differentiate content.
  - Source: main.js/lib.js search: `session.screenShareLabel`.

- Name: screensharecursor | cursor
  - Scope: source/viewer
  - Type/Default: boolean | off
  - Description: Show the mouse cursor in the screen-share capture when supported.
  - Source: main.js search: `session.screensharecursor`.

- Name: screensharevideoonly | ssvideoonly | ssvo
  - Scope: source/viewer
  - Type/Default: boolean | off
  - Description: Hide the camera tile and show only the screen-share video.
  - Source: main.js/lib.js search: `session.screenshareVideoOnly`.

- Name: screensharefps | ssfps
  - Scope: source
  - Type/Default: number (fps) | 2
  - Description: Set a target frame rate for the screenshare track.
  - Source: main.js search: `session.screensharefps`.

- Name: screensharequality | ssq
  - Scope: source
  - Type/Default: preset/number | 0
  - Description: Quality preset for screenshare resolution/scale. Accepts `4k/2160p/2160=-2`, `2k/1440p/1440=-3`, `fullhd/1080p/1080/high=0`, `720p/720/hd=1`, `360p/360/low=2`, or a number.
  - Source: main.js search: `session.screensharequality`.

- Name: screenshareid | ssid
  - Scope: source
  - Type/Default: string | `<streamID>_ss`
  - Description: Override the stream ID used for the screenshare track; sanitized by the app.
  - Source: main.js search: `session.screenshareid`.

- Name: sspaused | sspause | ssp
  - Scope: source
  - Type/Default: boolean | off
  - Description: Start a screenshare in a paused state.
  - Source: main.js search: `session.screenShareStartPaused`.

Video Effects & Tuning
- Name: flip
  - Scope: source/viewer
  - Type/Default: boolean | on
  - Description: Mirror‑flip the local video horizontally (off with `&flip=0/false/off`).
  - Source: main.js search: `urlParams.has("flip")`.

- Name: digitalzoom
  - Scope: source
  - Type/Default: number | 1
  - Description: Set initial digital zoom level when using the Zoom effect; value becomes the default `effectvalue`.
  - Source: main.js search: `digitalzoom`.

- Name: whitebalance | wb; exposure; saturation; sharpness; contrast; brightness
  - Scope: source
  - Type/Default: string/number | device/browser dependent
  - Description: Request camera property adjustments where supported by the device driver. Effect depends on hardware/browser.
  - Source: main.js search: `whitebalance`, `exposure`, `saturation`, `sharpness`, `contrast`, `brightness`.
- Scope: source
- Description: Display/window/tab capture; `smallshare` hides banner.
- Source: `main.js` search for screenshare flags and `screensharesupport`.
Screen Share Surface
- Name: surfaceswitching
  - Scope: source
  - Type/Default: boolean | on
  - Description: Allow switching surfaces (tab/window/screen) without renegotiation where supported.
  - Source: lib.js search: `constraints.surfaceSwitching`.




# Audio Processing & Routing

Name: stereo | s | proaudio; mono; channelcount | ac | inputchannels; monomic
- Scope: source/viewer
- Type/Default: mixed; see below
- Description: Controls channel layout and pro‑audio mode.
- Behavior:
  - `stereo` values map to modes: 0=mono, 1=stereo, 2=in, 3=out/mono, 4=quad/multi, 5=guest profile, 6=5.1, 8=7.1.
  - `mono` forces mono and may set `audiobitrate=128` depending on prior state.
  - `channelcount` sets input channel count; `monomic` forces 1.
- Interactions: Enabling stereo disables `echoCancellation`, `autoGainControl`, and `noiseSuppression`.
- Examples: `?push=ID&stereo=1`, `?push=ID&mono`, `?push=ID&channelcount=2`
- Source: `main.js` search: `session.stereo`, `session.mono`, `session.audioInputChannels`.

Name: screensharestereo | sss | ssproaudio
- Scope: source (screenshare)
- Type/Default: mixed; see mapping above
- Description: Same as `stereo` but for screen-share capture audio routing and channel mode.
- Source: `main.js` search: `session.screenshareStereo`.

Name: echocancellation | aec | ec
- Scope: source
- Type/Default: boolean | browser default
- Description: Toggle echo cancellation on mic input.
- Interactions: Disabled automatically when stereo/pro‑audio modes are used.
- Examples: `?push=ID&ec=false`
- Source: `main.js` search: `session.echoCancellation`.

Name: noaudioprocessing | noap
- Scope: source
- Type/Default: boolean | off
- Description: Disable browser audio processing (AEC/AGC/Denoise) for a raw input path.
- Source: main.js search: `noaudioprocessing`.

Name: autogain | ag | agc
- Scope: source
- Type/Default: boolean | browser default
- Description: Toggle automatic gain control on mic input.
- Source: `main.js` search: `session.autoGainControl`.

Name: denoise | dn; voiceisolation | vi | isolation
- Scope: source
- Type/Default: boolean | browser default
- Description: Toggle noise suppression and platform voice isolation.
- Source: `main.js` search: `session.noiseSuppression`, `session.voiceIsolation`.

Name: screenshareaec | ssec | ssaec; screenshareautogain | ssag | ssagc; screensharedenoise | ssdn
- Scope: source (screenshare)
- Type/Default: boolean | browser default
- Description: Apply AEC/AGC/Denoise to screen-share audio path.
- Source: `main.js` search: `session.screenshareAEC`, `session.screenshareAutogain`, `session.screenshareDenoise`.

Name: audiobitrate | ab; outboundaudiobitrate | oab
- Scope: source
- Type/Default: kbps | auto; `oab` as encoder hint
- Description: Control Opus target bitrate; iOS disables custom bitrates.
- Source: `main.js` search: `session.audiobitrate`, `session.outboundAudioBitrate`.

Name: playchannel
- Scope: viewer
- Type/Default: number | none
- Description: Selects which output channel to playback locally.
- Source: `main.js` search: `session.playChannel`.

Name: panning | pan; latency | al | audiolatency; micdelay | delay | md
- Scope: viewer/source
- Type/Default: boolean/number
- Description: Spatialize audio, add playout latency, or delay mic input.
- Source: `main.js` search: `session.panning`, `session.audioLatency`, `session.micDelay`.

Name: deafen | deaf; mutespeaker | sm | ms | speakermute
- Scope: viewer
- Type/Default: boolean | off
- Description: Disable or mute local playback.
- Source: `main.js` search lines around 1582–1630.

Additional Audio Controls
- Name: audiogain | gain | g | muteguest | volume
  - Scope: source
  - Type/Default: number (dB or normalized) | auto
  - Description: Manually adjust mic gain prior to encode; pairs with `autogain` (AGC) when disabled.
  - Source: advanced-settings/audio-parameters/and-audiogain.md

- Name: compressor | comp
  - Scope: source
  - Type/Default: boolean | off
  - Description: Enable a dynamics compressor on the microphone path.
  - Source: main.js search: `compressor`/`comp`.

- Name: samplerate | sr; outboundsamplerate | obsr; micsamplerate | msr; micsamplesize
  - Scope: source
  - Type/Default: number | 48000 Hz; size 16-bit
  - Description: Override mic capture/output sample rate and sample size, subject to device/browser limits.
  - Source: main.js search: `micsamplerate`, `micsamplesize`

- Name: audiocodec
  - Scope: source
  - Type/Default: string | opus
  - Description: Select publishing audio codec. Supported cases include `opus` (default), `red`, `lyra`, `pcm` (where available). Value is lowercased.
  - Interactions: `red`/`lyra` may alter FEC/RED behavior. Viewer preference (`preferaudiocodec`) can also influence negotiation.
  - Examples: `?audiocodec=red`, `?audiocodec=lyra`
  - Source: main.js search: `session.audioCodec`.

- Name: preferaudiocodec
  - Scope: interop
  - Type/Default: string | opus
  - Description: Request a preferred audio codec where supported.
  - Source: advanced-settings/audio-parameters/and-preferaudiocodec.md

- Name: dtx | usedtx; cbr | vbr
  - Scope: source
  - Type/Default: boolean | off (DTX); CBR off by default
  - Description: Enable Opus Discontinuous Transmission; enabling `dtx` disables `cbr` automatically. `&cbr` forces constant bitrate; `&vbr` explicitly disables CBR.
  - Source: main.js search: `session.dtx`, `session.cbr`.

- Name: ptime; minptime; maxptime
  - Scope: source
  - Type/Default: ms | `ptime` default 20; min 10, max 300
  - Description: Control Opus packetization time and bounds. Browser may clamp to supported ranges.
  - Source: main.js search: `session.ptime`, `session.minptime`, `session.maxptime`.

FEC/ACK Controls
- Name: fecaudio; pfecaudio; nofec
  - Scope: interop/audio
  - Type/Default: boolean | off
  - Description: Enable Opus FEC/RED parameters; `pfecaudio` toggles partial FEC; `nofec` disables.
  - Source: main.js search: `session.fecAudio`, `session.pfecAudio`, `session.noFEC`.

- Name: nonack | nonacks
  - Scope: interop
  - Type/Default: boolean | off
  - Description: Disable NACKs on the connection where supported.
  - Source: main.js search: `nonacks`.

Playback Constraints
- Name: suppresslocalaudio
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Request suppressed local audio playback where supported by the browser (experimental constraint).
  - Source: lib.js search: `suppressLocalAudioPlayback`.

- Name: noisegatesettings
  - Scope: director/scene
  - Type/Default: list | implementation default
  - Description: Fine-tune noise gate thresholds/attack/hold; used with `noisegate`.
  - Source: main.js search: `noisegatesettings`

- Name: nodirectoraudio
  - Scope: room/director
  - Type/Default: boolean | off
  - Description: Prevent director audio from being injected to program/guests.
  - Source: advanced-settings/audio-parameters/and-nodirectoraudio.md

- Name: channeloffset
  - Scope: viewer
  - Type/Default: number | 0
  - Description: Offset output channel mapping; helpful with multichannel workflows.
  - Source: advanced-settings/audio-parameters/and-channeloffset-1.md




# Viewer Parameters

Name: view | v | streamid | pull
- Scope: viewer
- Type/Default: string/list | none
- Description: Comma‑separated stream IDs to subscribe to. `:s` suffix whitelists screenshares only.
- Interactions: `&include` adds IDs; director/scene links compose views.
- Examples: `?view=ID1,ID2:s`
- Source: main.js search: `session.view = urlParams.get("view")`

Name: include
- Scope: viewer
- Type/Default: list | none
- Description: Adds allowed streams on top of `&view`.
- Examples: `?view=ID1&include=ID2,ID3`
- Source: main.js search: `if (urlParams.has("include"))`

Name: buffer | buffer2; sync
- Scope: viewer
- See global page for details.

Name: stats
- Scope: viewer
- See global page for details.

Name: mutespeaker | sm | ms | speakermute | speakermuted
- Scope: viewer
- Type/Default: boolean | on
- Description: Starts with local audio playback muted; useful for headless/monitor contexts.
- Examples: `?view=ID&mutespeaker`
- Source: main.js search: `urlParams.get("mutespeaker")`

Name: deafen | deaf
- Scope: viewer
- Type/Default: boolean | off
- Description: Disables audio playback entirely.
- Examples: `?view=ID&deafen`
- Source: see general settings docs; enforced in audio path

Name: cleanviewer | cv; cleanoutput | clean | cleanish
- Scope: viewer/global
- Type/Default: boolean | off
- Description: Hides UI elements; better for embedding and program feeds.
- Examples: `?view=ID&cleanviewer`
- Source: main.js search: `session.cleanViewer`, `session.cleanOutput`

Name: hideheader | noheader | hh; showheader
- Scope: viewer/global
- Type/Default: boolean | hide by default in some clean modes
- Description: Hide or force-show the header bar. `hideheader/noheader/hh` hides; `showheader` forces it visible.
- Examples: `?view=ID&hideheader`, `?showheader`
- Source: main.js search around header handling.

Name: showcontrols | videocontrols | forcecontrols | nocontrols
- Scope: viewer
- Type/Default: boolean | off
- Description: Toggle native player controls; `forcecontrols` re‑applies periodically.
- Examples: `?view=ID&showcontrols`, `?forcecontrols`
- Source: main.js search: `session.showControls`
- Name: showconnections
- Scope: viewer
- Type/Default: boolean | off
- Description: Shows remote guest connection counts in stats.
- Source: main.js search: `session.showConnections`

Name: fullscreenbutton | fsb | nofullscreenbutton | nofsb
- Scope: viewer/global
- Type/Default: boolean | off
- Description: Show or hide the page-level fullscreen toggle. Hidden on iOS/iPadOS. `nofsb` suppresses it.
- Examples: `?view=ID&fsb`, `?nofsb`
- Source: main.js search: `session.fullscreenButton`.

Name: nocontrolbar | nocontrolbarspace
- Scope: viewer
- Type/Default: boolean | off
- Description: Hide the control bar UI. `nocontrolbarspace` also removes its reserved layout space for tighter embedding.
- Examples: `?view=ID&nocontrolbarspace`
- Source: main.js search: `nocontrolbar`, `gridlayout.classList.add("nocontrolbar")`.

Name: nocursor | hidecursor | nomouse | hidemouse
- Scope: viewer
- Type/Default: boolean | off
- Description: Hide the mouse cursor over the video element(s); useful for program feeds and kiosk modes.
- Examples: `?view=ID&nocursor`
- Source: main.js search: `session.nocursor`.

Name: clock | clock24
- Scope: viewer
- Type/Default: boolean | off (24h when `clock24` used)
- Description: Show on-screen clock; `clock24` enables 24‑hour format.
- Examples: `?view=ID&clock24`
- Source: main.js search: `session.clock24`.

Closed Captions
- Name: closedcaptions | captions | cc
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Enable on-screen closed captions rendering, where available.
  - Source: main.js search: `session.closedCaptions`.

- Name: nocaptionlabels | nocclabels | nocaptionlabel | nocclabel
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Hide speaker labels in closed captions.
  - Source: main.js search: `session.nocaptionlabels`.

- Name: cccolor | cccolored | cccoloured | coloredcc | colorcc
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Colorize caption lines per speaker.
  - Source: main.js/lib.js search: `session.ccColored`.

Name: statsinterval
- Scope: viewer
- Type/Default: ms | 3000
- Description: Interval for requesting remote stats updates displayed in overlays/menus.
- Examples: `?view=ID&statsinterval=5000`
- Source: main.js search: `session.statsInterval`.

Name: autohide
- Scope: viewer/global
- Type/Default: boolean | off
- Description: Hide major UI chrome when not in use (kiosk/clean layouts); interacts with `cleanviewer/cleanoutput`.
- Source: main.js/webrtc.js search: `session.autohide`.

Name: automute | am
- Scope: viewer
- Type/Default: boolean/string | off
- Description: Start with local audio playout muted; a non-"2" value allows unmute on interaction. Used for autoplay policy compliance.
- Source: main.js/lib.js search: `session.automute`.

Name: outputdevice | od | audiooutput
- Scope: viewer
- Type/Default: string (device label substring) | default
- Description: Selects audio output device by matching a substring of the device label. Requires speaker selection support; falls back gracefully if not permitted.
- Examples: `?view=ID&audiooutput=Headphones`, `?od=VB-Audio`
- Source: main.js search: `session.outputDevice`.

Name: sink
- Scope: viewer
- Type/Default: deviceId | default
- Description: Set audio output device by exact deviceId (advanced); complements `outputdevice` (label matching).
- Examples: `?view=ID&sink=1234abcd`
- Source: main.js search: `session.sink`.

Name: forcelandscape | forcedlandscape | fl; forceportrait | forcedportrait | fp
- Scope: viewer/mobile
- Type/Default: boolean | off
- Description: Locks page orientation for better fullscreen playback on mobile. On Firefox, also forces fullscreen to simplify orientation.
- Examples: `?view=ID&forcelandscape`, `?fp`
- Source: main.js search: `session.orientation`.

Name: forceviewerlandscape; forceviewerportrait
- Scope: viewer
- Type/Default: number (deg) | 270 and 90 respectively if no value
- Description: Keeps incoming videos displayed in landscape or portrait by rotating them. Values are degrees if provided.
- Examples: `?view=ID&forceviewerlandscape=270`, `?forceviewerportrait=90`
- Source: main.js search: `session.keepIncomingVideosInLandscape`, `session.keepIncomingVideosInPortrait`.

Name: rotatewindow; rotatepage
- Scope: viewer
- Type/Default: degrees | 90
- Description: Rotates the window or entire page render by a set angle.
- Examples: `?view=ID&rotatepage=180`
- Source: main.js search: `rotatewindow`, `rotatepage`.

Playback Aspect Ratio
- Name: portrait | 916 | vertical; square | 11; 43
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Forces playback layout aspect ratio (9:16, 1:1, or 4:3) for the tile layout; useful for signage and vertical video.
  - Source: main.js search: `session.aspectRatio`.

Name: overlaycontrols
- Scope: viewer
- Type/Default: boolean | off
- Description: Show overlay controls on the viewer UI for quick access.
- Source: main.js search: `session.overlayControls`.

Name: overlayimg | overlayimage | userforegroundimage
- Scope: viewer
- Type/Default: URL | none
- Description: Overlay a foreground image (logo/watermark) on the viewer composition when supported by the page layout.
- Examples: `?overlayimg=https://example.com/logo.png`
- Source: main.js search: `userforegroundimage`/`overlayimage`/`overlayimg`.

Theme & Styling
- Name: darkmode | nightmode | darktheme; lightmode | lighttheme; whitemode | whitetheme
  - Scope: viewer/global
  - Type/Default: boolean | inferred from theme variable
  - Description: Switch UI theme. `whitemode/whitetheme` adds a specific white theme class. Defaults vary by environment.
  - Source: main.js search: `session.darkmode`, theme toggles.

- Name: chroma
  - Scope: viewer
  - Type/Default: hex string | 0F0
  - Description: Set page background chroma key color (e.g., `&chroma=000` for black).
  - Source: main.js search: `getById("main").style.backgroundColor`.

- Name: margin
  - Scope: viewer
  - Type/Default: number (px) | 10
  - Description: Adjust video tile margins.
  - Source: main.js search: `session.videoMargin`.

- Name: rounded | round
  - Scope: viewer
  - Type/Default: number (px) | 50
  - Description: Border radius for tiles (CSS variable `--video-rounded`).
  - Source: main.js search: `--video-rounded`.

- Name: holdercolor | videobg | videobgcolor | videobackground | videobackgroundcolor | holderbg | holderbgcolor
  - Scope: viewer
  - Type/Default: hex | #000
  - Description: Background color of the video holder behind/around video tiles (CSS variable `--video-holder-color`). This does not change the whole page background or pixels inside the video stream.
  - Source: main.js search: `--video-holder-color`.

- Name: menuoffset
  - Scope: viewer
  - Type/Default: CSS length | 50px
  - Description: Adjusts the bottom offset of the controller UI.
  - Source: main.js search: `menuoffset`.

- Name: userbackgroundimage | userbgimage | ubgimg; bgimage | bgimage2 | bgimage3 | bgimg*
  - Scope: viewer/global
  - Type/Default: URL | defaults set to local assets
  - Description: Set background images (general, talking, and screaming states) via CSS variables; use `avatarimg*` aliases as well to set background placeholders.
- Source: main.js search: `userbackgroundimage`, `bgimage*`, `avatarimg*`.

- Name: imagelist
  - Scope: viewer
  - Type/Default: JSON‑encoded array/URL | none
  - Description: Provide a list (JSON or single URL) of background images to use as defaults.
  - Source: main.js search: `imagelist`.

UI Sliders & Meters
- Name: showslider
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Show bitrate/control sliders in supported views.
  - Source: webrtc.js search: `session.showSlider`.

- Name: signalmeter
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Show CPU/signal meter overlays on tiles.
  - Source: webrtc.js search: `signalMeter`.

- Name: showmeta
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Show extra metadata overlays (diagnostic info) on tiles.
  - Source: main.js search: `session.showmeta`.

Scene Slots
- Name: slotslist
  - Scope: viewer/scene
  - Type/Default: CSV of slot indices | off
  - Description: Restrict scene processing to specific slot indices (e.g., `slotslist=0,2,4`). Empty/invalid list disables filter.
  - Source: main.js search: `session.slotsList`.

Playback Volume
- Name: volumecontrol | volumecontrols | vc
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Show UI for per‑tile playback volume control.
  - Source: main.js/webrtc.js search: `session.volumeControl`.

- Name: volume | vol
  - Scope: viewer
  - Type/Default: percent (0–100) | 100
  - Description: Default playback volume for new video elements.
  - Source: main.js search: `session.volume`.

Labels & Sorting
- Name: showlabels | showlabel | sl
  - Scope: viewer
  - Type/Default: boolean/string | off
  - Description: Show labels; optional style string is sanitized and applied.
  - Source: main.js search: `session.showlabels`, `session.labelstyle`.

- Name: sizelabel | labelsize | fontsize
  - Scope: viewer
  - Type/Default: percent | 100
  - Description: Scale label font size percentage (or accept CSS font-size for widgets that support it).
  - Source: main.js search: `session.labelsize`.

- Name: orderby
  - Scope: viewer
  - Type/Default: string | id
  - Description: Sort order for streams: `id` (default) or `label`.
  - Source: main.js search: `session.orderby`.

Raise Hand
- Name: hand | hands
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Enable “raise hand” controls/indicator for guests.
  - Source: main.js/lib.js search: `raisehand`, `hands`.

Device/Platform Tweaks
- Name: forceios; androidfix
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Apply iOS/Android playback/codec handling tweaks. `forceios` adjusts mobile playback rules; `androidfix` enables Android H.264 handling fix.
  - Source: main.js/webrtc.js search: `session.forceios`, `session.AndroidFix`.

Fonts (overlays/widgets)
- Name: font
  - Scope: overlays/widgets
  - Type/Default: string | inherited
  - Description: Override CSS font family for pages that honor `--font-family`. Use fonts helper at `source-code/fonts.html` to generate values.
  - Source: fonts.html search: `urlParams.get("font")`.

Misc UI/Playback
- Name: pauseinvisible
  - Scope: viewer
  - Type/Default: boolean | off
- Description: Pause playback when the page isn’t visible to reduce CPU usage.
- Source: main.js search: `session.pauseInvisible`.

- Name: zoomslider; ptzslider
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Show UI sliders to control zoom/PTZ where supported.
- Source: main.js search: `session.zoomSlider`, `session.ptzSlider`.

Slides & PPT
- Name: pptcontrols | slides | ppt | powerpoint
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Enable UI controls to remotely control slideshow/presentations where configured.
  - Source: main.js search: `session.pptControls`.

Picture-in-Picture
- Name: pip; pip2; pip3 | mypip | pipme; pipall
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Enable picture‑in‑picture for the main/selected video (`pip`), alternate modes (`pip2`, `pip3`/`mypip`/`pipme`), or apply to all where supported (`pipall`).
  - Source: main.js/webrtc.js search: `session.pip`, `session.pip3`.

- Name: hideusermenu | nousermenu | hum
  - Scope: viewer
  - Type/Default: boolean | off
- Description: Hide the user menu (three dots/gear) for kiosk/clean views.
- Source: main.js search: `hideusermenu`.

Visibility Toggles
- Name: hidevideo | showonly; hideaudio
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Suppress remote video or audio playback. `showonly` acts like `hidevideo` for non-target elements.
  - Source: main.js search: `novideo`/`hidevideo`, `noaudio`/`hideaudio`.

- Name: hidesolo | hs; hidescreenshare | hidess | sshide | screensharehide
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Hide solo button or screen-share controls/tiles in the UI.
  - Source: main.js search: `hidesolo`, `hidescreenshare`.

- Name: hidemenu | hm; hidetranslate
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Hide the bottom control menu or translate button.
  - Source: main.js search: `hidemenu`, `hidetranslate`.

Header & Buttons
- Name: headertitle
  - Scope: viewer
  - Type/Default: string | none
  - Description: Override page header title text.
  - Source: lib.js search: `headertitle`.

Stats Toggle
- Name: nostats
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Disable the stats menu/overlay regardless of `&stats`.
  - Source: main.js search: `nostats`.

- Name: hangupbutton | hub | humb64; hangupmessage | hum | humb64
  - Scope: viewer
  - Type/Default: boolean/string | off
  - Description: Add a hangup button and optional message (plain or base64). `humb64` can carry either the button label or message in base64.
  - Source: main.js search: `hangupbutton`, `hangupmessage`.

Director Visibility
- Name: nodirectorvideo
  - Scope: viewer/scene
  - Type/Default: boolean | off
  - Description: Suppress the director’s video in scenes or viewer playback.
  - Source: main.js/webrtc.js search: `session.nodirectorvideo`.

Layout Fit
- Name: cover; fit
  - Scope: viewer
  - Type/Default: boolean | off
  - Description: Control object-fit behavior of video tiles. `cover` scales to fill (may crop), `fit` contains within (may letterbox).
  - Source: main.js search: `cover`, `fit`.

- Name: batterymeter
  - Scope: viewer
  - Type/Default: boolean/string | auto
  - Description: Enable showing remote battery meter on tiles; accepts truthy/falsey values.
  - Source: main.js/webrtc.js search: `session.batteryMeter`.

- Name: tally; tallyoff | notally | disabletally | to
  - Scope: viewer/scene
  - Type/Default: boolean | off
  - Description: Enable or disable tally light indicators for live/on-deck states.
  - Source: main.js search: `tallyoff`, `tally`.

Custom CSS/JS Injection
- Name: css; cssb64 | cssbase64 | b64css | base64css
  - Scope: viewer/global
  - Type/Default: URL/base64 | none
  - Description: Inject external CSS by URL (`css=`) or inline base64‑encoded CSS (`cssb64`/`b64css` and aliases).
  - Source: main.js search: styles injection around 2209–2241.

- Name: b64js | base64js
  - Scope: viewer/global
  - Type/Default: base64 string | none
  - Description: Inject base64‑encoded JS blob; use with care (security implications).
  - Source: main.js search: `base64js`/`b64js`.

Name: showmutestatus | mutestatus | showmuted | showmutestate; showunmutestatus | unmutestatus | showunmuted | showunmutestate
- Scope: viewer/global
- Type/Default: boolean | off
- Description: Show a visible indicator when the local playout is muted or unmuted.
- Examples: `?view=ID&showmuted`, `?showunmuted`
- Source: main.js search: `session.showMuteState`, `session.showUnMuteState`.




# Room and Director Parameters

Name: director | dir
- Scope: director
- Type/Default: string/boolean | if boolean, director landing
- Description: Enters director mode for a given room name. Without a value, shows landing.
- Examples: `?director=myshow`, `?dir`
- Source: main.js search: `session.director = urlParams.get("director")`

Name: directorpassword | dirpass | maindirpass
- Scope: director/room
- Type/Default: string | none
- Description: Protect director access to a room with a password. `maindirpass` can designate a main password for elevated control.
- Source: webrtc.js search: `session.directorPassword`, `session.mainDirectorPassword`.

Name: codirector
- Scope: director/room
- Type/Default: string | none
- Description: Co‑director password token used in invite links or for joining as a co‑director. Equivalent to providing `&directorpassword`.
- Examples: `?dir=ROOM&codirector=SECRET`
- Source: main.js search: `urlParams.get("codirector")` → `session.directorPassword`.

Name: roomkey | rk
- Scope: director/room invite links
- Type/Default: string | none
- Description: Trusted bypass key for claim-time room admission controls; skips approval and room-cap checks when matched.
- Examples: `?room=ROOM&roomkey=TRUSTED_KEY`
- Source: main.js/webrtc.js/hss/gemini.js search: `roomkey`, `roomKey`, `bypassKey`.

Name: noclaim | noautoclaim | nonclaiming; claim=0
- Scope: director/co-director
- Type/Default: boolean | off
- Description: Join director mode without trying to claim the room as main director. Useful for co-director links.
- Examples: `?dir=ROOM&codirector=SECRET&noclaim`
- Source: main.js/webrtc.js search: `noRoomClaim`.

Name: directorsonly
- Scope: director/room
- Type/Default: boolean | off
- Description: Restrict access to the director interface to authorized users only.
- Source: main.js/webrtc.js; search: `directorsonly`.

Name: hidedirectors | hideusermenu
- Scope: director UI
- Type/Default: boolean | off
- Description: Hide co‑director listings or the user menu for a cleaner UI or kiosk use.
- Source: main.js; search these flags for DOM toggles.

Name: hidecodirector | hidecodirectors
- Scope: director UI
- Type/Default: boolean | off
- Description: Hide co‑director UI elements; aliases for the co‑director visibility toggle.
- Source: main.js search: `hidecodirectors`.

Name: hideguest
- Scope: director/viewer
- Type/Default: boolean | off
- Description: Hide the director’s video (or guest tile) from scenes; sets internal directorVideoMuted state.
- Source: main.js search: `hideguest`.

Name: queue | queuetransfer | audience
- Scope: room/director
- Type/Default: number/boolean | off
- Description: Enable audience/greenroom queueing behavior and transfer from queue to stage.
- Source: main.js search: `queuetransfer`; webrtc.js search: `session.queue` and queue handling.

Name: audience
- Scope: relay/rooms
- Type/Default: string/token | none
- Description: Enables audience listen/publish mode using dedicated audience WSS endpoints. Viewer endpoints adjust `session.wss` based on the token.
- Source: main.js/lib.js search: `session.audience`, `audience.vdo.ninja`.

Name: joinscene | joinscenes
- Scope: room/director
- Type/Default: boolean/list | off
- Description: Auto‑place or restrict a guest to specific scenes on join. Provide a list to limit allowed scenes.
- Source: lib.js and main.js (scene composition); `joinscene` flags.

Name: room | r | roomid
- Scope: room
- Type/Default: string | none
- Description: Selects room for guests, scenes, and director. Combine with `&password` to isolate realm.
- Examples: `?room=myshow&password=ROOMPASS`
- Source: main.js search: `roomid = urlParams.get("room")`

Name: codirector (invite via UI)
- Scope: director
- Type/Default: link with scoped permissions
- Description: Co‑director support with configurable permissions; link generated from director UI.
- Source: docs: `director-settings/codirector.md`

Name: scene | scn
- Scope: room/program
- Type/Default: number | 0
- Description: Program/compositor view within a room.
- Examples: `?scene&room=myshow`
- Source: main.js search: `session.scene = urlParams.get("scene")`

Name: showdirector | sd; directorview | dv; directoronly | do
- Scope: director/viewer
- Type/Default: boolean/number | varies
- Description: Show director video, enable director’s view overlay, or restrict view to director only.
- Examples: `?room=myshow&directorview`
- Source: main.js search: `session.showDirector`, `session.directorView`, `session.viewDirectorOnly`

Name: showdirector | sd (numeric semantics)
- Scope: director/viewer
- Type/Default: number/boolean | true
- Description: When present, shows director feed; value `2` restricts to video-only (no audio). Any truthy non-numeric enables video+audio.
- Source: main.js search: `session.showDirector`

Name: bitratecutoff | bitcut
- Scope: director/room
- Type/Default: kbps | 300
- Description: Threshold for low-bitrate cutoff used in director logic.
- Source: main.js search: `session.lowBitrateCutoff`

Name: motionswitch | motiondetection; motionrecord | recordmotion
- Scope: director/room
- Type/Default: number | 15
- Description: Motion detection threshold used to auto-switch scenes or start motion-based recording.
- Source: main.js search: `session.motionSwitch`, `session.motionRecord`

Name: locked
- Scope: director/room
- Type/Default: boolean/string | off
- Description: Locks certain room interactions; used by director UI to prevent changes.
- Source: main.js search: `session.locked = urlParams.get("locked")`
Name: roombitrate | roomvideobitrate | rbr; controlroombitrate | crb; minroombitrate | mrb
- Scope: director/room
- Type/Default: kbps | varies
- Description: Room‑wide bitrate targets and control behavior (min, control enable).
- Examples: `?room=myshow&roombitrate=2000&controlroombitrate`
- Source: main.js search: `session.roombitrate`, `session.controlRoomBitrate`

Name: slotmode | slotsmode
- Scope: director UI
- Type/Default: number | 1
- Description: Director slot layout behavior.
- Source: main.js search: `session.slotmode`




# Director & Layout Controls

Name: slotmode | slotsmode
- Scope: director UI
- Type/Default: number | 1
- Description: Controls how guests map to slots in the director interface.
- Source: `main.js` search: `session.slotmode`.

Name: activespeaker | speakerview | sas; activespeakerdelay | speakerviewdelay | sasdelay
- Scope: director/scene
- Type/Default: number | 1; delay ms | 0
- Description: Auto‑switch to active speaker; optional delay before switching.
- Source: `main.js` search: `session.activeSpeaker`, `session.activeSpeakerTimeout`.

Name: noisegate | gating | gate | ng; noisegatesettings
- Scope: director/scene
- Type/Default: number | 1; settings list
- Description: Quiet others and tune gate behavior.
- Source: `main.js` search: `session.quietOthers`, `session.noisegateSettings`.

MIDI & Hotkeys
- Name: midi | hotkeys; disablehotkeys
  - Scope: director/viewer
  - Type/Default: number/bool | off
  - Description: Enable MIDI/hotkey profile (1–N). `disablehotkeys` turns off keyboard shortcuts.
  - Source: main.js search: `session.midiHotkeys`, `disablehotkeys`.

- Name: midiremote | remotemidi
  - Scope: director
  - Type/Default: number | 1/4 depending on context
  - Description: Allow remote MIDI control channel bridging.
  - Source: main.js search: `session.midiRemote`.

- Name: midipush | midiout | mo; midipull | midiin | midin | mi
  - Scope: director
  - Type/Default: boolean/number | off/true
  - Description: Send (`midipush`/`midiout`) or receive (`midipull`/`midiin`) MIDI.
  - Source: main.js search: `session.midiOut`, `session.midiIn`.

- Name: midichannel; mididevice; mididelay; midioffset; midiiframe
  - Scope: director
  - Type/Default: varies | defaults in code
  - Description: MIDI routing channel/device selection, delay/offset adjustments, iframe mode.
  - Source: main.js/webrtc.js around the MIDI blocks.

- Name: timecode | tc | showtimecode
  - Scope: director
  - Type/Default: boolean/string | off
  - Description: Enable/show MIDI timecode overlay/state.
  - Source: main.js search: `session.midiTimecode`.
- Layout & Director Controls
- Name: layouts
  - Scope: director UI
  - Type/Default: string | auto
  - Description: Select built-in or custom layout presets via director UI/API.
  - Source: advanced-settings/director-parameters/and-layouts.md

- Name: layout; viewslot; updateonslotschange | uosc
  - Aliases: updateonslotchange
  - Scope: director/scene
  - Type/Default: object/index/bool | off
  - Description: Apply a specific layout JSON (`&layout=` raw/URL‑encoded or base64), force a specific `viewslot`, and control whether updates should apply on slot change (disable with `&uosc=false`).
  - Source: main.js search: `session.layout`, `session.viewslot`, `session.updateOnSlotChange`.

- Name: previewmode | pausepreview | hidecodirectors
  - Scope: director UI
  - Type/Default: boolean | off
  - Description: Control director preview behavior and visibility; manage co-director UI elements. Aliases include `hidecodirector` and `hidedirectors`.
  - Source: advanced-settings/director-parameters/and-previewmode.md, and-pausepreview.md, and-hidecodirectors.md

- Name: maindirectorpassword
  - Scope: director/room
  - Type/Default: string | none
  - Description: Set/require a main director password for elevated control.
  - Source: advanced-settings/director-parameters/and-maindirectorpassword.md

- Name: autoadd
  - Scope: director/scene
  - Type/Default: list | off
  - Description: Comma-separated stream IDs to auto-add to the scene as they connect.
  - Source: main.js/lib.js search: `session.autoadd`.

- Name: showdirector | sd; hidedirector | hidedirectors
  - Scope: director/scene
  - Type/Default: number/bool | 0
  - Description: Controls director presence in scenes: 0=none, 1=video+audio (no iframe/widgets), 2=video‑only, 3=screenshare‑only, 4=all. `hidedirector` forces director hidden.
  - Source: main.js/webrtc.js search: `session.showDirector`, application in scene rules.

- Name: inclusivelayoutaudio | exclusivelayoutaudio
  - Scope: director/scene
  - Type/Default: boolean | exclusive by default for `viewslot`
  - Description: Audio mixing policy for layout scenes; exclusive limits audio to visible slots vs inclusive mixes others.
  - Source: main.js search: `session.exclusiveLayoutAudio`.

Room Bitrate Controls
- Name: limittotalbitrate | ltb
  - Scope: director/room
  - Type/Default: kbps | disabled
  - Description: Limit total room video bitrate; visible in the director UI when active.
  - Source: main.js search: `limittotalbitrate`, `ltb`.

- Name: hiddenscenebitrate
  - Scope: director/room
  - Type/Default: kbps | 0
  - Description: Target bitrate used for hidden scene tiles when rendered offscreen.
  - Source: main.js/lib.js search: `hiddenSceneViewBitrate`.

- Name: lowbitratescene | cutscene
  - Scope: director/room
  - Type/Default: string | `cutscene`
  - Description: Lower bitrate policy on scene transitions to reduce load.
  - Source: main.js search: `lowBitrateSceneChange`.

- Name: totalroombitrate | totalroomvideobitrate | trb | totalbitrate | tb
  - Scope: director/room
  - Type/Default: kbps | default from session
  - Description: Set total room bitrate for all senders/viewers; director can adjust dynamically.
  - Source: main.js/webrtc.js search: `session.totalRoomBitrate`.

Room Timer (API)
- Tokens: timer; timeouts
  - Scope: director/room (API‑driven)
  - Description: Room timer is controlled via API/iframe commands (start/pause/stop). Not a URL parameter.
  - Source: lib.js search: `startRoomTimer`, `pauseRoomTimer`, `stopRoomTimer`.

- Name: totalscenebitrate | maxtotalscenebitrate | tsb | mtsb | totalbitrate | tb
  - Scope: director/room
  - Type/Default: kbps | none
  - Description: Set or cap the total scene bitrate budget; alias family of parameters.
  - Source: main.js search: `session.totalSceneBitrate`.

Groups
- Name: group | groups; groupview | viewgroup | gv; groupmode | gm
  - Scope: director/scene
  - Type/Default: string | empty
  - Description: Assign streams to named groups and set group view/mode for layout logic.
  - Source: main.js search: `session.group`, `session.groupView`, `session.groupMode`.

Scene Link Settings
- Name: scenelinkbitrate; scenelinkcodec
  - Scope: director/scene
  - Type/Default: kbps/string | none
  - Description: Hint total bitrate/codec to apply in generated scene links for downstream consumers.
  - Source: main.js search: `session.bitrateGroupFlag`, `session.codecGroupFlag`.

- Name: scenetype | type; openscene | openscenes
  - Scope: director/scene
  - Type/Default: number/bool | false
  - Description: Configure scene behavior and allow opening scenes via API/links.
  - Source: main.js/webrtc.js search: `session.sceneType`, `session.openscene`.

Limits and Publishers
- Name: maxpublishers | mp
  - Scope: room/director
  - Type/Default: number | unlimited
  - Description: Limit number of publishers/guests allowed to join.
  - Source: main.js search: `session.maxpublishers`.




# Iframe / Remote APIs

Remote Flag
- `&remote` enables remote stat access and limited control permissions for monitoring tools.

HTTP/WSS Remote Control API
- Parameter: `&api=KEY` (see docs `general-settings/api.md`).
- Use: A companion controller with the same API key may send commands to the session.

Iframe Integration
- PostMessage and DOM hooks allow embedding and control. Prefer using explicit `&remote` and API keys where applicable.

Notes
- Keep API keys secret; use realm/password and hash checks for public links.
- Some actions depend on user gesture or browser policy; remote commands cannot bypass autoplay/device permission gates.

Remote/OSC and Webhooks
- Name: api | osc
  - Scope: global
  - Type/Default: string | off
  - Description: Enables Remote/OSC control using the provided key/value. When set, the app initializes the OSC client shortly after load.
  - Source: main.js search: `session.api`, `oscClient()`

- Name: postapi | posturl
  - Scope: global
  - Type/Default: URL | off
  - Description: Sends JSON webhooks to the given endpoint with connection/stat events; expects HTTPS. Value is URL‑decoded by the app.
  - Source: main.js search: `session.postApi = decodeURI(session.postApi)`

Commands Quick Reference (from source)
- Message schema: postMessage/remote API payload supports `{ action, value?, value2?, target? }`.
  - action: string key (see below). value/value2: arguments; strings `"true"/"false"` normalized to boolean.
  - target: UUID or streamID when applicable; omit to apply to self or globally. Some actions accept `"*"` to apply to all.
  - Source: lib.js search: `processMessage`, `Commands`.

Session/media toggles
- mic | speaker | camera | video: boolean or `"toggle"`. Returns current state.
- hangup: ends the session.
- bitrate: number kbps (0=off, -1=auto) applied to all peers.
- volume: 0–100 percent (per WebAudio pipeline if active).
- reload: soft‑reload view.

Chat
- sendChat, sendChatMessage: send text to chat; showChatOverlay displays an overlay of a message.

Groups/scenes
- group/joinGroup/leaveGroup: add/remove from scene groups.
- viewGroup/joinViewGroup/leaveViewGroup: viewer group selection.
- soloVideo | highlight: toggle solo/infocus for the director.
- activeSpeaker: number (profile) or toggle; enables active‑speaker switching.

Room timer (director)
- startRoomTimer, pauseRoomTimer, stopRoomTimer: control director room timer (UI driven).

PTZ/zoom/camera control
- zoom | focus | pan | tilt | exposure: value (float) and optional value2 `true|"true"|"abs"` to set absolute; else relative.
- setAspectRatio: float or `"W:H"` (e.g., `"16:9"`). Applies camera constraint.
- videoConstraint: generic constraint setter; `value`=constraint name, `value2`=value (boolean/number supported).

Buffering & stats
- setBufferDelay: `value` ms; optional `value2` target `UUID|streamID|"*"`.
- getStats: return quick stats; getDetails: return detailed state; getGuestList: list of guests.

Slides / tally
- prevSlide, nextSlide: controls mapped via MIDI emulation.
- tallylight: values `onair|active|standby|off|false|0` or a number; overrides tally state.

Targeting/returns
- Most actions return the applied/updated state or `true` on success. Target may be a UUID or a streamID; where both apply, UUID takes precedence.

Notes
- Many of these actions have dedicated pages under `iframe-api/api-commands/`. This section reflects the live in‑code map (lib.js `setupCommands()`), which backs the Iframe API, the HTTP/WSS remote API, and UI integrations.




# Additional Interop & Relay

Name: whipview | whip; whippush | whipout | pushwhip; cftoken | cft
- Scope: interop
- Description: WHIP/WHEP ingress/egress controls for interop with streaming services; Cloudflare token helper.
- Interactions: `&noaudiowhipin`, `&novideowhipin`, `&whipwait`, `&whepwait`, `&endpage`.
- Source: main.js search: `whipClient`, `whipOutput`, `cftoken`
 - Source: main.js search: `whipClient`, `whipOutput`, `cftoken`

WHIP/WHEP Publishing Options
- Name: whipoutcodec | whipoutvideocodec | woc | wovc; whipoutaudiocodec | woac
  - Scope: interop (publish)
  - Type/Default: string/list | auto
  - Description: Set preferred codecs for WHIP output. Multiple video codecs can be provided comma‑separated. Firefox limits H.264 in some cases. Aliases include Meshcast forms: `mccodec` (video), and `mcab`/`mcaudiobitrate` for audio bitrate.
  - Source: main.js search: `session.whipOutCodec`, `session.whipOutAudioCodec`.

- Name: whipoutvideobitrate | wovb; whipoutaudiobitrate | woab
  - Scope: interop (publish)
  - Type/Default: kbps | none
  - Description: Target encoder bitrates for WHIP output. Aliases include `mcb`/`mcbitrate` (video) and `mcab`/`mcaudiobitrate` (audio) for Meshcast.
  - Source: main.js search: `session.whipOutVideoBitrate`, `session.whipOutAudioBitrate`.

- Name: whippushtoken | whippush; whepplaytoken | whepplay
  - Scope: interop (auth)
  - Type/Default: string | none
  - Description: Provide tokens for WHIP push and WHEP play endpoints where required.
  - Source: webrtc.js fields: `session.whipOutputToken` (whip push), `session.whepInputToken` (whep play).

- Name: whipoutkeyframe; whipoutkeyframenewviewer
  - Scope: interop (publish)
  - Type/Default: ms | none
  - Description: Force periodic keyframes for WHIP output, and/or trigger on new viewer joins (if supported by encoder).
  - Source: webrtc.js search: `session.whipOutKeyframe`, `session.whipOutKeyframeOnNewViewer`.

- Name: wossbitrate | wosscodec | woscale
  - Scope: interop (publish screenshare)
  - Type/Default: kbps/string/percent | defaults vary
  - Description: WHIP output controls specific to screen-share pipeline (bitrate, codec, scale factor). Aliases include Meshcast forms `mcscreensharebitrate`/`mcssbitrate` and `mcscreensharecodec`/`mcsscodec`.
- Source: main.js search: `whipoutscreensharebitrate`, `whipoutscreensharecodec`, `whipOutScale`.

Encryption & Data Channels
- Name: e2ee | insertablestreams | is
  - Scope: interop/security
  - Type/Default: boolean/string | off
  - Description: Enable Encoded Insertable Streams pipeline. `e2ee` selects end‑to‑end encryption mode; `insertablestreams`/`is` accept values like `lyra`/`e2ee` or `true`.
  - Source: main.js search: `session.encodedInsertableStreams`.

- Name: datamode | dataonly
  - Scope: interop/data
  - Type/Default: boolean | off
  - Description: Prefer/limit to datachannel‑only connectivity where supported.
  - Source: main.js search: `datamode`, `dataonly`.

Experimental & Misc
- Name: planb
  - Scope: interop
  - Type/Default: boolean | off
  - Description: Enable legacy SDP Plan B behavior where available.
  - Source: main.js search: `planb`.

- Name: resources
  - Scope: interop/data
  - Type/Default: list/bool | off
  - Description: Allow “resources” datachannel to send named resource items; accepts a CSV allowlist or true to allow all.
  - Source: main.js/webrtc.js/lib.js search: `resources`.

WHEP Host/Share
- Name: hostwhep | whepout
  - Scope: interop (WHEP host)
  - Type/Default: string | stream ID or false
  - Description: Host a WHEP endpoint for the current stream; uses provided value or stream ID.
  - Source: main.js search: `session.whepHost`.

- Name: whepshare | whepsrc; whepsharetoken | whepsrctoken
  - Scope: interop (WHEP advertise)
  - Type/Default: URL/token | none
  - Description: Advertise a remote WHEP playback URL to room peers via the data channel so viewers can switch to WHEP instead of P2P when allowed. Use with `&dataonly` to avoid publishing local A/V when the stream already exists elsewhere. Tokens are sent as `Authorization: Bearer ...`. If the URL value is blank, the UI prompts for it.
  - Source: main.js search: `whepshare`, `whepsrctoken`.

- Name: hearptsn
  - Scope: interop/voice
  - Type/Default: string (code) | none
  - Description: Join an audio listen path via a phone/telephony bridge (experimental).
  - Source: main.js search: `hearptsn`.

Posting Images (Experimental)
- Name: postimage; postinterval
  - Scope: interop/UX
  - Type/Default: URL; seconds | 60 (min 5)
  - Description: Periodically POST a captured image (JPEG) to a URL; `postinterval` controls the cadence.
  - Source: main.js search: `postimage`, `postinterval`.

Transcription
- Name: transcript | transcribe | trans
  - Scope: interop
  - Type/Default: string (locale) | en‑US
  - Description: Enable live transcription with a given locale code.
  - Source: main.js search: `session.transcript`.

Name: noaudiowhipin; novideowhipin
- Scope: interop
- Description: Force disable audio/video on WHIP ingest.
- Source: main.js search: `forceNoAudioWhipIn`

Name: whipwait | whipicewait; whepwait | whepicewait
- Scope: interop
- Description: ICE gather wait times (ms) before sending offers for WHIP/WHEP.
- Source: main.js search: `session.whipWait`, `session.whepWait`

Name: meshcast; meshcastcode | mccode; nomeshcast | nowhep; chunkcast
- Scope: relay
- Description: Meshcast/relay toggles and options for scale or distribution.
- Source: main.js search: `meshcast(true)`, `meshcastCode`, `noMeshcast`, `chunkcast`

Meshcast (Explicit)
- Name: meshcast
  - Scope: relay
  - Type/Default: string | any
  - Description: Enable Meshcast and select target (e.g., any/video/audio/server code/id).
  - Source: main.js search: `session.meshcast`.

- Name: nomeshcast | nowhep; meshcastfailed
  - Scope: relay
  - Type/Default: boolean | off
  - Description: Disable Meshcast/WHEP relay; `meshcastfailed` allows auto fallback links.
  - Source: main.js/webrtc.js search: `session.noMeshcast`, `meshcastfailed`.

- Name: meshcastbitrate | mcbitrate; meshcastcodec | mccodec; meshcastscale | mcscale; meshcastab
  - Scope: relay (Meshcast)
  - Type/Default: kbps/string/percent | defaults vary
  - Description: Control Meshcast video bitrate/codec/scale and audio bitrate. See WHIP alias docs above for behavior.
  - Source: main.js search: `meshcastbitrate`, `meshcastcodec`, `meshcastscale`, `meshcastab`.

Chunked Mode Controls
- Name: nochunk | nochunked; nochunkaudio | nochunkedaudio
  - Scope: interop/relay
  - Type/Default: boolean | off
  - Description: Disable chunked streaming globally or for audio only.
  - Source: main.js search: `nochunk`, `nochunkaudio`.

- Name: nochunkediframestats
  - Scope: interop/relay
  - Type/Default: boolean | off
  - Description: Disable reporting of chunked IFRAME stats to the iframe API.
  - Source: main.js search: `nochunkediframestats`.

- Name: relaywss
  - Scope: relay
  - Type/Default: URL | none
  - Description: Override relay WebSocket endpoint for chunkcast/relay use cases.
  - Source: webrtc.js search: `session.relaywss`.

Session Redirects and Timers
- Name: endpage; endpagetimer
  - Scope: interop/UX
  - Type/Default: URL; ms | 3000 ms default
  - Description: Redirect to a URL after hangup; optional delay with `endpagetimer`.
  - Source: main.js `session.redirectHangup`, `session.redirectHangupTimer`

- Name: autoend
  - Scope: session
  - Type/Default: ms | default 600000 (10 minutes)
  - Description: Auto hangup after a duration (default if no value provided is 10 minutes).
  - Source: main.js `session.autoEnd`

Recording Automation
- Name: autorecord; autorecordlocal; autorecordremote
  - Scope: session/recording
  - Type/Default: boolean/string | off
  - Description: Automatically start recording; local (on this device) or remote (where supported). Some platforms (iOS) restrict auto‑start.
  - Source: main.js search: `session.autorecord*`; lib.js recording guards.

- Name: waitpage; waitmessage
  - Scope: UX
  - Type/Default: URL/string | none
  - Description: Show a custom intermediate page or message while waiting for a guest/session to resume or connect.
  - Source: main.js/webrtc.js search: `session.waitPage`, `waitmessage`.

- Name: beep | notify | tone; custombeep; beepvolume
  - Scope: UX/notifications
  - Type/Default: boolean/URL/percent | off/0
  - Description: Enable join/leave beep; `custombeep` provides an audio URL; `beepvolume` sets volume percent.
  - Source: main.js search: `beep`, `custombeep`, `beepvolume`.

- Name: welcome | entrymsg | welcomeb64; welcomehtml; welcomeimg | welcomeimage
  - Scope: UX
  - Type/Default: string/base64/URL | none
  - Description: Show a welcome message/HTML/image banner to guests on entry. Base64 variants accepted.
  - Source: main.js search: `welcomeMessage`, `welcomeHTML`, `welcomeImage`.

- Name: whipme
  - Scope: interop (WIP UI)
  - Type/Default: boolean | off
  - Description: Shows WIP WHIP UI section.
  - Source: main.js search: `getById("container-18").classList.remove("hidden")`




# Media & Performance

- Codecs: Select via `&codec` (h264/vp9/av1/hevc|h265) subject to browser/OS support. Hardware H.264 decode benefits OBS; VP9/AV1 improve compression at higher CPU. HEVC/H.265 notes:
  - Publish: Safari commonly supports HEVC; Chrome HEVC encode availability is limited (licensing/OS/GPU dependent). Don’t assume Chrome can publish HEVC.
  - View: Modern Chrome builds can natively decode HEVC on many platforms. OBS Browser Source depends on its bundled CEF; verify CEF HEVC support before relying on it.
  - Negotiation: If both peers expose HEVC in SDP, WebRTC may select it even without `&codec`. You can hint with `&codec=hevc`/`&codec=h265`, but actual selection depends on encode/decode availability.
- Preferences: Viewers and iframe API can request codecs (webrtc.js prefers H.264/VP8/V9 based on context). Android + hardware H.264 has special handling.

Keyframes & Bandwidth Controls
- Name: keyframeinterval | keyframerate | keyframe | fki
  - Scope: source/interop
  - Type/Default: number (seconds) | 0 (auto)
  - Description: Request a target keyframe interval for encoders where supported.
  - Source: main.js search: `session.keyframeRate`.

- Name: maxbandwidth
  - Scope: source/viewer
  - Type/Default: percent (0–200) | 80 default when set
  - Description: Cap outbound bitrate as a percentage of available bandwidth; clamps to [0,200].
  - Source: main.js/webrtc.js search: `session.maxBandwidth`, `limitMaxBandwidth`.

- Name: maxmobilebitrate
  - Scope: source/viewer (mobile)
  - Type/Default: kbps | 350
  - Description: Mobile maximum video bitrate cap to preserve performance; applied when platform is mobile.
  - Source: webrtc.js search: `session.maxMobileBitrate`.

Startup Optimization
- Name: optimize
  - Scope: viewer/scene
  - Type/Default: number | off
  - Description: Optimize bitrate of non-visible tiles to a target kbps; `0` applies aggressive optimize logic.
  - Source: main.js/webrtc.js/lib.js search: `session.optimize`.

- Name: preloadbitrate; rampuptime
  - Scope: source/viewer
  - Type/Default: kbps/ms | 1500 kbps, 6000 ms
  - Description: Use `preloadbitrate` during initial handshake and ramp to estimator over `rampuptime`.
  - Source: main.js/webrtc.js search: `session.preloadbitrate`, `session.rampUpTime`.

- Name: noremb
  - Scope: interop
  - Type/Default: boolean | off
  - Description: Disable REMB feedback; tests different bandwidth estimator behavior.
  - Source: main.js/webrtc.js search: `session.noREMB`.

Zoomed View Bitrate
- Name: zoomedbitrate | zb
  - Scope: viewer/source
  - Type/Default: kbps | 2500
  - Description: Target bitrate to request when a zoomed effect is active.
  - Source: main.js search: `session.zoomedBitrate`.
- Bitrate control: `&bitrate` targets video; `&maxbitrate` caps. Room director can enforce `&roombitrate` with `&controlroombitrate`.
- Frame rate and resolution: Balance `&frameRate`, `&width/&height` with encoder and network capacity.
- Packet loss/jitter: Use `&buffer` (viewer) and `&sync` to trade latency for smoothness. Monitor stats for RTT, dropped frames, and NACK/PLI rates.
- Audio quality: `&audiobitrate` adjusts Opus; stereo/echo/noise settings interact with hardware and OS; iOS disables custom bitrates.
- CPU/GPU: Avoid excessive simultaneous decodes in OBS; use program/scene views and consider `&minipreview` to reduce local UI load.
- Network: WebRTC uses STUN/TURN/ICE. Relays/meshcast can help with restrictive NATs or scale; `&relay` and TURN specifics depend on deployment.
- Stats: See kb/media-stats.md for field meanings and thresholds; use `&stats`, `&remote`, and iframe API continuous stats for monitoring.




# Stats & Diagnostics

Key Stats (typical WebRTC)
- Round-trip time (RTT): End-to-end signaling latency; high values degrade bitrate decisions.
- Jitter: Variability in packet arrival; contributes to choppy audio/video. Viewer `&buffer` mitigates.
- availableOutgoingBitrate: Sender’s estimate of allowed bitrate; capped by encoder and network.
- Packets lost / NACKs per second: Loss indicator; frequent NACKs suggest congestion or Wi‑Fi issues.
- Frames dropped/decoded/received: Video pipeline health; decode drops suggest CPU/GPU limits.
- Audio level (VU): Confirm mic presence and gating.

Where to see them
- `&stats` overlay (viewer/program links) and remote monitor tools (`&remote`, speed test monitor).
- Iframe/Remote API: request continuous stats via postMessage to parent (see examples).

Useful thresholds
- RTT > 200 ms: increase `&buffer` (100–200ms), reduce `&bitrate`.
- Jitter > 15 ms sustained: viewer `&buffer` 150–250ms, prefer wired Ethernet.
- availableOutgoingBitrate << target: lower `&bitrate` or enable room bitrate control.
- Persistent NACKs/PLIs: increase keyframe interval, lower framerate/bitrate.

Source references
- webrtc.js: stats accumulation (e.g., `nacks_per_second`), bitrate logic, codec preferences.
- main.js: `&stats` toggles and remote monitoring flags.




# Integrations

- OBS
  - Use Browser Source with `?view=ID` or room scene URLs. For better playback, consider Electron Capture app for `&buffer` and A/V sync support.
  - Virtual Cam can feed OBS output back into VDO.Ninja as a source when needed.
- Self‑hosting handshake
  - Use compatible websocket signaling server; see `general-settings/pie.md` and referenced repo. Peer traffic remains P2P unless relayed.
- External platforms
  - WHIP/WHEP: Interop with services like Twitch (special tokens) and CF relay.
  - ATEM/NDI/SRT: Typically via bridge apps; out of scope here beyond detection.

OBS Remote/Controls
- Name: obscontrols | controlobs | obs | remoteobs | obsremote
  - Scope: viewer/director
  - Type/Default: boolean/string | off
  - Description: Enable OBS control integration states; values like `full` or truthy enable richer control messaging. `false/0/off/no` disable.
  - Source: main.js search: `session.obsControls`; webrtc.js messaging `msg.info.obs_control`.

- Name: obsoff | disableobs | oo
  - Scope: global
  - Type/Default: boolean | off
  - Description: Disable OBS‑specific behaviors and UI adjustments.
  - Source: main.js search: `session.disableOBS`.

Widgets & Favicons
- Name: widget; widgetleft; widgetwidth
  - Scope: viewer/director
  - Type/Default: URL/boolean/percent | 25%
  - Description: Embed an external widget sidebar; control side (left) and width percentage.
  - Source: main.js/webrtc.js search: `session.widget*`.

- Note: Favicons are static in index.html (`./media/favicon*`). They are not set via URL params.

Social Stream & Streamlabs
- Name: socialstream
  - Scope: integration mode
  - Type/Default: string | false
  - Description: Enable SocialStream integration mode for compatible overlays.
  - Source: main.js/webrtc.js search: `session.socialstream`.

- Name: streamlabs
  - Scope: integration hint (macOS UI notice)
  - Type/Default: boolean | off
  - Description: Enables macOS compatibility messaging for StreamLabs; not a functional behavior toggle.
  - Source: main.js search: `streamlabs` usage (UI notice only).

OBS UI State Mirrors
- Name: noobsstream; noobsvirtual; noobsrecord; noobssourceactive; noobsvisibility
  - Scope: OBS integration
  - Type/Default: boolean | off
  - Description: Override OBS UI state indicators (streaming/virtualcam/recording/sourceActive/visibility) in the page; useful for JS integrations or kiosk views.
  - Source: main.js search: `session.obsState.*` setters.




# Troubleshooting Playbook

Approach
- Quick checks: device permissions, mic/cam selection, local CPU/GPU load, network quality, browser/OS specifics.
- Deep dive: open stats (`&stats`), inspect ICE state, RTT, bitrate, dropped frames, audio levels, packet loss.
- Isolation: test direct link vs room, try relay/meshcast, reduce bitrate/framerate, use `&buffer` on viewers.

Top Issues
- No audio/video
  - Check browser permissions; verify `&vdo`/`&ado` values; confirm device index/name; try `?vdo=1&ado=1`.
  - For screenshare audio, ensure system audio capture is supported and enabled.
- Appearing then disappearing guest
  - Symptoms of network drops or tab suspends. Add viewer `&buffer=120`, lower source `&bitrate=1500`, check power settings.
- Already in use / claimed errors
  - Stream ID collision across the same realm. Change `&push` or add/change `&password`.
- High latency or choppy playback
  - Increase `&buffer` on viewer, limit `&frameRate`, cap `&bitrate`, check stats for high RTT. Consider relay/meshcast.
- A/V sync drift
  - Use viewer `&buffer` with `&sync`. Prefer Electron Capture for robust sync in display pipelines.
- OBS playback artifacts
  - Try Browser Source hardware acceleration; reduce concurrent decodes; consider Electron Capture + window capture.
- Mobile issues (iOS/Android)
  - iOS disables custom audio bitrate; ensure `&audiobitrate` not set. Use Safari/Chrome latest. Avoid backgrounding tabs.

Diagnostics Links
- Minimal test publish: `https://vdo.ninja/?push=TEST&label=Test&autostart`
- Minimal test view: `https://vdo.ninja/?view=TEST&stats&buffer=0`




# Security & Privacy

- Link hygiene: Use `&password` and short `&hash` checks for publicly shared links; avoid exposing director URLs.
- Realms: Passwords isolate stream/room ID namespaces; same `&push` can exist under different passwords without collision.
- Remote/API: Only enable `&remote` and `&api=KEY` when needed; keep keys private and rotate.
- Permissions: Browsers require user gesture for device capture and audio playback; remote commands cannot bypass.
- Embeds: Use `&cleanviewer` and `&nocontrols` for embeds; consider `sandbox` attributes when iframing third‑party content.




# Side‑Project Routing

Detect and redirect when queries are about:
- Social Stream Ninja: chat/alerts aggregation for streams; not core to P2P video transport.
- Raspberry Ninja: Raspberry Pi capture/bridge specifics.
- Caption Ninja: live captioning/transcription overlays.
- Electron Capture: stand‑alone window capture with strong playback/`&buffer` support.
- Meshcast: relay/SFU helper for larger audiences.

Routing Guidance
- If user needs chat overlays/alerts → Social Stream Ninja KB/bot.
- If user mentions Pi hardware capture → Raspberry Ninja KB/bot.
- If captions/transcripts/subtitles → Caption Ninja KB/bot.
- If OBS playback quirks or desire for resilient viewing → Electron Capture KB/bot.
- If scaling viewers beyond P2P → Meshcast docs.




# Glossary & Index

- Stream ID: Unique identifier for a published media stream; used by `&view`.
- Room: Named collection for multi‑party sessions; managed by director.
- Director/Co‑Director: Control plane roles to manage rooms and guests.
- Realm/Password: Security namespace that isolates stream/room IDs.
- WHIP/WHEP: HTTP‑based ingest/playout for WebRTC interop with CDNs/services.
- STUN/TURN/ICE: NAT traversal components; TURN can relay traffic when direct P2P fails.
- Buffer/Sync: Viewer side latency and A/V alignment controls.

Parameter Index
- See `kb/parameters/` for canonical entries and aliases.




# How does it work

VDO.Ninja harnesses the power of WebRTC, a technology that enables secure, real-time communication directly between web browsers. This peer-to-peer approach means most of the action happens right within your browser, ensuring low latency and high-quality video transmission. While VDO.Ninja does utilize servers for initial setup, the actual video data flows directly between devices, leading to a remarkably smooth experience.

**Benefits of the Peer-to-Peer Approach**

* **Ultra-Low Latency:** Experience minimal delays, making interactions feel natural and conversations flow seamlessly.
* **Exceptional Video Quality:** Enjoy crisp, clear video, even at high resolutions.
* **Bandwidth Efficiency:** When on the same local network, video data stays local, saving you precious bandwidth.
* **OBS Integration:** Stream directly into OBS or other browser-enabled applications without any extra software or accounts.
* **Versatility:** VDO.Ninja works across a wide range of devices and platforms, from your smartphone to a Tesla!

**Simple and Powerful**

VDO.Ninja's core functionality revolves around two types of URLs:

* **PUSH URL:** This is used on the sending device (your smartphone, webcam, etc.) to capture and transmit the video and audio.
* **VIEW URL:** Open this URL on any device, anywhere, to watch the live stream in a clean, full-screen interface.

**Collaboration Made Easy**

Beyond basic streaming, VDO.Ninja offers group chat rooms, giving you more control and flexibility when working with multiple streams simultaneously. You can manage participants, adjust settings, and even create custom layouts, all within your browser.

**URL Parameters: Your Control Center**

VDO.Ninja uses URL parameters to fine-tune your streaming experience. These parameters act like commands, allowing you to adjust video quality, enable features, and much more. Think of them as similar to command-line options you might use with software like FFmpeg.

**Ready to Dive Deeper?**

While VDO.Ninja's default settings are designed to be user-friendly, its extensive feature set offers endless possibilities. Explore our documentation to discover all the advanced options and unleash the full potential of VDO.Ninja for your video production needs.




# FAQ

## Project Information and Support Links

**Web service URL**: [https://vdo.ninja/](https://vdo.ninja/)\
**Project development URL**: [https://github.com/steveseguin/vdo.ninja](https://github.com/steveseguin/vdo.ninja)\
**Developer/maintainer**: [steve@seguin.email](mailto:steve@seguin.email)\
**Donations**: [via GitHub Sponsors](https://github.com/steveseguin/obsninja/wiki/Sponsor-%E2%9D%A4)

### Community Support

**Discord**: [https://discord.vdo.ninja](https://discord.vdo.ninja)\
**Reddit**: [https://www.reddit.com/r/VDONinja/](https://www.reddit.com/r/VDONinja/)

## Where can I get support?

The preferred support mechanism is via [Reddit](https://www.reddit.com/r/VDONinja/) or [Discord](https://discord.gg/feenJm8HTa), which offer community-assisted support. Development issues, feature requests, and bugs are tracked on [GitHub](https://github.com/steveseguin/obsninja). For mission critical support issues, or business-related inquiries, you can contact Steve directly.

## Where can I report a bug?

It is most helpful to report bugs via the official [GitHub](https://github.com/steveseguin/obsninja). We also monitor the [Reddit](https://www.reddit.com/r/VDONinja/) and [Discord](https://discord.gg/qWDshMsTar) channels, though it is easier to miss reports that occur there.




---
description: Remote control API (HTTP-GET / WSS-based)
---

# \&api

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&osc`

## Options

Example: `&api=SomeAPIKey`

<table><thead><tr><th width="180">Value</th><th>Description</th></tr></thead><tbody><tr><td>(key)</td><td>API KEY to control VDO.Ninja remotely</td></tr></tbody></table>

## Details

You can use this parameter to enable the HTTP/WSS remote control API for VDO.Ninja. You pass a API KEY value to the parameter, and if it matches the remote control's API KEY, then the remote control interface will be able to send commands to your VDO.Ninja session.

You can control guests in the director's room, or you can control your local microphone and camera, as examples.

Please see [https://github.com/steveseguin/Companion-Ninja](https://github.com/steveseguin/Companion-Ninja) for documentation and details of this command. There is a module for Bitfocus's Companion available, along with HTTP and WSS API endpoints.

Please see [https://companion.vdo.ninja](https://companion.vdo.ninja) for a sample interface to test this command out with. The Companion module is available here: [https://github.com/bitfocus/companion-module-vdo-ninja](https://github.com/bitfocus/companion-module-vdo-ninja)

## Related

{% content-ref url="../guides/hotkey-support/" %}
[hotkey-support](../guides/hotkey-support/)
{% endcontent-ref %}

{% content-ref url="../guides/hotkey-support/how-to-control-vdo.ninja-with-touch-portal.md" %}
[how-to-control-vdo.ninja-with-touch-portal.md](../guides/hotkey-support/how-to-control-vdo.ninja-with-touch-portal.md)
{% endcontent-ref %}




---
description: Allows remote operation of the zoom and focus, and access to statistics
---

# \&remote

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&rem`

## Options

Example: `&remote=somepasscode`

| Value                 | Description                                                    |
| --------------------- | -------------------------------------------------------------- |
| (some passcode value) | this string will have to match on both sides of the connection |

## Details

{% hint style="info" %}
**Android** devices **only**!
{% endhint %}

Must be enabled by both the sender and viewer with identical passcodes in order to work. This is a security precaution. If you pass no value to `&remote`, it will still work, so long as both sides leave it blank.

In some ways, the `&remote` function gives permissions to a viewer that would otherwise be restricted to a director or the sender themselves.

A director of a room can remotely change focus/zoom of a participant without needing the `&remote` command. This applies to both the main director and any co-director, and that's accessible via their per-guest video settings options.

There is a toggle in the director's room which adds `&remote` to the guest's invite link. (2).png>)

### Remote Zooming using `&remote`

Use the mouse wheel over the video you wish to zoom in or out of as a viewer. The sender needs to support zoom, which often is limited to some webcams and Android devices.

### Remote Focus using `&remote`

Remote focus may also work as well by holding `CTRL` (or Command) while using the mouse wheel.  The sender needs to support focus for this to work, which often is limited to some webcams and Android devices. It's sometime listed as "focus distance" in the senders video settings menu.

To check if a device supports zoom or focus, go to [https://vdo.ninja/supports](https://vdo.ninja/supports). It will show whether your browser and the selected camera supports focus/zoom.

If you are the one publishing with an Android device, you can hold the screen down and move your finger up or down to zoom in and out as well; you don't need a remote user or the settings menu to do this.

### Remote Statistics using `&remote`

A bit less accessible, but using `&remote` also gives the viewer permission to request statistic information. The monitoring tool, also used by the VDO.Ninja speed-test, makes use of the `&remote` flag to remote access stats.

[https://vdo.ninja/monitor](https://vdo.ninja/monitor)

Example usage:\
\
Monitoring Link: `https://vdo.ninja/monitor?sid=BaGpHmu,stevetest123`

.png>)

It will pull statistics data from the sender of a video stream and visualize it, allowing for remote monitoring of stream quality. For this command to work though, the publisher needs to add `&remote` to their URL to allow for remote access.\
\
This reason for needing `&remote` is privacy related, as the statistical information being shared with the monitor page could include information like browser or system data of remote viewers unconnected to the monitoring user. While likely unneeded, adding `&remote=somePassword` to both the monitoring and push links will further increase security with a password check.

The VDO.Ninja speed test ([https://vdo.ninja/speedtest](https://vdo.ninja/speedtest)) has a link at the bottom of the page, which is all already configured to provide remote monitoring of speed test results without needing to play with any parameters or settings.

In regards to `&sid`, you can pass multiple stream IDs, and so long as each remote sender of that stream ID has `&remote` added to their URL, the monitoring page will be able to monitor all those outbound streams.

Nacks per second is similar to packet loss, and so a high nack loss rate implies a restriction on network quality. "quality limitation reason" may also be stated, which can imply whether the CPU or Network is the bottleneck in achieving maximum quality.

If viewers of a stream ID being monitor have a label assigned ([`&label`](label.md)), then that will appear as a label on the monitor page besides the graph, identifying it.

### Remote on Basic Push and View Links

When using the `&remote` control option, the viewer can now remotely hang-up the sender via the right-click menu. The sender needs to remote control enabled for this to work of course.

`&remote`, if used on a push link without a password added, it will now allow the remote viewer limited control (hangup, focus, zoom, detailed stats), even if they don't have `&remote` added to their URL also. When using `&remote`, the option to "reload" the remote browser is now available, so you can potentially reload a remote unattended session that contains`&autostart&webcam`..png>)

### Standalone Camera Operator Console

[`https://vdo.ninja/control.html`](https://vdo.ninja/control.html) provides a responsive non-director control surface for one or more simple push streams. Add `&remote` to both the console/viewer and sender links, optionally using the same `&remote=TOKEN` value on both sides. Add `&ptz` to the sender link when the camera supports pan, tilt, or zoom.

The console keeps background camera previews at a low requested bitrate and raises only the selected preview. It discovers each camera's browser-exposed controls, including PTZ, focus, exposure, white balance, image adjustment, torch, capture format, camera-device selection, and digital video effects with their supported amount controls. Unsupported settings are not shown. Camera-device and effect changes use the sender consent flow and prompt the sender by default. Effect approval is remembered for that controller's current connection so the operator can continue adjusting the effect and its amount. The sender can intentionally add `&consent` to pre-authorize unattended changes.

Directors have the same effect and amount controls in each guest's advanced camera settings. Background and overlay modes use images already selected or configured by the sender; remote controllers cannot upload an arbitrary image.

General URL parameters on the console link are forwarded to its preview viewers, including `&password`, `&salt`, `&wss`, `&noaudio`, codec options, and custom connection settings. Stream-role parameters and the console's preview-bitrate parameters are replaced for each camera. Generated sender links carry the same general connection settings, but omit viewer-role parameters, console bitrate settings, and `&consent`.

Example console: `https://vdo.ninja/control.html?view=CAMERA1,CAMERA2&password=PASSWORD&remote=TOKEN`

Generated sender: `https://vdo.ninja/?password=PASSWORD&push=CAMERA1&remote=TOKEN&ptz&autostart&webcam&nopreview`




---
description: >-
  Sets the audio mode to stereo and changes default audio settings to improve
  audio quality
---

# \&stereo

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&s`
* [`&proaudio`](../advanced-settings/audio-parameters/and-proaudio.md)

## Options

Example: `&stereo=1`

<table><thead><tr><th width="191">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>It behaves like 3 or 1, depending on if you are a guest or not</td></tr><tr><td><code>0</code></td><td>will try to down-mix your mic to mono. Does not enable any pro-audio settings</td></tr><tr><td><code>1</code></td><td>enables it for both push and view (if used on both links)</td></tr><tr><td><code>2</code></td><td>enables it just for viewing requests and not publishing requests</td></tr><tr><td><code>3</code></td><td>enables it for just publishing requests and not viewing requests</td></tr><tr><td><code>4</code></td><td>enables 5.1-multichannel audio support (Experimental and may require a Chrome flag to be set)</td></tr><tr><td><code>5</code></td><td>This is the default if nothing is set. It behaves like 3 or 1, depending on if you are a guest or not</td></tr><tr><td><code>6</code></td><td>solely just enables stereo for both in/out</td></tr><tr><td><code>8</code></td><td>7.1 surround sound audio <a data-mention href="stereo.md#and-stereo-8">#and-stereo-8</a></td></tr></tbody></table>

## Details

Adding `&stereo` to the URL will apply audio-specific setting presets. For inbound audio streams, it can be used to increase the audio bitrate from 32-kbps to 256-kbps. For outbound streams, it will disable echo-cancellation and noise-reduction. When applied to both the outbound and inbound sides of an audio stream, it will also enable stereo audio if available.

There are a variety of different modes that apply different combination of presets. You can also override any preset with other URL parameters, such as [`&audiobitrate`](../advanced-settings/view-parameters/audiobitrate.md), [`&outboundaudiobitrate`](../source-settings/and-outboundaudiobitrate.md), and [`&aec=1`](../source-settings/aec.md).

If using a microphone, wearing headphones is strongly recommended if using this parameter, along with knowledge of correctly setting your microphone gain settings. Echo and feedback issues can occur if this option is used incorrectly.

When using this option in a group room, you can't simply just apply this URL option to the director and have it apply to all guests. You will need to add the flag to each guest and to each scene-link to enable the pro-audio stereo mode. Depending on the value you pass to the URL parameter, you will get slightly different outcomes.

### More Details

`&stereo` and `&proaudio` currently do the same thing, so they are just aliases of each other. When used, they can be used to setup the audio transfer pipeline to allow for unprocessed, high-bitrate, stereo audio.

Use of this option is generally for advanced users who understand the consequences of enabling this. High-quality audio can cause audio clicking, reduced video quality, feedback issues, low volume levels, and higher background noise levels.

For stereo-channel support to work, you will want both the viewer AND the publisher of the stream to have the respective `&stereo` flag add to their URL.

You can customize things further using [`&aec`](../source-settings/aec.md), [`&ag`](../source-settings/autogain.md), [`&dn`](../source-settings/and-denoise.md), [`&ab`](../advanced-settings/view-parameters/audiobitrate.md) and [`&mono`](../advanced-settings/view-parameters/mono.md). These flags will override the presets applied by the `&stereo` flag.  Please note, depending on your browser, enabling `&aec`, `&ag`, or `&dn` can force disable stereo audio.

The most powerful mode is `stereo=1` , which if enabled:

* Turns off audio normalization or auto-gain when publishing ([`&push`](../source-settings/push.md))
* Turns off noise-cancellation when publishing
* Turns off echo-cancellation when publishing
* Enables higher audio bitrate playback, up to 256-kbps, when listening ([`&view`](../advanced-settings/view-parameters/view.md))

If the parameter is used, but left without a value, it is treated as a special case (either 1 or 3). Please see follow link for more info:

[https://docs.google.com/spreadsheets/d/e/2PACX-1vS7Up5jgXPcmg\_tN52JLgXBZG3wfHB3pZDQWimzxixiuRIDbeMdmU11fgrMpdYFT6yy4Igrkc9hnReY/pubhtml](https://docs.google.com/spreadsheets/d/e/2PACX-1vS7Up5jgXPcmg\_tN52JLgXBZG3wfHB3pZDQWimzxixiuRIDbeMdmU11fgrMpdYFT6yy4Igrkc9hnReY/pubhtml)

|    Option   | alias | aec   | autogain | denoise | stereo playback | stereo output | default ab in | max ab out | limited ab in | cbr  |
| :---------: | ----- | ----- | -------- | ------- | --------------- | ------------- | ------------- | ---------- | ------------- | ---- |
| `&stereo=0` | off   | on    | on       | on      | _off_           | _no_          | 32            | 510        | 510           | _no_ |
| `&stereo=1` | both  | _off_ | _off_    | _off_   | on              | yes           | 256           | 510        | 510           | yes  |
| `&stereo=2` | in    | on    | on       | on      | on              | _no_          | 256           | 510        | 510           | yes  |
| `&stereo=3` | out   | _off_ | _off_    | _off_   | _off_           | yes           | 32            | 510        | 510           | _no_ |
| `&stereo=4` | multi | _off_ | _off_    | _off_   | on (5.1)        | yes           | 256           | 510        | 510           | yes  |

### Newbie mode

The default mode when `&stereo` is used alone is `&stereo=5`, which acts like either `&stereo=3` or `&stereo=1`, depending on whether the link its applied to is a room guest or not. This option will make the most sense for most users.

| Option      | Context     | alias | aec   | autogain | denoise | stereo playback | stereo output | default ab in | max ab out | limited ab in | cbr  |
| ----------- | ----------- | ----- | ----- | -------- | ------- | --------------- | ------------- | ------------- | ---------- | ------------- | ---- |
| `&stereo=5` | Regular/OBS | 5     | _off_ | _off_    | _off_   | on              | yes           | 256           | 510        | 510           | yes  |
| `&stereo=5` | Director    | 5     | _off_ | _off_    | _off_   | on              | yes           | 32            | 510        | 510           | _no_ |
| `&stereo=5` | Room Guest  | 5     | _off_ | _off_    | _off_   | _off_           | yes           | 32            | 510        | 510           | _no_ |

### iOS Devices

| Option      | alias | aec | autogain | denoise | stereo playback | stereo output | default ab in | max ab out | limited ab in | cbr  |
| ----------- | ----- | --- | -------- | ------- | --------------- | ------------- | ------------- | ---------- | ------------- | ---- |
| iOS devices |       | on  | on       | on      | _off_           | _off_         | 32            | 32         | 32            | _no_ |

Just for reference, the audio codec used by VDO.Ninja is OPUS (48khz), which can provide high-fidelity music transfer when the audio bitrate is set to 80-kbps per channel or higher. The default audio bitrate used is 32-kbps VBR, which is sufficient for most voice applications. Increasing the audio bitrate to a near-lossless 500-kbps or something may end up causing more problems than anything, but that is supported if needed.

### WHIP

`&stereo` now works with the WHIP output, so if enabled, you'll publish stereo 2.0 with a default audio bitrate of around 80 to 100-kbps; otherwise the default is mono at around 60kbps. These defaults bitrates might be changed own the road.

### \&stereo=8

7.1 surround sound audio is being supported now, in a technical sense, although really only if the source is a server stream. To use, add `&stereo=8` on the viewer end. (5.1 multi channel was around supported with `&stereo=4` I think)

## Related

{% content-ref url="../advanced-settings/view-parameters/audiobitrate.md" %}
[audiobitrate.md](../advanced-settings/view-parameters/audiobitrate.md)
{% endcontent-ref %}

{% content-ref url="../source-settings/and-outboundaudiobitrate.md" %}
[and-outboundaudiobitrate.md](../source-settings/and-outboundaudiobitrate.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-screensharestereo.md" %}
[and-screensharestereo.md](../newly-added-parameters/and-screensharestereo.md)
{% endcontent-ref %}




---
description: Shows the connection/media stats window by default
---

# \&stats

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Details

Adding `&stats` to a URL shows the connection/media stats window.

On desktop, you can hold `CTRL` (or `CMD`) and `Left-Click` a video to get its stats.\
On Version 22 you can `Right-Click` -> Stats on a video feed to get its stats.

On mobile, you can just rapidly touch the display to trigger the stats window instead.

The `&stats` URL parameter is for those like vMix users who might not be able to interact with the browser source.

.png>)




---
description: Forces TURN relay server into use
---

# \&relay

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&private`
* `&privacy`

## Details

Forcing relay mode is provided for testing and emergency purposes. It will typically increase latency; sometimes by a lot.

Alternatives to relay mode include:

* Using wired Ethernet instead of Wi-Fi will also reduce packet loss.
* A VPN service, like Speedify, will likely be better than using a TURN server.

Uses of relay mode include:

* Can potentially reduce packet loss with some guests on bad connections.
* Some peer to peer connections over residential networks struggle, and introducing a relay server can help avoid those issues.
* Has the advantage of hiding your IP address from peers.

You can [deploy your own TURN server](https://github.com/steveseguin/obsninja/blob/master/turnserver.md) if intending to use this feature a lot or needing more bandwidth.

Please feel free to donate to VDO.Ninja to help support the provided TURN servers.

Currently TURN servers are deployed numerous countries around the world.

Ports that a TURN server may use include 443, 3478, and potentially others.

{% hint style="info" %}
More information on what TURN is [here](https://en.wikipedia.org/wiki/Traversal\_Using\_Relays\_around\_NAT)
{% endhint %}

### Difference between `&relay` and `&privacy`

If using `&privacy` on the URL (using TURN server), with the intent being to hide your IP address, a page will prompt you if an IFrame tries to load, asking if you wish to continue.

<figure><figcaption></figcaption></figure>

Using `&relay` will not do this behavior, despite using the turn server none-the-less; so `&privacy` is evolving to be a bit more strict than `&relay` alone.

It will even show if loaded into OBS, as privacy trumps there. (IFrames can steal IP address, etc.).

You can also just use [`&nowebsite`](../source-settings/nowebsite.md), to disable IFrames from loading at all (always existed as an option).

Certain known sites are excepted; YouTube, Twitch, Vimeo, etc. will not ask for confirmation.

## Related

{% content-ref url="turn.md" %}
[turn.md](turn.md)
{% endcontent-ref %}




---
description: Lets you specify a STUN server for webRTC negotiation
---

# \&stun

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Details

This parameter lets you specify a STUN server for webRTC negotiation. The default STUN servers use those provided by Google (and recently also Cloudflare), at `stun:stun.l.google.com:19302`, but with this command you can set your own.

`&stun` will overwrite the existing STUN values provided by VDO.Ninja. If you wish to keep the existing STUN server options, adding additional options, or if you wish to add multiple custom STUN servers, you can use the related [`&addstun`](../newly-added-parameters/and-addstun.md) parameter. This is the same idea, but when used it won't overwrite the existing STUN options.

Using `&stun` and [`&addstun`](../newly-added-parameters/and-addstun.md) together will let you specify two custom STUN servers.

Setting `&stun` to false will clear the default STUN servers.

If your STUN server requires a password, you can pass the STUN server address with semi-comma separated values in the form `&stun=USERNAME;PASSWORD;ADDRESS`

Basic sample usage of `&stun`:

[`https://vdo.ninja/?push&stun=stun:stun4.l.google.com:19302`](https://vdo.ninja/?push\&stun=stun:stun4.l.google.com:19302)

### About STUN servers

A STUN (Session Traversal Utilities for NAT) server is used to discover a device's public IP address and port, especially when it is behind a Network Address Translator (NAT), facilitating peer-to-peer communication in technologies like WebRTC.

If your browser has disabled WebRTC IP leaking, then the STUN servers may be pretty useless, as the only IP your browser will share with other peers is any obtained from the relay server.

Without a STUN server though, you will still share your local IP, the HOST candidate type, as well as any RELAY candidates obtained from available turn servers.

The magic with VDO.Ninja and peer-to-peer webRTC is largely made possible by STUN servers.

### More about SRFLX vs PRFLX candidate modes

When dealing with ICE (Interactive Connectivity Establishment) candidates, you may encounter terms like "srflx" and "prflx," which refer to different types of ICE candidates. ICE is a protocol used for establishing peer-to-peer communication sessions, often for real-time audio and video communication.

1. **srflx (Server Reflexive)**:
   * Server reflexive candidates are created when a device behind a Network Address Translator (NAT) sends a request to a STUN (Session Traversal Utilities for NAT) server. The STUN server then sends a response back, and this response contains a reflexive candidate. This reflexive candidate represents the public IP and port of the NAT device.
   * Srflx candidates are used to traverse NATs and allow the devices on both sides to find a route to communicate through the NAT.
   * Srflx is the most common candidate type seen when making a connection with another remote peer on the Internet, via VDO.Ninja.
2. **prflx (Peer Reflexive)**:
   * Peer reflexive candidates are also a result of communication with a STUN server, but unlike server reflexive candidates, they represent the reflexive address of the remote peer, not the local device. In other words, they are the public IP and port of the other side, as observed by the STUN server.
   * Prflx candidates can be helpful in situations where a WebRTC peer wants to communicate with another peer, and it needs to discover the public address of that peer to establish direct communication.
   * Prflx are not common among VDO.Ninja connections, but may be seen when tethering, using a symmetrical firewall, or other non-common networking setups.

In summary, srflx and prflx candidates both involve the use of STUN servers to discover reflexive addresses, but srflx represents the public address of the local device (behind NAT), while prflx represents the public address of the remote peer. These types of candidates are crucial for WebRTC communication because they help establish peer-to-peer connections across NAT devices and firewalls.

## Related

{% content-ref url="../newly-added-parameters/and-addstun.md" %}
[and-addstun.md](../newly-added-parameters/and-addstun.md)
{% endcontent-ref %}

{% content-ref url="turn.md" %}
[turn.md](turn.md)
{% endcontent-ref %}




---
description: Lets you specify a custom TURN server or disable all TURN servers
---

# \&turn

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md), [`&director`](../viewers-settings/director.md))

## Options

Example: `&turn=steve;setupYourOwnPlease;turn:turn.vdo.ninja:443`

<table><thead><tr><th width="283">Value</th><th>Description</th></tr></thead><tbody><tr><td>(user;pwd;turnserveraddress)</td><td>Set this TURN server to turnserveraddress with username user and password pwd</td></tr><tr><td><code>false</code> | <code>off</code></td><td>Disable the use of the TURN servers</td></tr></tbody></table>

## Details

Several TURN servers are provided by Steve for free, for now, and these are automatically selected based on your geographic location. You may wish to use your own privately hosted TURN server instead though, and the `&turn` is one flexible way to select it.

### Locations

* Canada
* Germany
* USA
* France/UK

### **Example Usage**

`https://vdo.ninja/?turn=steve;setupYourOwnPlease;turn:turn.vdo.ninja:443&relay`\
\
Note the use of `turn:`, and in the case of TLS/SSL, `turns:`

### **More Info**

TURN Servers are designed to help certain users connect when they are behind a firewall or other network restriction. About 1 in 10 users need a TURN server to use VDO.Ninja; if you are having problems, check to see if they are using the TURN server.

Sometimes, rarely, using your own TURN server can improve video quality for some users, if the public network routing is very bad and the TURN server is hosted on a high-quality private network, like Google Cloud. Details are provided in the code repo no how to deploy your own (turnserver.md).

TURN servers are NOT something you can use to share one video stream with multiple viewers. (That is an SFU server, which is out of scope of this article.) A TURN server acts like a middle-man, routing the encrypted data between two peers, mainly when those two peers are unable to speak directly themselves.

Using a TURN server can also hide your IP address from other peers. You will need to use [`&relay`](and-relay.md) to FORCE the TURN server to be enabled, as otherwise the system will still try to use a direct p2p connection, instead of the TURN server. You may want to add turn and relay flags to both the viewer and the sender side, to ensure things are correctly set.

[https://vdo.ninja/speedtest](https://vdo.ninja/speedtest) performs a connection test using the TURN server. It will select the closest public TURN server to you. At peak hours, these TURN servers might have lower performance compared to at off-peak hours, so consider hosting your own TURN server if absolute maximum performance is needed.

You can check to see if you are using the TURN server by checking the connection stats window (`Left-Click` + `CTRL` while viewing a video. In this stats display, "Relay" implies connected to a TURN server. HOST implies connected via a LAN. SRFLX/PRFLX implies connected directly via [STUN](stun.md).

### Installing your own TURN server

Details on how to setup and deploy your own TURN server is here, although there are also plenty of guides online for this, too:

[https://github.com/steveseguin/vdo.ninja/blob/develop/turnserver.md](https://github.com/steveseguin/vdo.ninja/blob/develop/turnserver.md)

It is possible to store credentials for your TURN server on a server, pulling them as needed via an API, such as from Twilio's API. It is also possible to hard-code the credentials into the app itself. Both these options require self-deploying the website code however.

## Related

{% content-ref url="and-tcp.md" %}
[and-tcp.md](and-tcp.md)
{% endcontent-ref %}

{% content-ref url="../common-errors-and-known-issues/hosted-your-own-turn-server.md" %}
[hosted-your-own-turn-server.md](../common-errors-and-known-issues/hosted-your-own-turn-server.md)
{% endcontent-ref %}

{% content-ref url="and-relay.md" %}
[and-relay.md](and-relay.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-tz.md" %}
[and-tz.md](../newly-added-parameters/and-tz.md)
{% endcontent-ref %}




---
description: Sets a display name label
---

# \&label

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&l`

## Options

Example: `&label=Steve`

| Value             | Description                                        |
| ----------------- | -------------------------------------------------- |
| (no value given)  | It will prompt the user for a Display Name on load |
| (string)          | Sets the label for the guest/browser tab           |
| `TITLEn\SUBTITLE` | [Multiple lines](label.md#multiple-lines-on-alpha) |

## Details

`&label` sets a display name label to the stream ID.

* Uses the label in OBS Studio if dragging the link into OBS Studio.
* Will change the name of the Browser tab to the Label specified.\
  .png>)
* Shows up in the connection debug Stats window.\
   (2).png>)
* If left blank, it will prompt the user for a Display Name on load.\
   (1).png>)
* You can use [`&showlabels`](../advanced-settings/design-parameters/showlabels.md) to show the labels in the video sources.

### Multiple lines

Until I figure out a better way of doing this, I've enabled a way to have a display name be on multiple-lines in VDO.Ninja.

`&label=DisplayNameHere\nSubtitleHere` Note the use of as a line break ie:

```
https://vdo.ninja/?label=Steve_Seguin\n(he/him)\nhttps://twitch.tv/vdoninja&push=JaAiVEH
https://vdo.ninja/?view=JaAiVEH&showlabels
```

So it's not super obvious how to do this currently, so I think the next goal will be to add the option to let a guest enter their own sub-title, etc, when joining, using dedicated input fields. But until then, I hope this still helps. You can stylize the sub-label within OBS's CSS section, targeting the following CSS, but please note I'll probably be tweaking the CSS/HTML as well in the future:

```
.video-label>span:nth-child(2) {
    font-size: 50%;
    display: block;
    text-align: center;
}
```

 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)

## Related

{% content-ref url="../advanced-settings/design-parameters/showlabels.md" %}
[showlabels.md](../advanced-settings/design-parameters/showlabels.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-screensharelabel.md" %}
[and-screensharelabel.md](../newly-added-parameters/and-screensharelabel.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/setup-parameters/and-labelsuggestion.md" %}
[and-labelsuggestion.md](../advanced-settings/setup-parameters/and-labelsuggestion.md)
{% endcontent-ref %}




---
description: Audio playback is muted
---

# \&deafen

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&deaf`

## Details

Audio playback is muted in VDO.Ninja. If you just want to mute the speaker button temporarily use [`&mutespeaker`](../source-settings/and-mutespeaker.md).

## Related

{% content-ref url="../source-settings/and-mutespeaker.md" %}
[and-mutespeaker.md](../source-settings/and-mutespeaker.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/view-parameters/noaudio.md" %}
[noaudio.md](../advanced-settings/view-parameters/noaudio.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/video-parameters/and-blind.md" %}
[and-blind.md](../advanced-settings/video-parameters/and-blind.md)
{% endcontent-ref %}




---
description: Support for piesocket.com
---

# \&pie

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Options

Example: `&pie=YourPiesocketAPIKey`

<table><thead><tr><th width="187">Value</th><th>Description</th></tr></thead><tbody><tr><td>(API_KEY)</td><td>the only parameter is your own piesocket.com API key</td></tr></tbody></table>

## Details

Third-party handshake-server service option. If using piesocket, you can just do `&pie=APKKEY` to use that service, without deploying any code or servers yourself.

{% hint style="warning" %}
At the time of originally adding this feature, PieSocket was a free service. That has since changed (Dec 2021). VDO.Ninja is not affiliated with PieSocket and never has been. We have no recommendation on whether you should use them or not.

For a free handshake-server though, please instead consider hosting your own on Google Cloud or Amazon AWS with a free micro-server instance. The following server code is compatible with VDO.Ninja: [https://github.com/steveseguin/websocket\_server](https://github.com/steveseguin/websocket\_server)
{% endhint %}




---
description: Sets a room ID for the session to join
---

# \&room

General Option! ([`&push`](../source-settings/push.md), [`&scene`](../advanced-settings/view-parameters/scene.md), [`&solo`](../advanced-settings/mixer-scene-parameters/and-solo.md))

## Aliases

* `&roomid`
* `&r`

## Options

Example: `&room=RoomID`

<table><thead><tr><th width="335">Value</th><th>Description</th></tr></thead><tbody><tr><td>(string)</td><td>1 to 49-characters long: aLphaNumEric-characters; case sensitive.</td></tr></tbody></table>

## Details

Rooms broadcast to all participants who have joined.

Rooms are complemented by the [`&director=roomname`](../viewers-settings/director.md) function. Directors can have oversight of a room.

Rooms limit the viewing bitrate that guests of a room can request. OBS does not have these viewing limits though.

Rooms have no forced limit on the number of guests allowed, but practically 10 is about the limit I'd recommend.

Adding [`&showonly=xxx`](../advanced-settings/video-parameters/and-novideo.md) and [`&roombitrate=0`](../advanced-settings/video-bitrate-parameters/roombitrate.md) to the guest's URL can be used to help increase the capacity of rooms to 30 or more.

An alternative to a `&room` is a [_faux-room_](../getting-started/multi-person-chat.md), which can be done with:\
`https://vdo.ninja/?push=aaa&view=bbb,ccc,ddd`

## Additional info

There's a documentation page dedicated to rooms [here](../getting-started/rooms/).

There's also a video below looking at what sort of performance and system load there is when using an unoptimized group room.

{% embed url="https://www.youtube.com/watch?v=VYYG4rZffcM" %}

You can reduce CPU load using the [`&broadcast`](../advanced-settings/view-parameters/broadcast.md) flag, if hosting a larger room.

You can also [transfer guests between group rooms](../getting-started/rooms/transfer-rooms.md), using the transfer function that the director has.

## Related

{% content-ref url="../getting-started/rooms/" %}
[rooms](../getting-started/rooms/)
{% endcontent-ref %}

{% content-ref url="../getting-started/rooms/transfer-rooms.md" %}
[transfer-rooms.md](../getting-started/rooms/transfer-rooms.md)
{% endcontent-ref %}

{% content-ref url="../viewers-settings/director.md" %}
[director.md](../viewers-settings/director.md)
{% endcontent-ref %}




---
description: Disables all webaudio audio-processing pipelines
---

# \&noaudioprocessing

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&noap`

## Details

`&noaudioprocessing` disables the web-audio audio processing pipelines of both inbound and outbound audio. This is not the same as disabling echo-cancellation, denoise, or auto-gain; those are not web-audio-based.

Disabling the web-audio processing pipeline can help reduce audio distortion, clicking, and some echo-cancellation issues, especially if your CPU is overloaded.

The web-audio pipeline is like a chain of audio-plugins, loaded into Javascript, which does custom audio processing. This includes the low-cut filters, limiting, compression, audio-visualizers, active-speaker, director-side gain and mute control, and more.

This audio pipeline can start to have problems though if the CPU is overloaded. This can result in odd issues, including clicking. This pipeline is disabled by default in scenes, but it's usually enabled by default for most guest types.

{% hint style="warning" %}
Disabling audio processing will disable many features, such as audio-visualizers, gain control, and loudness-monitoring API functions.

The ability to remotely mute a guest as a director (along with [`&audiogain=0`](../advanced-settings/audio-parameters/and-audiogain.md)) will not work if audio processing is disabled.
{% endhint %}




---
description: A basic guest queuing and approving system
---

# \&queue

Director and/or Sender Option! ([`&director`](../viewers-settings/director.md), [`&push`](../source-settings/push.md), [`&room`](room.md))

## Details

`&queue` lets the room's director review guests who join a room.

The option can be used in one of two ways; either as a powerful screening room or as a simple approval system, depending on if the `&queue` option is also used on the director's URL.

<div align="left">

<figure><figcaption></figcaption></figure>

</div>

{% embed url="https://www.youtube.com/embed/DDJrhhdNX_c" %}

{% hint style="info" %}
`&queue` was changed in v24 to not allow the guest to see the director's video, until the director activates the guest with their pink activate-guest button. Otherwise, it's the same as before. Use [`&screen`](../advanced-settings/guest-queuing-parameters/and-screen-alpha.md) for the old version.
{% endhint %}

If used on the director's URL, as well as the guest's URL, guests are added to a queue as they join, and the director can connect to those guests with a button in their lower control bar. This feature prevents the director's computer from being overwhelmed with connections.

The guests will not be able to see anyone, until they are transferred or approved. Once approved, the director will be able to see them, and they will be able to see the director.

Guests can be disconnected and they can then rejoin the queue, but when they do they will be at the end of the queue again.

This system can support hundreds of guests in queue, but it is not advisable to use this system if you expect thousands of guests to join.

{% hint style="info" %}
Looking for feedback!
{% endhint %}

### Using `&queue` on both director + guest links

The `&queue` option can be added to both the director URL and the guest URL, or just the guest's URL.

Example director link:

```
https://vdo.ninja?director=roomname&queue
```

Corresponding room link:

```
https://vdo.ninja/?room=roomname&queue
```

When `&queue` is added both the guests' links and director's link, there will be a new 'wait list' button added to the director's view, which when pressed, will load the next guest in queue in the director's room. The guest will be able to see the director and only the director then.

The director can add more guests this way, kicking out those they don't want, and continue to cycle thru the queue of guests as they join the room. This setup is designed as a screening room, where the director is expected to transfer the guests to the main production room when appropriate.

When transferred, the guest will no longer be considered in 'a queue' and will be able to see everyone in the new room they were transferred to, and vice versa. The guest will not know which room they were transferred to, and will be unable to rejoin without joining the queue again. You can use the "change URL" button in the director's room if you wish to permanent-transfer a guest to a new link.

This setup is ideal for when dozens or hundreds of guests may try joining a room. The director can load a few guests at a time, preventing their system from being overloaded. Relying on a transfer room prevents the main room from being attacked as well.

### Using `&queue` on just the guest invite link

When `&queue` is added to just the invite link for a guest, and not added to the director's link also, the guest will auto-load for the director, and only for the director. There is no wait-list.

The director will have a button for each joined guest titled "Activate Guest", which will pressed, will accept the guest into the current room as if a normal guest. They will see other activated guests in the room, without needing to be transferred to another room.

This approach to just adding `&queue` to the guest invite links, and not putting the room itself into a screening room, is well suited when you are only expecting just a few guests to join, and not dozens or hundreds, since the director will auto-load the video of each guest who joins.

Since it's possible for a user to just remove `&queue` from their URL when joining, bypassing the need for activation, this method is considered less secure versus the use of the screening room where users are transferred to the main room instead.

<figure><figcaption></figcaption></figure>

### Exempt certain connections from the queue automatically

As a director, you can use [`&view`](../advanced-settings/view-parameters/view.md) in the URL to specify stream IDs that you wish to connect normally, bypassing the queue.

For example:\
[`https://vdo.ninja/?director=MyRoom123&codirector&queue&push=mainDirector123&view=coDirectorStreamID123`](https://vdo.ninja/?director=MyRoom123\&codirector\&queue\&push=mainDirector123\&view=coDirectorStreamID123)

[`https://vdo.ninja/?director=MyRoom123&codirector&queue&push=coDirectorID123&view=mainDirector123`](https://vdo.ninja/?director=MyRoom123\&codirector\&queue\&push=coDirectorID123\&view=mainDirector123)

The above links allows a co-director join the room, despite the main director and co-director being in queuing-mode. By specifying each other's stream ID as a listed view value, they can both bypass each other's queue together.

`&view` can accept a list of stream IDs. When in `&queue` mode, `&view` allows connections to join that are not listed, but only if they are brought in via the queue. This makes it a bit of a special case for `&view`, where it otherwise is pretty strict about who connects or not.

### Other queue modes

The "queue" mode, when applied only to the guest-link, has been extended with new options. These modes do not apply when you have `&queue` also on the director's link, however, rather just when added to the guest-invite link only.

These options might be appealing for screening guests when either you don't want to use a transfer room or don't expect too many guests to be in queue.

[and-screen-alpha.md](../advanced-settings/guest-queuing-parameters/and-screen-alpha.md "mention")

[and-hold-alpha.md](../advanced-settings/guest-queuing-parameters/and-hold-alpha.md "mention")

[and-holdwithvideo-alpha.md](../advanced-settings/guest-queuing-parameters/and-holdwithvideo-alpha.md "mention")

## Related

{% content-ref url="../advanced-settings/guest-queuing-parameters/and-screen-alpha.md" %}
[and-screen-alpha.md](../advanced-settings/guest-queuing-parameters/and-screen-alpha.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/guest-queuing-parameters/and-hold-alpha.md" %}
[and-hold-alpha.md](../advanced-settings/guest-queuing-parameters/and-hold-alpha.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/guest-queuing-parameters/and-holdwithvideo-alpha.md" %}
[and-holdwithvideo-alpha.md](../advanced-settings/guest-queuing-parameters/and-holdwithvideo-alpha.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/settings-parameters/and-queuetransfer.md" %}
[and-queuetransfer.md](../advanced-settings/settings-parameters/and-queuetransfer.md)
{% endcontent-ref %}




---
description: Puts guests into sub-groups, so they only see others in the same group
---

# \&group

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&groups`

## Options

Example: `&group=Groupname`

<table><thead><tr><th width="222.57142857142856">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code></td><td>adds the guest or director to group 1</td></tr><tr><td><code>2</code></td><td>adds the guest or director to group 2</td></tr><tr><td><code>3,4,5,6</code></td><td>adds the guest or director to group 3, 4, 5 and 6</td></tr><tr><td>(string)</td><td>creates/adds the guest or director to a custom group</td></tr></tbody></table>

## Details

The idea is, you can put guests of a room into sub-groups. When added to a sub group, those guests will only be able to see and hear others in that same sub group.&#x20;

Guests can be assigned to multiple subgroups. Groups can be specified via the URL using `&group=1,5,6` or/and the director can dynamically assign sub-groups, as seen in the below image.&#x20;

.png>)

If not in a group, that guest will still see/hear everyone, regardless of which group they are in, even if a guest in another group may not be able to see/hear that guest back.

Scenes can be put into groups as well, via the URL group option, such `&group=3`, but the director will not be able to dynamically change which group a scene is in. Not yet at least.

Using this group function is an alternative to transfer rooms, however it's perhaps less secure, as a guest could just tinker with their URL parameters or just refresh their page to perhaps see everyone in the room again.

[`&groupaudio`](and-groupaudio.md) can be used to enable audio in-between different groups, instead of audio being group-specific. Useful for blind-dating show formats or such.

### New in Version 22

Custom groups used by remote guests now show in the director's view, just like custom scenes do. If you use `&groups=group,test,vdo`, new group buttons will appear.\
.png>)

With [`&groupmode`](../advanced-settings/setup-parameters/and-groupmode.md) added to your URL, when not assigned to a group, you don't hear or see anything. This also goes for remote participants who are not in a group - you will not see or hear them if they are not in a group, even if you also are not in a group.

## Related

{% content-ref url="and-groupaudio.md" %}
[and-groupaudio.md](and-groupaudio.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/setup-parameters/and-groupview.md" %}
[and-groupview.md](../advanced-settings/setup-parameters/and-groupview.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/setup-parameters/and-groupmode.md" %}
[and-groupmode.md](../advanced-settings/setup-parameters/and-groupmode.md)
{% endcontent-ref %}

{% content-ref url="../director-settings/rooms.md" %}
[rooms.md](../director-settings/rooms.md)
{% endcontent-ref %}




---
description: Tells the system to not filter out audio streams when using &group
---

# \&groupaudio

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&ga`

## Details

This just enables the guest or scene to not filter out audio streams that are contained in other sub-groups.

By default a stream assigned to one group won't be visible or audible to those in another group. `&groupaudio` prevents audio from being filtered, but keeps the video filtering in place.

## Related

{% content-ref url="and-group.md" %}
[and-group.md](and-group.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/setup-parameters/and-groupmode.md" %}
[and-groupmode.md](../advanced-settings/setup-parameters/and-groupmode.md)
{% endcontent-ref %}




---
description: Filters ICE candidates
---

# \&icefilter

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Options

Example: `&icefilter=tcp`

<table><thead><tr><th width="222">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>tcp</code></td><td>Filters TCP ICE candidates</td></tr><tr><td><code>udp</code></td><td>Filters UDP ICE candidates</td></tr><tr><td><code>host</code></td><td>Filters HOST ICE candidates</td></tr></tbody></table>

## Details

Filters out ICE candidates that do not include the specified word in the candidate string.

Added for advanced use-cases and testing purposes.

{% hint style="warning" %}
This is an advanced parameter that can stop your links from working correctly.
{% endhint %}




---
description: Forces TCP mode
---

# \&tcp

General Option! ([`&push`](../source-settings/push.md), [`&room`](room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Details

Forces TCP mode if connected to a TURN server.

Versus the default, which may be UDP or TCP.

## Related

{% content-ref url="turn.md" %}
[turn.md](turn.md)
{% endcontent-ref %}




---
description: Shows a help-screen on the guest joining
---

# \&tips

Sender-Side Option! ([`&push`](../source-settings/push.md))

## Details

Shows a help-screen on the guest joining.\
.png>)

Also available as a director room toggle to add to the guest's invite link.\
 (2).png>)




---
description: Pre-configures the selected video device
---

# \&videodevice

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&vdevice`
* `&vd`

## Options

Example: `&videodevice=BRIO_4K`

<table><thead><tr><th width="150">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>0</code></td><td>disable the video camera automatically. No option to change it during setup is provided.</td></tr><tr><td><code>1</code> | (no value given)</td><td>auto-select the default video camera. No option to change it will be allowed.</td></tr><tr><td>(string value)</td><td>auto-select a video device that has a label containing that same string specified. Whitespaces in names can be replaced with underscores.<br><br>Device IDs can also be used; exact match only in that case.</td></tr></tbody></table>

## Details

It can be changed after the connection has been established.\
.png>)

Useful for helping a remote guest skip-past the complex setup of their camera/audio.

You can use this option to also disable a guest's camera, potentially allowing for guest connections that have no video or audio. This is a great option if you want to use midi-only transport, add some hidden IFRAME control, or just wanted to text chat.

For a device like an iPhone, you can pass a string value such as `&videodevice=back` to specify the back camera by default. For Android, you might try `rear` instead of `back`, but it will depend on the name the manufacture gave the camera.

When combined with [`&webcam`](and-webcam.md) and [`&autostart`](and-autostart.md), you can have the camera start publishing instantly, often without any user interaction at all. Keep in mind that some browsers will still need to ask for permissions or require a user-gesture for things to function correctly though.

{% hint style="info" %}
See [vdo.ninja/devices](https://vdo.ninja/devices) to see the device IDs and device names. DeviceIDs are specific to VDO.Ninja's domain, while device names are not. The page will also auto-create links for  you, just by clicking on the respective device.
{% endhint %}

When using `&videodevice=videoDevice`, the name matching order sorts based on "NameStartsWith", then "ExactDeviceID", and then finally "NameIncludes". This should avoid the Streamlabs OBS Virtual Cam being selected when you actually want the OBS Virtual Camera being selected, as the two devices both contain `obs virtual camera` in their name.

#### Director's room toggles

Auto-selects the default camera of a guest by adding `&vd` to the guest's invite link.\
.png>)

Disables the guest's camera by adding `&vd=0` to the guest's invite link.\
 (2).png>)

## Related

{% content-ref url="../newly-added-parameters/and-vdo.md" %}
[and-vdo.md](../newly-added-parameters/and-vdo.md)
{% endcontent-ref %}

{% content-ref url="audiodevice.md" %}
[audiodevice.md](audiodevice.md)
{% endcontent-ref %}

{% content-ref url="and-nosettings.md" %}
[and-nosettings.md](and-nosettings.md)
{% endcontent-ref %}

{% content-ref url="and-webcam.md" %}
[and-webcam.md](and-webcam.md)
{% endcontent-ref %}

{% content-ref url="and-autostart.md" %}
[and-autostart.md](and-autostart.md)
{% endcontent-ref %}

{% content-ref url="and-device.md" %}
[and-device.md](and-device.md)
{% endcontent-ref %}




---
description: Pre-configures the selected audio device
---

# \&audiodevice

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&adevice`
* `&ad`

## Options

Example: `&audiodevice=Cable_Output`

| Value                   | Description                                                                                                          |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `0`                     | disable audio source automatically; no option to change it during setup is provided.                                 |
| `1` \| (no value given) | auto-select the default audio; no option to change it will be allowed.                                               |
| `Cable_Output`          | will match against "CABLE Output (VB-Audio Virtual Cable). Use any other string to match against other device names. |

## Details

It can be changed after the connection has been established. Useful for helping a remote guest skip-past the complex setup of their camera/audio.\
.png>)

You can pass a string name to auto-select an audio device that has a label containing that same string.

You can pass a device ID as well; see [vdo.ninja/devices](https://vdo.ninja/devices) to see the device IDs (specific to VDO.Ninja's domain).

Setting this option to `&audiodevice=0` will also disable the guest's microphone, potentially allowing for guest connections that have no video or audio. You might do this if you needed midi-only transport, hidden IFRAME control, or just to chatting.

{% hint style="info" %}
See [vdo.ninja/devices](https://vdo.ninja/devices) to see the device IDs and device names. DeviceIDs are specific to VDO.Ninja's domain, while device names are not. \
\
This web-based tool will also auto-create links for you, just by clicking on the respective device.
{% endhint %}

There is a toggle in the director's room which adds `&ad` to the guest's invite link. (2).png>)

### Update in V22

`&audiodevice` can accept multiple audio devices now. `&audiodevice=cam,cable` for example, will select the camlink and virtual audio cable devices as an audio source when joining.

`&audiodevice={device name}` will now also now show the selected audio devices before joining, while `&audiodevice=1` or `&audiodevice=0` will still hide the option to change or see audio devices.

## Related

{% content-ref url="and-nosettings.md" %}
[and-nosettings.md](and-nosettings.md)
{% endcontent-ref %}

{% content-ref url="videodevice.md" %}
[videodevice.md](videodevice.md)
{% endcontent-ref %}




---
description: Set a custom screenshare quality
---

# \&screensharequality

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&ssq`

## Options

Example: `&screensharequality=1`

| Value | Description   |
| ----- | ------------- |
| `0`   | 1080p         |
| `1`   | 720p          |
| `2`   | 360p          |
| -1    | unconstrained |

## Details

{% hint style="info" %}
Update on V22:\
`&screensharequality` applies now to both primary and secondary types of screen-shares. Before [`&quality`](../advanced-settings/video-parameters/and-quality.md) was needed for primary screen share quality setting.
{% endhint %}

When a guest shares their screen during a group chat, it creates a secondary VDO.Ninja session to share that screen, alongside their active webcam. Two streams as a result.

Using this parameter will give you control over the quality of the screen share, specifically, overriding what you might have set with [`&quality`](../advanced-settings/video-parameters/and-quality.md). It will not impact the webcam quality.

Set a target quality for your screen share, when you screen share as a secondary stream (in a room).

### Achieving higher sharpness

If looking to screen share a document at the highest quality possible, consider the follow URL parameters:

* `&screensharequality=-1` may be a good option for screen sharing documents, where more sharpness is needed.
* `&screensharecontenthint=detail` to hint to use higher resolution over frame rates; this would be applied to the viewer's URL.
* `&codec=av1` can also be applied to the viewer's URL to change to a better video codec.
* `&screensharebitrate=6000` on the viewer side can increase the video bitrate, but you can go upwards of 20000-kbps if needed for heavier motion-based video.
* `&sharperscreen` on the viewer end can avoid scaling down the image if the playback window is smaller than the video's native resolution.  This will avoid double aliasing issues.
* As well, if using OBS Studio for playback, you can add a sharpness filter to the video to improve the clarity. This can undo some of the softness caused by video compression, improving edge sharpness.
*   If in a group room, as a guest, the director can increase the total bitrate of the room, which will improve the screen share quality for all the guests in the room. By default, guests and directors view a screen share at a relatively low bitrate.\
    \

    <figure><figcaption></figcaption></figure>

## Related

{% content-ref url="../advanced-settings/video-parameters/and-quality.md" %}
[and-quality.md](../advanced-settings/video-parameters/and-quality.md)
{% endcontent-ref %}

{% content-ref url="screenshareid.md" %}
[screenshareid.md](screenshareid.md)
{% endcontent-ref %}

{% content-ref url="screensharefps.md" %}
[screensharefps.md](screensharefps.md)
{% endcontent-ref %}




---
description: Applies effects to the video/audio feeds
---

# \&effects

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&effect`

## Options

Example: `&effects=7` or `&effects=zoom`

<table><thead><tr><th width="227">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>Shows a "Digital Video Effects" panel when setting up devices</td></tr><tr><td><code>0</code> | <code>false</code> | <code>off</code></td><td>Disables effects</td></tr><tr><td><code>1</code> | <code>facetracking</code></td><td>Face tracker (legacy native FaceDetector auto-crop)</td></tr><tr><td><code>facecrop</code> | <code>autofacecrop</code></td><td>Auto face crop with native FaceDetector plus MediaPipe fallback</td></tr><tr><td><code>-1</code></td><td>Flip image</td></tr><tr><td><code>2</code></td><td>Mirror image</td></tr><tr><td><code>-2</code></td><td>Flip + mirror image</td></tr><tr><td><code>3</code></td><td>Background blur</td></tr><tr><td><code>4</code></td><td>Virtual Greenscreen</td></tr><tr><td><code>5</code></td><td>Background replacement</td></tr><tr><td><code>6</code></td><td>Face mesh overlay with bundled MediaPipe FaceLandmarker</td></tr><tr><td><code>7</code> | <code>digitalzoom</code></td><td>Zoom (software-based zoom)</td></tr><tr><td><code>8</code></td><td><a data-mention href="effects.md#and-effects-8">#and-effects-8</a></td></tr><tr><td><code>9</code></td><td>Legacy Jeeliz face-box sample effect</td></tr><tr><td><code>10</code></td><td>Legacy dog ears and nose alias</td></tr><tr><td><code>11</code> | <code>anon</code></td><td>Anonymous face mask</td></tr><tr><td><code>13</code></td><td>New experimental background blur effect; it's not supported by most browsers/systems and its in origin trial</td></tr></tbody></table>

## Details

Adding `&effects` to a guest link enables the drop-down menu for Digital Video Effects. The guest can then choose the digital video effect via the drop-down menu.\
 (2) (1).png>)

This is on by default when using a basic push link outside of a room.

You can pre-select the digital video effect by adding `&effects=X` (see [Options](effects.md#options) above) to a guest/push link.

The guest can change the digital video effect dynamically via the video settings panel if you have added `&effects` to the guest's URL.

You can also pre-select the effect value by adding [`&effectvalue`](../newly-added-parameters/and-effectvalue.md) to the URL. ie: the amount of blur.

### Greenscreen performance

`&effects=4` enables a virtual Greenscreen on the publisher side.

Green screen doesn't require SIMD support to work, although it won't work as well without it on. There's a little warning info icon (!) if SIMD is not enabled.

Please do enable Webassembly-SIMD support under `chrome://flags/` if you'd like to see a large reduction in CPU load when using this feature.

### Important Note for `&effects=1`

{% hint style="warning" %}
`&effects=1` requires the use of the Chromium experimental face detection API, as I'm using the built-in browser face-tracking model for this. You can enable the API flag here: `chrome://flags/#enable-experimental-web-platform-features`\
My hope is that this feature will eventually be enabled by default within Chromium, as loading a large ML model to do face detection otherwise is a bit heavy; you may need to enable this within the OBS CLI if wishing to use it there?
{% endhint %}

### `&effects=facecrop`

`&effects=facecrop`, `&autofacecrop`, and `&facecrop` enable the newer auto face crop effect. It keeps the sender's face framed by cropping and panning through the existing canvas effects pipeline. It first tries the browser's native `FaceDetector` API and falls back to the bundled MediaPipe face detector model when available. Existing `&facetracker`, `&facetracking`, and `&effects=1` links keep their original behavior.

### `&effects=6`

`&effects=6` and `&facemesh` render a face mesh overlay using the bundled MediaPipe FaceLandmarker model. The older TensorFlow.js face mesh path can still be requested with `&legacyfacemesh` or `&tfjsfacemesh`.

### Legacy face effects

`&effects=9` is a legacy Jeeliz sample effect that draws a face-tracking box. `&effects=10` is a legacy alias for the dog ears and nose effect. These values are kept for backwards compatibility.

### `&effects=8`

Added `&effects=8`, which might be useful if using a Camlink or simple HDMI capture device and [`&record`](../advanced-settings/recording-parameters/and-record.md) mode. The current `&record` mode doesn't seem to always scale down the video before recording (browser issue it seems), so local file recordings might be 4K in size, despite the target resolution being set much lower. `&effects=8` will use a canvas to first resize the video though, and then recordings will be based on that, making smaller recording sizes possible. (You could also use `&effects=7`, which then provides digital zooming controls and is otherwise the same thing).

This `&effects=8` mode might also be helpful in solving issues with cameras disconnecting or having their frame rate change while recording, causing issues with the recording. The canvas acts as a reliable middle man between the camera and output video stream, so if the camera's input stream fails, the recording stream will not be impacted, other than perhaps skipping some frames. The canvas is sensitive to CPU load or browser throttling though, so frame rates may fluctuate more often when using it, so I can't suggest using it unless the guest/user is known to have a problematic camera.

### `&effects=7` (Zoom)

[`&effectvalue=1.2`](../newly-added-parameters/and-effectvalue.md) will now work with `&digitalzoom` (`&effects=7`), so you can trigger the camera to digitally zoom in on load. This works regardless of whether the camera supports zooming or not, as it is software based. Software zoom offers lower quality than hardware-based or driver-based zoom, but the zoom effect itself is often quite smooth in comparison to hardware based zoom.

## Related

{% content-ref url="../newly-added-parameters/and-effectvalue.md" %}
[and-effectvalue.md](../newly-added-parameters/and-effectvalue.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-chunked.md" %}
[and-chunked.md](../newly-added-parameters/and-chunked.md)
{% endcontent-ref %}




---
description: Sets whether audio auto-normalization is ON or OFF
---

# \&autogain

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&agc`
* `&ag`

## Options

Example: `&autogain=1`

| Value | Description                  |
| ----- | ---------------------------- |
| `0`   | audio auto-normalization off |
| `1`   | audio auto-normalization On  |

## Details

Audio auto-normalization is ON by default in VDO.Ninja.

You can turn off auto-normalization by adding `&autogain=0` to a source link (guest). If you are using [`&proaudio`](../advanced-settings/audio-parameters/and-proaudio.md), auto-normalization gets turned off. You can enable it again with `&proaudio&autogain=1`.

You can also switch it on or off via the audio settings. If you want the guests to be able to change the audio settings by themselves, use [`&mediasettings`](../newly-added-parameters/and-mediasettings.md) on the guests' link, as per default only the director can change the audio settings of the guests.

.png>)

Your browser will try to keep optimum audio levels.

## Known issues with auto-gain

Some microphones or devices with software-based gain controls can have problems with auto-gain. The microphone volume might go to high, causing clipping, for example, or it might interfere with the gain of other applications.

If using a Chromium-based browser, like Chrome, Edge or Brave, you can either disable auto-gain or you can go into your browser's settings and disable the browser from being able to control the device's input volume. The link to this option is here: [chrome://flags/#enable-webrtc-allow-input-volume-adjustment](chrome://flags/#enable-webrtc-allow-input-volume-adjustment) (as of March 2024 at least)\
\
Please note that this issue seems to be a Chromium-related issue, and it is not VDO.Ninja specific. If you do disable auto-gain within VDO.Ninja, the option to manually increase your gain is still normally available also.

## Related

{% content-ref url="../newly-added-parameters/and-screenshareautogain.md" %}
[and-screenshareautogain.md](../newly-added-parameters/and-screenshareautogain.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/audio-parameters/and-audiogain.md" %}
[and-audiogain.md](../advanced-settings/audio-parameters/and-audiogain.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/audio-parameters/and-volume.md" %}
[and-volume.md](../advanced-settings/audio-parameters/and-volume.md)
{% endcontent-ref %}




---
description: >-
  Lowers your mic volume to 10% of its current value based on volume-level
  activity
---

# \&noisegate

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&gating`
* `&gate`
* `&ng`

## Options

Example: `&noisegate=1`

| Value                   | Description                                                                |
| ----------------------- | -------------------------------------------------------------------------- |
| `0`                     | hides it from the menu                                                     |
| `1` \| (no value given) | enables the new noise gate (see Details)                                   |
| `2`                     | will mute the speakers when you are talking                                |
| `3`                     | will mute the speakers when someone else is talking (mainly for debugging) |
| `4`                     | will mute the microphone when someone else is speaking                     |

## Details

The default setting is OFF. You can switch on the noise gate in the audio settings:\
.png>)

This is a new noise gate, that lowers your mic volume to 10% of its current value based on volume-level activity. If you haven't made a significant sound in few seconds, the noise gate kicks in, and will re-enable when a significant noise is detected. It will take about 300-ms for the volume to recover once the noise triggers it back on, which can be a small bit harsh/distracting at times.

The point of this feature is to allow guests who might be in a rather noisy room or who are unable to use echo cancellation to still engage with a chat, without them introducing feedback back into the room.

This is a very hard and aggressive noise filter, and a guest won't be audible to others in the room if others in the room are currently talking.

User feedback on this feature welcomed.

### Noise Gate Settings

[`&noisegatesettings`](../advanced-settings/audio-parameters/and-noisegatesettings.md) is used in conjunction with `&noisegate`. This feature lets you tweak the noise-gate's variables, making it more or less aggressive as needed.

It takes a comma separated list:

* First value is target gain (0 to 100), although 0 to 40 is probably the recommended range here.
* Second value is the threshold value where the gate is triggered if below it. \~ 100 is loudly speaking, \~ 20 is light background noise levels, and under 5 is quiet background levels.
* Third value is how 'sticky' the gate-open position is, in milliseconds. Having this set to a few seconds should prevent someone from being cut off while speaking or if taking a short pause.

Example:\
[`https://vdo.ninja/alpha/?noisegate&noisegatesettings=10,25,3000`](https://vdo.ninja/alpha/?noisegate\&noisegatesettings=10,25,3000)

To help users with testing the noise gate and configurating the noise gate settings, there's an interactive page here for it: [https://vdo.ninja/noisegate](https://vdo.ninja/noisegate)

## Related

{% content-ref url="../advanced-settings/audio-parameters/and-noisegatesettings.md" %}
[and-noisegatesettings.md](../advanced-settings/audio-parameters/and-noisegatesettings.md)
{% endcontent-ref %}

{% content-ref url="and-denoise.md" %}
[and-denoise.md](and-denoise.md)
{% endcontent-ref %}




---
description: Automatic echo-cancellation is ON or OFF
---

# \&echocancellation

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&aec`
* `&ec`

## Options

Example: `&echocancellation=1`

| Value | Description                               |
| ----- | ----------------------------------------- |
| `0`   | Turns OFF the automatic echo-cancellation |
| `1`   | Turns ON the automatic echo-cancellation  |

## Details

Automatic echo-cancellation is ON by default in VDO.Ninja.

You can turn off echo-cancellation by adding `&aec=0` to a source link (guest). If you are using [`&proaudio`](../advanced-settings/audio-parameters/and-proaudio.md), echo-cancellation gets turned off. You can enable it again with `&proaudio&aec=1`.

You can also switch it on or off via the audio settings. If you want the guests to be able to change the audio settings by themselves, use [`&mediasettings`](../newly-added-parameters/and-mediasettings.md) on the link of the guests, as per default only the director can change the audio settings of the guests.

.png>)

May need to be disabled to use [`&proaudio`](../advanced-settings/audio-parameters/and-proaudio.md) on some older browsers.

## Related

{% content-ref url="../advanced-settings/audio-parameters/and-proaudio.md" %}
[and-proaudio.md](../advanced-settings/audio-parameters/and-proaudio.md)
{% endcontent-ref %}

{% content-ref url="noisegate.md" %}
[noisegate.md](noisegate.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-screenshareaec.md" %}
[and-screenshareaec.md](../newly-added-parameters/and-screenshareaec.md)
{% endcontent-ref %}




# &accelerometer

**Also known as:** `&sensors`, `&sensor`, `&gyro`, `&gyros`

#### **Description**

Enables device motion and orientation sensor data transmission, allowing real-time sharing of accelerometer, gyroscope, and other sensor information.

#### **Sender-Side Option**

This parameter activates sensor data collection and transmission from devices that support motion sensors.

#### **Usage**

* **`&accelerometer`** - Enable at default rate (30 Hz)
* **`&accelerometer=60`** - Enable at 60 Hz update rate
* **`&sensor=10`** - Enable at 10 Hz update rate
* **`&gyro=30`** - Alias usage

#### **Examples**

```
https://vdo.ninja/?push=streamID&accelerometer
https://vdo.ninja/?push=streamID&sensor=60
https://vdo.ninja/?room=roomname&gyro=30
```

#### **Sensor Data Included**

* **Accelerometer**: Linear acceleration (x, y, z)
* **Gyroscope**: Rotational velocity
* **Orientation**: Device orientation in space
* **Magnetometer**: Compass heading (if available)
* **Linear Acceleration**: Acceleration without gravity
* **Absolute Orientation**: Quaternion orientation

#### **Update Rates**

* **Default**: 30 Hz (30 updates per second)
* **Minimum**: 1 Hz
* **Maximum**: 60 Hz (device dependent)
* **Recommended**: 10-30 Hz for most applications

#### **Device Support**

* **Smartphones**: Full support (iOS/Android)
* **Tablets**: Full support
* **Laptops**: Limited (some have accelerometers)
* **Desktop**: Usually no sensors

#### **Browser Requirements**

* Requires HTTPS connection
* User permission required
* Not all browsers support all sensors

#### **Data Format**

Sensor data is transmitted as structured data containing:
- Timestamp
- Sensor type
- X, Y, Z values
- Additional sensor-specific data

#### **Use Cases**

* Motion-controlled applications
* VR/AR experiences
* Game controllers
* Motion analysis
* Remote device monitoring
* Interactive presentations

#### **Performance Notes**

* Higher rates increase bandwidth usage
* Can impact battery life on mobile
* May affect device performance
* Consider network latency

#### **Privacy Considerations**

* Requires explicit user permission
* Can reveal device movement patterns
* May be disabled by privacy settings
* Use responsibly

#### **Related Parameters**

* [`&sensorfilter`](../settings-parameters/and-sensorfilter.md) - Filter specific sensors
* [`&remote`](../general-settings/remote.md) - Remote control features
* [`&ptz`](ptz.md) - Pan-tilt-zoom control
* [`&api`](../general-settings/api.md) - API for sensor data access




---
description: Skips the camera/audio device or screenshare selection
---

# \&autostart

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&autojoin`
* `&aj`
* `&as`

## Details

Auto starts when the camera/audio device or screenshare is ready. Useful for helping a remote guest skip-past the complex setup of their camera/audio.

Can be used together with [`&webcam`](and-webcam.md) or [`&screenshare`](screenshare.md) to join the room or start the stream immediately.

## Related

{% content-ref url="easyexit.md" %}
[easyexit.md](easyexit.md)
{% endcontent-ref %}

{% content-ref url="and-webcam.md" %}
[and-webcam.md](and-webcam.md)
{% endcontent-ref %}

{% content-ref url="screenshare.md" %}
[screenshare.md](screenshare.md)
{% endcontent-ref %}




---
description: Applies a generic audio compressor to the local microphone
---

# \&compressor

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&comp`

## Details

By adding `&compressor` to a source link, it applies a generic audio compressor to the local microphone.

An audio compressor can help reduce spikes in audio loudness.

{% hint style="info" %}
The compressor is **off by default**.
{% endhint %}

{% hint style="warning" %}
This will enable the audio processing pipeline.
{% endhint %}

There is a toggle in the director's room which adds `&comp` to the guest's invite link.\
.png>)

## Update in Version 22

There is now an option to control the compressor remotely (3 states for the compressor; Off/On/Limiter)

 (4) (2).png>)

## Related

{% content-ref url="and-limiter.md" %}
[and-limiter.md](and-limiter.md)
{% endcontent-ref %}




---
description: Turn audio noise reduction filter ON or OFF
---

# \&denoise

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&dn`

## Options

Example: `&compressor=1`

| Value | Description |
| ----- | ----------- |
| `0`   | Filter Off  |
| `1`   | Filter On   |

## Details

Noise suppression reduces background audio noise from your surrounding environment.

Noise suppression is ON by default in VDO.Ninja.

You can turn off noise suppression by adding `&denoise=0` to a source link (guest). If you are using [`&proaudio`](../advanced-settings/audio-parameters/and-proaudio.md), echo-cancellation gets turned off. You can enable it again with `&proaudio&denoise=1`.

You can also switch it on or off via the audio settings. If you want the guests to be able to change the audio settings by themselves, use [`&mediasettings`](../newly-added-parameters/and-mediasettings.md) on the link of the guests, as per default only the director can change the audio settings of the guests.

.png>)

## Related

{% content-ref url="noisegate.md" %}
[noisegate.md](noisegate.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-screensharedenoise.md" %}
[and-screensharedenoise.md](../newly-added-parameters/and-screensharedenoise.md)
{% endcontent-ref %}




---
description: Same as &audiodevice or &videodevice, but applies to both
---

# \&device

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&d`

## Options

Example: `&device=Brio_4K`

<table><thead><tr><th width="187">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>0</code></td><td>disable the audio and video devices; no option to change it during setup is provided.</td></tr><tr><td><code>1</code></td><td>auto-select the default video and audio devices; no option to change it will be allowed.</td></tr><tr><td>(string value)</td><td>auto-select a video and audio device that has a label containing that same string; whitespaces in names can be replaced with underscores.</td></tr></tbody></table>

## Details

If you set `&device=0`, you disable audio and video inputs, but chat is still available.

Chat-only guests can access a group-room this way.

## Related

{% content-ref url="videodevice.md" %}
[videodevice.md](videodevice.md)
{% endcontent-ref %}

{% content-ref url="audiodevice.md" %}
[audiodevice.md](audiodevice.md)
{% endcontent-ref %}




---
description: >-
  Provides access to a generic audio equalizer that can be applied to the local
  microphone
---

# \&equalizer

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&eq`

## Details

Adding `&equalizer` to a source link, it provides access to a generic audio equalizer that can be applied to the local microphone.

It can be accessed via the Audio Settings page or the Director can remotely adjust it.

.png>)

{% hint style="warning" %}
Enables the audio processing pipeline.
{% endhint %}

## Related

{% content-ref url="and-compressor.md" %}
[and-compressor.md](and-compressor.md)
{% endcontent-ref %}

{% content-ref url="and-limiter.md" %}
[and-limiter.md](and-limiter.md)
{% endcontent-ref %}




---
description: Allows the user to select a video or audio file as a source for streaming
---

# \&fileshare

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&fs`

## Details

Adding `&fileshare` to a URL allows the user to select a video or audio file as a source for streaming.

The stream can be paused and scrubbed like a normal video/audio file. It will auto-loop when it ends.

Supports audio-only files as well as common video formats. Depends on your browser. If you mute the video, it will mute the video for all the viewers as well. It is extremely simple in functionality and is only available when the URL is used. The resolution used will be limited by the video's native resolution.

{% hint style="warning" %}
The video will be **transcoded for each** connected **guest**!
{% endhint %}

<figure><figcaption></figcaption></figure>




---
description: Enables a "Raise Hand" button for guests
---

# \&hands

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&hand`

## Details

Adds a button for guests to raise their hands.

.png>)

If pressed, and the user is in a room, the room's director will get a notification that the user pressed the button.\
.png>)

It will do nothing if the room does not have a director in it.

The director can dismiss the user's action.

There is a toggle in the director's room which adds `&hand` to the guest's invite link..png>)

## Related

{% content-ref url="and-notify.md" %}
[and-notify.md](and-notify.md)
{% endcontent-ref %}




---
description: Sets the maximum height of the video allowed in pixels
---

# \&height

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&h`

## Options

Example: `&height=1080`

| Value                         | Description  |
| ----------------------------- | ------------ |
| (some positive integer value) | height in px |

## Details

Sets the maximum height of the video allowed in pixels.

Actual height may be less based on bandwidth allowances.

Limiting the height can force the camera to use higher frame rates.

Limiting the height can reduce the CPU load.

[https://vdo.ninja/supports](https://obs.ninja/supports) will list the support resolutions of your default camera.

[https://webrtchacks.github.io/WebRTC-Camera-Resolution/](https://webrtchacks.github.io/WebRTC-Camera-Resolution/) Is a tool to help you find the resolutions supported by your camera.

You can use [`&scale=50`](../advanced-settings/view-parameters/scale.md) also, as a viewer, to scale down a selected width/height to something more exact.

{% hint style="danger" %}
If the camera cannot support the height, **it will fail**.
{% endhint %}

You can get [4K](../guides/how-to-stream-4k-video-using-vdo.ninja.md) by adding `&width=3840&height=2160` to the source link if the camera supports it.

## Related

{% content-ref url="and-width.md" %}
[and-width.md](and-width.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/video-parameters/and-aspectratio.md" %}
[and-aspectratio.md](../advanced-settings/video-parameters/and-aspectratio.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/video-parameters/and-quality.md" %}
[and-quality.md](../advanced-settings/video-parameters/and-quality.md)
{% endcontent-ref %}




---
description: Applies a generic audio limiter to the local microphone
---

# \&limiter

Sender-Side Option! ([`&push`](push.md))

## Details

`&limiter` applies a generic audio limiter to the local microphone.

A limiter is like an aggressive compressor.

The limiter is **off by default**.

{% hint style="warning" %}
Enables the audio processing pipeline.
{% endhint %}

{% hint style="danger" %}
It cannot be used along with the [`&compressor`](and-compressor.md) option.
{% endhint %}

## Related

{% content-ref url="and-compressor.md" %}
[and-compressor.md](and-compressor.md)
{% endcontent-ref %}




---
description: Limits total of view and push connections
---

# \&maxconnections

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&mc`

## Options

Example: `&maxconnections=5`

| Value               | Description                     |
| ------------------- | ------------------------------- |
| (any integer value) | Will set maximum to given value |

## Details

Limits total of view and push connections to the given value.

## Related

{% content-ref url="../advanced-settings/view-parameters/and-maxpublishers.md" %}
[and-maxpublishers.md](../advanced-settings/view-parameters/and-maxpublishers.md)
{% endcontent-ref %}

{% content-ref url="and-maxviewers.md" %}
[and-maxviewers.md](and-maxviewers.md)
{% endcontent-ref %}




---
description: >-
  Like &fps, except it will allow for lower frame rates if the specific frame
  rate requested failed
---

# \&maxframerate

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&mfr`
* `&mfps`

## Options

Example: `&maxframerate=60`

| Value                    | Description                    |
| ------------------------ | ------------------------------ |
| (positive integer value) | Frame rate (frames per second) |

## Details

Like [`&fps`](../advanced-settings.md#framerateframe-rate), except it will allow for lower frame rates if the specific frame rate requested failed.

You can set `&maxframerate=60` and the system automatically selects 30 if your camera doesn't support a frame rate of 60.

## Related

{% content-ref url="../advanced-settings/video-parameters/and-fps.md" %}
[and-fps.md](../advanced-settings/video-parameters/and-fps.md)
{% endcontent-ref %}




---
description: Limits the number of viewers allowed
---

# \&maxviewers

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&mv`

## Options

Example: `&maxviewers=8`

| Value                    | Description         |
| ------------------------ | ------------------- |
| (positive integer value) | max allowed viewers |

## Details

Useful for iOS devices that might explode if more than 3 video viewers connect.

Useful to prevent publicly shared guest links from being crashed due to too many viewer requests.

## Related

{% content-ref url="../advanced-settings/view-parameters/and-maxpublishers.md" %}
[and-maxpublishers.md](../advanced-settings/view-parameters/and-maxpublishers.md)
{% endcontent-ref %}

{% content-ref url="and-maxconnections.md" %}
[and-maxconnections.md](and-maxconnections.md)
{% endcontent-ref %}




---
description: Delays the microphone by specified time in ms
---

# \&micdelay

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&md`

## Options

Example: `&micdelay=100`

| Value                    | Description                         |
| ------------------------ | ----------------------------------- |
| (positive integer value) | Delay to add in milliseconds        |
| (no value given)         | Will show the mic delay as a slider |

## Details

Delays the microphone by specified time in ms.

### Update in Version 22

Added the "mic delay" option as a slider to the director's control; it's available by default, with up to 500-ms of delay ready. If you make use of it, it will "enable" the `&micdelay` web audio node remotely if not yet on, which might cause a clicking sound. Hoping that this though can help with problematic guests who might be out of sync. This is not the same as [`&buffer`](../advanced-settings/view-parameters/buffer.md) or [`&sync`](../advanced-settings/view-parameters/sync.md) delay, which are a view-side parameters.

 (1) (4).png>)

`&micdelay`, if used on a basic push link, will show the mic delay as a slider now also. So you can adjust it as needed. I don't show the slider by default unless using the URL parameter, as I don't think its a commonly used feature.\
 (2) (1).png>)

## Related

{% content-ref url="../newly-added-parameters/and-audiolatency.md" %}
[and-audiolatency.md](../newly-added-parameters/and-audiolatency.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/view-parameters/sync.md" %}
[sync.md](../advanced-settings/view-parameters/sync.md)
{% endcontent-ref %}




---
description: Mini self-preview at the top right corner
---

# \&minipreview

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&mini`

## Options

Example: `&minipreview=0`

<table><thead><tr><th width="247">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>shows the mini self-preview at the top right corner</td></tr><tr><td><code>0</code></td><td>disables the mini preview in broadcast mode</td></tr></tbody></table>

## Details

## Details

Shows the mini self-preview at the top right corner. This is the default behavior when [`&broadcast`](../advanced-settings/view-parameters/broadcast.md) mode is on.

 (1) (2).png>)

You can change the default position of the mini preview with [`&minipreviewoffset`](../advanced-settings/video-parameters/and-minipreview-1.md).

## Related

{% content-ref url="../advanced-settings/video-parameters/and-largepreview.md" %}
[and-largepreview.md](../advanced-settings/video-parameters/and-largepreview.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/video-parameters/and-minipreview-1.md" %}
[and-minipreview-1.md](../advanced-settings/video-parameters/and-minipreview-1.md)
{% endcontent-ref %}

{% content-ref url="and-preview.md" %}
[and-preview.md](and-preview.md)
{% endcontent-ref %}

{% content-ref url="and-nopreview.md" %}
[and-nopreview.md](and-nopreview.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/view-parameters/broadcast.md" %}
[broadcast.md](../advanced-settings/view-parameters/broadcast.md)
{% endcontent-ref %}




---
description: Starts with the microphone muted by default
---

# \&mute

Sender-Side Option! ([`&push`](push.md), [`&director`](../viewers-settings/director.md))

## Aliases

* `&muted`
* `&m`

## Details

Starts with the microphone muted by default. The guest can switch on the microphone.

 (2) (1) (1) (3).png>)

### Update in [v23](../releases/v23.md)

`&mute` works with the director now, so the mic starts muted when you enable your microphone or when using [`&autostart`](and-autostart.md).

## Related

{% content-ref url="and-videomute.md" %}
[and-videomute.md](and-videomute.md)
{% endcontent-ref %}

{% content-ref url="and-mutespeaker.md" %}
[and-mutespeaker.md](and-mutespeaker.md)
{% endcontent-ref %}




---
description: Auto mutes the speaker
---

# \&mutespeaker

General Option! ([`&push`](push.md), [`&room`](../general-settings/room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md), [`&director`](../viewers-settings/director.md))

## Aliases

* `&ms`
* `&speakermute`
* `&sm`
* `&speakermuted`

## Options

Example: `&mutespeaker=0` or `&mutespeaker=false`

| Value            | Description                                                           |
| ---------------- | --------------------------------------------------------------------- |
| (no value given) | the default behavior of this option is to mute inbound audio playback |
| `0` \| `false`   | will have the speaker button unmuted                                  |
| `1` \| `true`    | will have the speaker button muted                                    |

## Details

Sets the speaker to be muted (or unmuted) by default for a push-link, guest, director or view/scene link.

If no value is passed, the default behavior of this option is to mute inbound audio playback. The user can still unmute the audio via the speaker-icon button in their lower control bar.

If looking to mute the audio playback of a view or scene link, [`&noaudio`](../advanced-settings/view-parameters/noaudio.md) is an alternative option that will block audio tracks from connecting in the first place. It can't be toggled on and off though, like `&mutespeaker` can be though.

### Unmuting the director's speaker by default

You can also use this parameter to have a director join the room with their speaker output unmuted by default.

Set the `&mutespeaker` value to `false` or `0` to have the mute button start unmuted. By default, the director joins with their speaker output muted, so this option can be used to have the director join unmuted instead.

[https://vdo.ninja/?director=ROOMNAME\&mutespeaker=0](https://vdo.ninja/?director=ROOMNAME\&mutespeaker=0)

### Muting shared websites ([meshcast.io](https://meshcast.io/) / youtube)

The director and guests can share websites with others in a group room. The audio playback of [meshcast.io](https://meshcast.io/) shared links will respect the `&mutespeaker` parameter used by VDO.Ninja, but other sites that are shared may not respect it.

You can also add [`&mute`](and-mute.md) to a meshcast.io link itself, when sharing it, which will mute just the meshcast video by default for others. This can be useful to avoid echo cancellation issues that sometimes are created when sharing meshcast.io links in a VDO.Ninja group room.

## Related

{% content-ref url="and-mute.md" %}
[and-mute.md](and-mute.md)
{% endcontent-ref %}

{% content-ref url="and-videomute.md" %}
[and-videomute.md](and-videomute.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/view-parameters/noaudio.md" %}
[noaudio.md](../advanced-settings/view-parameters/noaudio.md)
{% endcontent-ref %}




---
description: Disables the local self-preview
---

# \&nopreview

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&np`

## Details

If you don't want to see yourself when in a group chat, this will hide your video.

{% hint style="danger" %}
**iOS users:** This flag will break stuff; You must have a preview if using those devices and wanting to publish.
{% endhint %}

There is a toggle in the director's room which adds `&np` to the guest's invite link. (1).png>)

## Related

{% content-ref url="and-preview.md" %}
[and-preview.md](and-preview.md)
{% endcontent-ref %}

{% content-ref url="and-minipreview.md" %}
[and-minipreview.md](and-minipreview.md)
{% endcontent-ref %}




---
description: Disables the local settings button
---

# \&nosettings

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&ns`

## Details

`&nosettings` disables the local settings button.

You won't be able to change video or audio feeds after initially selecting them. This prevents guests accidentally changing their webcam or microphone after entering a room.

Hides the screen-share button as well.

.png>)




---
description: Hides the speaker button
---

# \&nospeakerbutton

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&nsb`

## Details

Hides the button that can mute the speaker.

.png>)

## Related

{% content-ref url="../viewers-settings/nomicbutton.md" %}
[nomicbutton.md](../viewers-settings/nomicbutton.md)
{% endcontent-ref %}

{% content-ref url="../viewers-settings/and-novideobutton.md" %}
[and-novideobutton.md](../viewers-settings/and-novideobutton.md)
{% endcontent-ref %}




---
description: Audio alerts for raised hands, chat messages and if somebody joins the room
---

# \&notify

Sender-Side Option / Director Option! ([`&push`](push.md), [`&director`](../viewers-settings/director.md))

## Aliases

* `&beep`
* `&tone`

## Details

Add this to a guest's/director's URL and you get audio alerts for raised-hands, chat messages and if somebody joins the room.

{% hint style="warning" %}
If you can't hear a sound, click any button in the room. Then the sounds will be activated.
{% endhint %}

## Advanced configurations

Enable audio notifications for specified events.

* Values: Comma-separated list of: `join`, `leave`, `test`
* Example: `?beep=join,leave` enables just the join and leave sounds
* Example: `?notify=join` enables only join sounds
* Note: Using the parameter without values (e.g., `?beep`) will enable all sound types.

### Custom Sound Settings

#### `customjoin=<url>`

Custom sound for join notifications.

* Value: URL to audio file
* Example: `?customjoin=https://example.com/join.mp3`
* Default if not specified: `./media/join.mp3`

#### `customleave=<url>`

Custom sound for leave notifications.

* Value: URL to audio file
* Example: `?customleave=https://example.com/leave.mp3`
* Default if not specified: `./media/leave.mp3`

#### `custombeep=<url>`

Sets a custom sound for the test tone.

* Value: URL to audio file
* Example: `?custombeep=https://example.com/beep.mp3`
* Supported formats: mp3, wav, ogg, aac, m4a, opus, flac, webm

#### `r2d2`

Replaces the test tone with a robot sound.

* Usage: `?r2d2`
* Effect: Sets test tone to `./media/robot.mp3`

### Volume Control

#### `beepvolume=<number>`

Sets volume for all notification sounds.

* Value: Number between 0-100 for normal volume, >100 for amplified volume
* Example: `?beepvolume=50` for 50% volume
* Example: `?beepvolume=500` for 500% volume using Web Audio API amplification
  * volume values are linear, yet the human ear hears loudness logarithmically, so 500 isn't that much louder.
* Default: 100 (100% volume)

#### Important Volume Limitations

When using `beepvolume` values greater than 100:

* Audio files must be hosted on a server that allows CORS access
* External audio files (like those from myinstants.com) may fail due to CORS restrictions
* If CORS fails, the audio will fallback to normal volume (100% max)
* For best results with amplified volume, host audio files on your own domain
* Volume boost requires Web Audio API support in the browser

### Examples

Basic notification setup:

```url
?beep=join,leave&beepvolume=75
```

Custom sounds with normal volume:

```url
urlCopy?beep=join,leave&customjoin=custom.mp3&customleave=custom2.mp3&beepvolume=100
```

Custom test tone:

```url
?custombeep=https://example.com/tone.mp3
```

R2D2 sounds with custom volume:

```url
?r2d2&beepvolume=80&beep=join,leave
```

### Best Practices

1. When using custom sounds:
   * Host audio files on your own domain to avoid CORS issues
   * Use short, small audio files for better performance
   * Test with both normal and amplified volume settings
2. When using amplified volume:
   * Test with your specific audio files first
   * Have a fallback plan if CORS restrictions prevent volume boost
   * Consider users with different audio setups

### Sound clip resources and hosting

There are sound effects available at [https://www.myinstants.com/](https://www.myinstants.com/), however it's generally not considered polite to directly link to their MP3 audio files. Instead, it is better to download any and host them yourself, perhaps on GitHub or a proper webserver.

As noted, if using `&beepvolume`, and you set it higher than 100, then direct linking to audio files will fail with some sites, such as with myinstants.com.&#x20;

## Related

{% content-ref url="r2d2.md" %}
[r2d2.md](r2d2.md)
{% endcontent-ref %}

{% content-ref url="and-hands.md" %}
[and-hands.md](and-hands.md)
{% endcontent-ref %}




---
description: Target audio bitrate and max bitrate for outgoing audio streams
---

# \&outboundaudiobitrate

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&oab`

## Options

Example: `&outboundaudiobitrate=128`

| Value           | Description                    |
| --------------- | ------------------------------ |
| (integer value) | outbound audio bitrate in kbps |

## Details

Target audio bitrate and max bitrate for outgoing audio streams.

Allows the Director to set their outbound audio bitrate to be shared with guests at something like 160-kbps, while having the guests still be able to share their audio between other guests at the default audio bitrate of around 32-kbps. If the guest sets the audio bitrate ([`&proaudio=1`](../advanced-settings/audio-parameters/and-proaudio.md) or [`&audiobitrate=200`](../advanced-settings/view-parameters/audiobitrate.md)) on the view link will override the publisher's `&outboundaudiobitrate` parameter.

## Related

{% content-ref url="../advanced-settings/audio-parameters/and-proaudio.md" %}
[and-proaudio.md](../advanced-settings/audio-parameters/and-proaudio.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/view-parameters/audiobitrate.md" %}
[audiobitrate.md](../advanced-settings/view-parameters/audiobitrate.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/video-bitrate-parameters/and-outboundvideobitrate.md" %}
[and-outboundvideobitrate.md](../advanced-settings/video-bitrate-parameters/and-outboundvideobitrate.md)
{% endcontent-ref %}




---
description: Forces the guest to have a self-preview
---

# \&showpreview

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&preview`

## Details

Forces the guest to have a self-preview.

## Related

{% content-ref url="and-minipreview.md" %}
[and-minipreview.md](and-minipreview.md)
{% endcontent-ref %}

{% content-ref url="and-nopreview.md" %}
[and-nopreview.md](and-nopreview.md)
{% endcontent-ref %}




---
description: Auto mutes guest's video
---

# \&videomute

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&vm`
* `&videomuted`

## Details

Auto mutes the guest's video when connecting.

 (1) (1) (2) (1) (1).png>)

## Related

{% content-ref url="and-mute.md" %}
[and-mute.md](and-mute.md)
{% endcontent-ref %}

{% content-ref url="and-videomute.md" %}
[and-videomute.md](and-videomute.md)
{% endcontent-ref %}




---
description: Disables screen-sharing as an option
---

# \&webcam

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&wc`

## Details

Automatically selects the Share your Camera option and hides the screen-share button in the control bar.\
.png>)

{% hint style="danger" %}
Do not use while on a director page to autostart a camera; `&autostart&vd=video_device` should handle that.
{% endhint %}

If you would still like the guest to have access to the screen-sharing button once they have joined the call, you can force it to appear with the [`&ssb`](../advanced-settings/settings-parameters/and-screensharebutton.md) option. The [`&webcam`](and-webcam.md) option by default will hide the screen-share button otherwise.

Starting with [v19](../releases/v19/) of VDO.Ninja, there is also the [`&webcam2`](../newly-added-parameters/and-webcam2.md) option; a minor UI variant that requires an additional button press, but more clearly preps the guest to the fact they will be sharing their webcam.

## Related

{% content-ref url="screenshare.md" %}
[screenshare.md](screenshare.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-webcam2.md" %}
[and-webcam2.md](../newly-added-parameters/and-webcam2.md)
{% endcontent-ref %}




---
description: Only shares a website with viewers
---

# \&website

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&iframe`

## Details

Only shares a website with viewers. You can use this to share a YouTube video with the guests.

.png>)




---
description: Sets the maximum width of the video allowed in pixels
---

# \&width

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&w`

## Options

Example: `&width=1920`

| Value                         | Description |
| ----------------------------- | ----------- |
| (some positive integer value) | width in px |

## Details

Sets the maximum width of the video allowed in pixels.

Actual width may be less based on bandwidth allowances.

Limiting the width can force the camera to use higher frame rates.

Limiting the width can reduce CPU load.

{% hint style="danger" %}
If the camera cannot support the width, **it will fail**.
{% endhint %}

You can get [4K](../guides/how-to-stream-4k-video-using-vdo.ninja.md) by adding `&width=3840&height=2160` to the source link if the camera supports it.

## Related

{% content-ref url="and-height.md" %}
[and-height.md](and-height.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/video-parameters/and-aspectratio.md" %}
[and-aspectratio.md](../advanced-settings/video-parameters/and-aspectratio.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/video-parameters/and-quality.md" %}
[and-quality.md](../advanced-settings/video-parameters/and-quality.md)
{% endcontent-ref %}




---
description: Controls unattended privacy-sensitive changes to a sender
---

# \&consent

Sender-Side Option! ([`&push`](push.md))

## Details

Adding this flag to the guest's invite link pre-authorizes otherwise permitted director or authenticated remote-control requests to change the guest's camera, microphone, URL, and digital video effects without another prompt. `&consent` grants no authentication or control capability by itself.

Without this flag, camera and microphone changes still require approval. Digital video effect control asks once per requesting controller and connection because changing or disabling an effect can reveal the sender's background. Approval is kept only in page memory for that live connection; reloading or connecting through another controller requires approval again.

 (1) (1) (1).png>)

### Update on [v23](../releases/v23.md)

Added "change URL" permissions to the `&consent` flag. That is, when using `&consent` on the guest URL, the director can remotely change the guest's URL without additional permission -- it will just change.

## Related

{% content-ref url="../general-settings/remote.md" %}
[remote.md](../general-settings/remote.md)
{% endcontent-ref %}




---
description: Attempts to show the mouse cursor on screen shares
---

# \&screensharecursor

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&cursor`

## Details

Adding `&screensharecursor` to a source link attempts to show the mouse cursor on screen shares.

This flag is introduced in [v18.4](../releases/v18/), but it's largely useless currently due to lack of support from most browsers.

The default cursor state in VDO.Ninja is to not show a cursor, but Chrome/Firefox will still add a cursor overlay in regardless.

If sharing a Chrome tab, Chrome adds the cursor in only when that tab is active.

According to the web spec, we should be able to control the visibility of a cursor, but we can't. Not yet.

You can see this link to tinker with different settings easily, to validate the problem:\
[https://www.webrtc-experiment.com/getDisplayMedia/](https://www.webrtc-experiment.com/getDisplayMedia/)

Generally, to have better control of the cursor, maybe instead capture the screen with OBS and bring the video into VDO.Ninja as a virtual camera.\
For information on alternative ideas on how to hide or show the cursor, you can see the following article.

{% content-ref url="../common-errors-and-known-issues/cursor-shows-when-screen-sharing.md" %}
[cursor-shows-when-screen-sharing.md](../common-errors-and-known-issues/cursor-shows-when-screen-sharing.md)
{% endcontent-ref %}

If none of this is working you might try [YoloMouse](https://store.steampowered.com/app/1283970/YoloMouse/) on Steam:\
[https://store.steampowered.com/app/1283970/YoloMouse/](https://store.steampowered.com/app/1283970/YoloMouse/)

## Related

{% content-ref url="../general-settings/and-nocursor.md" %}
[and-nocursor.md](../general-settings/and-nocursor.md)
{% endcontent-ref %}




---
description: Message ONLY the director
---

# \&directorchat

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&dc`

## Details

When this parameter is set, guest messages will only go to the director.




---
description: Won't ask the user to confirm that they wish to exit or leave the page
---

# \&easyexit

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&ee`

## Details

To prevent accidental page refreshes or exits during a stream, VDO.Ninja will ask the user to confirm they wish to leave the page when they try to. Using `&easyexit` prevents this confirmation pop-up from occurring, which might be useful if you are doing a lot of testing and find the added clicking to be annoying.

It hides this popup:\
 (2).png>)

## Related

{% content-ref url="and-autostart.md" %}
[and-autostart.md](and-autostart.md)
{% endcontent-ref %}




---
description: The preview video will be fullscreen
---

# \&fullscreen

Sender-Side Option! ([`&push`](push.md))

## Details

If publishing a video outside **of** a room, and not viewing any other video except your own preview, that preview will be windowed. This command will make that preview larger, sized to fit the window.

### Purpose

If you combine this command with [`&cleanoutput`](../advanced-settings/design-parameters/cleanoutput.md), you can then cleanly window-capture your preview window and use that instead as a local webcam source elsewhere, such as in OBS. This may potentially use less CPU than using a virtual camera, while still having access to the webcam in multiple applications.

If you load the webcam in OBS first, you'll need to use the Virtual Camera and some special settings to have the webcam be available in other applications, like the browser. Window-capturing is an alternative that uses less CPU and does not require special drivers to be installed.

It is recommend to consider using the Electron Capture app as the window-capture source app, as it is frameless, can be pinned on top, uses less CPU than the Chrome browser, and can be screen-captured or window-captured by most applications. It's also designed for VDO.Ninja, so lots of command line options available.

## Related

{% content-ref url="../advanced-settings/design-parameters/cleanoutput.md" %}
[cleanoutput.md](../advanced-settings/design-parameters/cleanoutput.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/settings-parameters/and-fullscreenbutton.md" %}
[and-fullscreenbutton.md](../advanced-settings/settings-parameters/and-fullscreenbutton.md)
{% endcontent-ref %}




---
description: >-
  When combined with the either &webcam or &screenshare, this option won't
  auto-load the camera/mic selection page
---

# \&intro

Sender-Side Option! ([`&push`](push.md),[`&webcam`](and-webcam.md),[`&screenshare`](screenshare.md))

## Aliases

* `&ib`

## Details

When combined with the either [`&webcam`](and-webcam.md) or [`&screenshare`](screenshare.md), this option won't auto-load the camera/mic selection page. Instead, it shows the main-menu button for either the webcam option or screen-share option.

For some users, this prepares them better for the upcoming request for camera/microphone permissions; particularly useful if using VDO.Ninja as an IFRAME integration.

`&intro&webcam` is the same like [`&wc2`](../newly-added-parameters/and-webcam2.md).\
`&intro&screenshare` is the same like [`&ss2`](../newly-added-parameters/and-screenshare2.md).

## Related

{% content-ref url="and-webcam.md" %}
[and-webcam.md](and-webcam.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-webcam2.md" %}
[and-webcam2.md](../newly-added-parameters/and-webcam2.md)
{% endcontent-ref %}

{% content-ref url="screenshare.md" %}
[screenshare.md](screenshare.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-screenshare2.md" %}
[and-screenshare2.md](../newly-added-parameters/and-screenshare2.md)
{% endcontent-ref %}




---
description: Adds a low-cut filter
---

# \&lowcut

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&lc`
* `&higpass`

## Options

Example: `&lowcut=150`

| Value           | Description                                         |
| --------------- | --------------------------------------------------- |
| (integer value) | Sets the cut-off frequency in hz (default is 100hz) |

## Details

Adds a low-cut filter.

{% hint style="warning" %}
Enables the audio processing pipeline.
{% endhint %}

## Related

{% content-ref url="and-compressor.md" %}
[and-compressor.md](and-compressor.md)
{% endcontent-ref %}

{% content-ref url="and-limiter.md" %}
[and-limiter.md](and-limiter.md)
{% endcontent-ref %}

{% content-ref url="and-equalizer.md" %}
[and-equalizer.md](and-equalizer.md)
{% endcontent-ref %}




---
description: Share audio-only; no video publishing allowed
---

# \&miconly

Sender-Side Option! ([`&push`](push.md))

## Details

Mostly just an alias of `&videodevice=0&webcam`, but it also further hides the option to later select a video device via the settings menu. It also hides the 'mute camera' and screen-share buttons.

This is a useful option for when you want a guest to join a room and only publish audio, with no opportunity to share video.

 (2) (1) (1) (1).png>)

## Related

{% content-ref url="videodevice.md" %}
[videodevice.md](videodevice.md)
{% endcontent-ref %}

{% content-ref url="and-webcam.md" %}
[and-webcam.md](and-webcam.md)
{% endcontent-ref %}




---
description: Hides the ability for a guest to upload a file
---

# \&nofileshare

Sender-Side Option! ([`&push`](push.md),[`&room`](../general-settings/room.md))

## Aliases

* `&nodownloads`
* `&nofiles`

## Details

In some cases, the guest will have a button by default to upload files to the group room.

Using `&nofileshare`**,** the button needed to select and share a file will be hidden.

This may also prevent a guest from being able to download files that are shared with them.

.png>)

## Related

{% content-ref url="and-fileshare.md" %}
[and-fileshare.md](and-fileshare.md)
{% endcontent-ref %}




---
description: >-
  Disables IFrames from loading, such as remotely shared websites by another
  guest or director
---

# \&nowebsite

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&noiframes`
* `&noiframe`
* `&nif`

## Details

Disables IFRAMEs from loading, such as remotely shared websites by another guest or director.

## Related

{% content-ref url="and-website.md" %}
[and-website.md](and-website.md)
{% endcontent-ref %}




---
description: The order priority of a source video when added to the video mixer
---

# \&order

Sender-Side Option! ([`&push`](push.md), [`&room`](../general-settings/room.md))

## Options

Example: `&order=3`

| Value                    | Description                         |
| ------------------------ | ----------------------------------- |
| (positive integer value) | Higher order, drawn first on screen |

## Details

Videos in the auto-mixer are normally sorted by default by their connection ID, but assigning a mix-order value to a video will order it based on that mix value instead. If not set manually via the `&order` parameter, the mix order value will be zero.

The director can change this value dynamically for each guest; they can change the order of a guest via the `Mix Order` option in the director's room. If wanting to pre-assign the mix-order value though, the `&order` option can be useful, such as when wanting to ensure the main host of a stream is always first in the video mix layout.

The mixer order takes priority over [`&orderby`](../newly-added-parameters/and-orderby.md), but the mix order has no effect if using a custom layout, such as when using a custom [`&layout`](../advanced-settings/mixer-scene-parameters/and-layout.md) or via the mixer app.\
\
 (1) (3).png>)

If two videos have the same order value, the mixer will decide on its own which is drawn first of the two.

Order is Left to Right; Top to Bottom.

The mix order value for a guest/video source is synced with all other guests/scenes/viewers, so changing it will impact how others see the mix order as well.

## Related

{% content-ref url="../newly-added-parameters/and-orderby.md" %}
[and-orderby.md](../newly-added-parameters/and-orderby.md)
{% endcontent-ref %}




---
description: Enables pan/tilt/zoom control of the device, if compatible
---

# \&ptz

Sender-Side Option! ([`&push`](push.md))

## Details

Enables pan/tilt/zoom control of the device, if compatible.

This will trigger a new permission popup though.

Can be added to a guest's URL in a room. Then the director can manually change pan, tilt and zoom for the guest's camera.

Can also be added to a simple push link, then you can change pan, tilt and zoom in the video settings.\
\
.png>)




---
description: The stream ID that you are publishing with will be the defined value
---

# \&push

Sender-Side Option! ([`&room`](../general-settings/room.md))

## Aliases

* `&id`

## Options

Example: `&push=StreamID`

<table><thead><tr><th width="186">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>creates a randomly generated stream ID</td></tr><tr><td>(string)</td><td>1 to 49-characters long: aLphaNumEric-characters; case sensitive.</td></tr></tbody></table>

## Details

`&push` is the parameter that tells VDO.Ninja to be a publisher.

[https://vdo.ninja/?push=streamid](https://vdo.ninja/?push=streamid)\
[https://vdo.ninja/?view=streamid](https://vdo.ninja/?view=streamid)

If the parameter is not provided, a randomly generated stream ID will be used instead.\
[https://vdo.ninja/?push](https://vdo.ninja/?push)

This is a useful parameter if you wish to reuse an invite link or if you refresh the page often.\
The value needs to be 1 to 24-characters long: `aLphaNumEric-characters`; case sensitive.\
If left empty, the stream ID will default to a random one.

{% hint style="info" %}
If the stream ID is already in active use, an error will be shown and the stream will not publish.
{% endhint %}

If using a [`&room`](../general-settings/room.md) URL and not using [`&scene`](../advanced-settings/view-parameters/scene.md) or [`&solo`](../advanced-settings/mixer-scene-parameters/and-solo.md), VDO.Ninja will automatically generate a `&push` ID.

## Related

{% content-ref url="../advanced-settings/setup-parameters/and-permaid.md" %}
[and-permaid.md](../advanced-settings/setup-parameters/and-permaid.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/view-parameters/view.md" %}
[view.md](../advanced-settings/view-parameters/view.md)
{% endcontent-ref %}




---
description: Easter egg &notify sound
---

# \&r2d2

Sender-Side Option! ([`&push`](push.md))

## Details

Add this to a guest's/director's URL and you get R2-D2 audio alerts for raised-hands, chat messages.

Same as [`&notify`](and-notify.md). If there is no sound when a guest is joining or leaving the room, use `&notify&r2d2` to get a basic sound.

{% hint style="warning" %}
If you can't hear a sound, click any button in the room. Then the sounds will be activated.
{% endhint %}

## Related

{% content-ref url="and-notify.md" %}
[and-notify.md](and-notify.md)
{% endcontent-ref %}

{% content-ref url="and-hands.md" %}
[and-hands.md](and-hands.md)
{% endcontent-ref %}




---
description: Disables camera-sharing as an option
---

# \&screenshare

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&ss`

## Details

`&screenshare` will allow the guest to screen share by being directly asked to share a screen or window instead of being taken to the camera/screenshare selection screen.\
 (1) (1) (2) (1).png>)

Starting with [v19](../releases/v19/) of VDO.Ninja, there is also the [`&screenshare2`](../newly-added-parameters/and-screenshare2.md) option; a minor UI variant that requires an additional button press, but more clearly preps the guest to the fact they will be sharing their screen.

#### Using `&screenshare` with the [Electron Capture App](../steves-helper-apps/electron-capture.md)

When using the Electron Capture App you have to "Elevate Privileges" to be able to share a window or screen. You can enable Elevated Privileges for the Electron App via the command line with `--node true` or in the app by right-clicking and selecting "Elevate Privileges" from the context-menu.

One unique feature about the [Electron Capture App](../steves-helper-apps/electron-capture.md) is that it can auto-select a screen or window when screen-sharing with VDO.Ninja, without user-input.\
For example:\
`&screenshare=1` for the main display\
`&screenshare=2` for the second display\
`&screenshare=discord` for the Discord application\
`&screenshare=googlechrome` for the Chrome Browser

## Related

{% content-ref url="and-webcam.md" %}
[and-webcam.md](and-webcam.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-screenshare2.md" %}
[and-screenshare2.md](../newly-added-parameters/and-screenshare2.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/screen-share-parameters/and-smallshare.md" %}
[and-smallshare.md](../advanced-settings/screen-share-parameters/and-smallshare.md)
{% endcontent-ref %}

{% embed url="https://github.com/steveseguin/electroncapture" %}




---
description: Set a target FPS for your screenshare (secondary stream)
---

# \&screensharefps

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&ssfps`

## Options

Example: `&screensharefps=60`

| Value           | Description                        |
| --------------- | ---------------------------------- |
| (integer value) | will target this framerate. Eg: 60 |

## Details

Set a target FPS for your screen share.&#x20;

## Related

{% content-ref url="screenshareid.md" %}
[screenshareid.md](screenshareid.md)
{% endcontent-ref %}

{% content-ref url="screensharequality.md" %}
[screensharequality.md](screensharequality.md)
{% endcontent-ref %}




---
description: >-
  Pre-sets the screenshare stream id for a screen share if its a secondary
  stream
---

# \&screenshareid

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&ssid`

## Options

Example: `&screenshareid=SomeID`

<table><thead><tr><th width="180">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>If no value is passed, the system will automatically add the suffix of "_ss" to the existing stream ID that the user might be using.</td></tr><tr><td>(string)</td><td>Pre-sets the screenshare ID. Useful to automate or prepare stuff in advance.</td></tr></tbody></table>

## Details

When screen sharing as a guest in a group room, in `&sstype=2` screen sharing mode, the screen share will now create a second stream for the screen share, keeping your webcam also.

`&screenshareid` will preset the ID the screen share will have, making the stream ID for the screen share easier to predict and prep for.

Example (`&room=roomname&sstype=2&push=streamid&screenshareid`)\
 (1) (1).png>)

Without this, the screen share ID in `&sstype=2` mode is random, which is a decision made to increase security. This complication will be addressed in the future.

There is a toggle in the director's room which adds `&ssid` to the guest's invite link.\
 (2).png>)

{% hint style="info" %}
`&screenshareid` doesn't work with [`&screensharetype=3`](../newly-added-parameters/and-screensharetype.md). When using `&screensharetype=3` the screen share gets the appendix `:s` added to the stream ID of the guest. \
\
As of VDO.Ninja [v23](../releases/v23.md),`&screensharetype=3` is default, but you can revert back to `&screensharetype=2` or use the new `&screensharetype=3` method post-fix `:s` method of identify screen shares.
{% endhint %}

## Related

{% content-ref url="screenshare.md" %}
[screenshare.md](screenshare.md)
{% endcontent-ref %}

{% content-ref url="screensharefps.md" %}
[screensharefps.md](screensharefps.md)
{% endcontent-ref %}

{% content-ref url="screensharequality.md" %}
[screensharequality.md](screensharequality.md)
{% endcontent-ref %}




---
description: >-
  Disconnects communication with the handshake server as soon as possible and
  provides verbose feedback
---

# \&secure

General Option! ([`&push`](push.md), [`&room`](../general-settings/room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Details

The enhanced security parameter will auto-disconnect you from the handshake-server after the first peer connection is established (Publishers only are disconnected; not viewers). In effect, this makes it impossible for the server to request future handshakes from you, and hence no more future peer connections.

The feature also makes the connection activity verbose, letting you know when someone starts watching your stream and when that viewer disconnects.

The security mode also limits the max number of viewers to just one viewer, and if they do disconnect, they cannot reconnect. No one can actually; you will have to re-setup via a page refresh to let someone try connecting again.

This can help prevent someone from destroying a live stream due to accidentally screen sharing the stream ID to the public.

### Technical Benefits

* The handshake server has no way of talking to the publisher after the stream starts. Fully decentralized once initialized.
* The publisher cannot be spammed by "Watch Stream" requests if the invite link gets shared accidentally.
* The publisher can clearly see when someone has joined and when someone has disconnected.
* Increased security and privacy, with just some minor added inconveniences.

### Alternatives

* If you wish to host your own handshake server, there is one available that is adequate for private for personal use here: [https://github.com/steveseguin/websocket\_server/](https://github.com/steveseguin/websocket\_server/)
* If interesting in hiding your IP address from a remote guest, you can use `&privacy` instead, which will use a TURN server to connect with remote guests, acting as a middleman for the peer connection.
* While it should be tested, you can also perhaps try [`&icefilter=host`](../general-settings/and-icefilter.md) which will attempt to filter out connections with remote guests that are behind a firewall.  Feedback and test results welcomed.




---
description: Access device sensor data at given rate
---

# \&sensor

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&sensors`
* `&gyro`
* `&gyros`
* `&accelerometer`

## Options

Example: `&sensor=50`

| Value           | Description                                           |
| --------------- | ----------------------------------------------------- |
| (integer value) | Set polling rate to given value, in hz. Default 30hz. |

## Details

Gyroscopic, accelerometer, magnetometer data can be pushed out.

Enable with `&sensor=30` (30hz).\
Results show up in the remote stats log or the remote IFRAME API.

Useful for VR live streaming support, where you want to capture a smartphone's movement, as well as video.\
\
Support will vary from device to device; please report problems or reach out for requests.

#### Update 22/06/02

`&sensor` now also includes speed and altitude data.&#x20;

Added a demo/sample on how to overlay speed + acceleration on top of video playback (compatible with a mobile phone sender)

[https://vdo.ninja/examples/sensoroverlay?view=STREAMID](https://vdo.ninja/examples/sensoroverlay?view=STREAMID)

{% embed url="https://www.youtube.com/watch?v=SqbufszHKi4" %}

## Related

{% content-ref url="../advanced-settings/settings-parameters/and-sensorfilter.md" %}
[and-sensorfilter.md](../advanced-settings/settings-parameters/and-sensorfilter.md)
{% endcontent-ref %}




---
description: Shows list of hidden guests
---

# \&showlist

General Option! ([`&push`](push.md), [`&room`](../general-settings/room.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Options

Example: `&showlist=1`

| Value                   | Description                             |
| ----------------------- | --------------------------------------- |
| `0`                     | Force disable the list of hidden guests |
| `1` \| (no value given) | Force enable the list of hidden guests  |

## Details

Should list user's labels in a list, along with whether they are video-muted or not.&#x20;

Includes microphone mute states and voice activity meters in the list.

Is visible by default when using [`&broadcast`](../advanced-settings/view-parameters/broadcast.md) mode.

 (1) (2) (1).png>)




---
description: Enables transcription and closed captioning
---

# \&transcribe

Sender-Side Option! ([`&push`](push.md))

## Aliases

* `&trans`
* `&transcript`

## Options

Example: `&transcribe=de-DE`

| Value                     | Description                                                                                              |
| ------------------------- | -------------------------------------------------------------------------------------------------------- |
| `en-US`                   | American English                                                                                         |
| `de-DE`                   | German                                                                                                   |
| `pt-PT`                   | Portuguese                                                                                               |
| (any xx-XX language code) | You can check for additional language codes [here](https://www.science.co.il/language/Locale-codes.php). |

## Details

The transcription service uses default browser/system mic as a source and cannot be muted.

Generally needs to be used in conjunction with [`&closedcaptions`](../advanced-settings/settings-parameters/and-closedcaptions.md).

{% hint style="warning" %}
* The transcription audio source will be the default microphone of the browser, which often is the same as the system's default input source.
* It is not necessary the microphone that has been selected in VDO.Ninja. Please double check this if the transcription isn't working.
* The mute button of VDO.Ninja will not work with this feature; at the moment anyways.
* Only one transcription service can run at a time.
* Chrome or other browsers will prevent the user from running multiple transcription services at a time. Since the transcription services of most browsers requires the Internet.
{% endhint %}

You will normally need Internet access for this to work and be willing to tolerate the occasional hiccup that the browser's transcription service may cause. Service may stop for seconds at a time as a result.

Certain Android devices may not require internet for the transcription to work.

{% embed url="https://www.youtube.com/embed/3eo85WAXeuk" %}

{% hint style="danger" %}
Does not work in Safari!
{% endhint %}

## Related

{% content-ref url="../advanced-settings/settings-parameters/and-closedcaptions.md" %}
[and-closedcaptions.md](../advanced-settings/settings-parameters/and-closedcaptions.md)
{% endcontent-ref %}

{% content-ref url="../steves-helper-apps/caption.ninja.md" %}
[caption.ninja.md](../steves-helper-apps/caption.ninja.md)
{% endcontent-ref %}




---
description: >-
  Allows assistant directors to have access to the director's room, with a
  subset of control
---

# \&codirector

Director Option! ([`&director`](../viewers-settings/director.md))

## Aliases

* `&directorpassword`
* `&dirpass`
* `&dp`

## Options

Example: `&codirector=DirectorPassword`

<table><thead><tr><th width="211">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>the site will prompt you for a password on load</td></tr><tr><td>(alpha numeric value)</td><td>password for the directors</td></tr></tbody></table>

## Details

The basic idea is there is a URL parameter called `&codirector` that you need to add to all the director links used.

For example, `https://vdo.ninja/?director=MYROOMNAME&codirector=DirectorPWD123`

So long as all the directors have `&codirector=DirectorPWD123` added to their URLs, they all share a common director's password, and so they all treat each other as valid directors.

If the passwords don't match, the first director into the room will be the real director, and the others will be rejected.

If you don't enter a password via the URL, the site will prompt you for a password on load.

### Description

Using this flag, the director can set a director's password (or prompt the user for one). Any other director that joins the room, who also has a matching director's password set, will be granted co-director controls.

A co-director has nearly all the same controls and powers as the main director, except they cannot control the main director, nor kick them out of the room. They also have a few features unavailable to them at present, such as solo-talk, as those currently would conflict with the main director's ability to use those features.

The first director to join the room is the main director, and so their password is the 'correct' password.

A co-director cannot force-disconnect the main director.

If the main director does not have `&codirector={somepassword}` in their URL, nor enabled co-director mode via the room-settings menu, then remote co-directors will not be able to join.

{% hint style="info" %}
The co-director mode is still evolving, and certain things like shared-state between all the directors may still be missing.

Starting with [v20](../releases/v20.md) of VDO.Ninja, a co-director invite link will be available via the room settings button, along with the option to customize permissions.
{% endhint %}

<div align="left"></div>

### Optional - Enable via Room Settings

You can also enable the co-director mode by checking the "Add co-directors .." option in the room settings menu. This will provide you a link with the `&codirector` invite link already generated.

This will only work while the check-box is selected, so be sure to re-enable it if reloading the page without `&codirector` added to your own link.

###  (3).png>)

### Warnings

Do not confuse the room password with the director's password; if they are the same, you potentially allow a mischievous guest to have access that they should not have.

Co-directors will not be able to join as co-directors unless the main director has enabled the co-director option via the room setting's checkbox or by having a matching `&codirector=xxx` parameter in their own link.

If the main director leaves and re-joins, or a new director joins, all the co-directors will need to be re-checked. It's possible that a network outage could have a co-director and the main director to switch roles, depending on who re-connected.

If you copy and paste the main director's URL to a new browser/tab, be sure to remove the [`&push=STREAMID`](../source-settings/push.md) portion of the URL. If you do not, you will get an error about the stream ID being already in use. Each co-director and guest needs their own unique stream ID.

If using the [`&queue`](../general-settings/queue.md) parameter with co-directors, you may need to use [`&view=STREAMID`](../advanced-settings/view-parameters/view.md) to allow the co-director to bypass the queue, else they won't be able to be validated since they will be stuck in the queue. There is more info about this in the [queue's documentation](../general-settings/queue.md).

## Related

{% content-ref url="../viewers-settings/director.md" %}
[director.md](../viewers-settings/director.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/director-parameters/and-hidecodirectors.md" %}
[and-hidecodirectors.md](../advanced-settings/director-parameters/and-hidecodirectors.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/director-parameters/and-maindirectorpassword.md" %}
[and-maindirectorpassword.md](../advanced-settings/director-parameters/and-maindirectorpassword.md)
{% endcontent-ref %}




---
description: Remote MIDI control
---

# \&midiremote

General Option! ([`&push`](../source-settings/push.md), [`&room`](../general-settings/room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&remotemidi`

## Options

Example: `&midiremote=4`

<table><thead><tr><th width="275">Value</th><th>Description</th></tr></thead><tbody><tr><td>(<code>1</code> to <code>4</code>)</td><td>reference <a href="../midi-settings/midi.md"><code>&#x26;midi</code></a>'s values</td></tr></tbody></table>

## Details

This lets you route all MIDI messages from one computer to another computer, with the purpose of remote triggering the VDO.Ninja hotkeys.

```
https://vdo.ninja/beta/?midiremote=4&director=ROOMNAMEHERE
https://vdo.ninja/beta/?room=ROOMNAMEHERE&midiout=1&vd=0&ad=0&push&autostart&label=MIDI_CONTROLLER
```

* `&midiremote={reference &midi's values; 1 to 4}`

See [`&midi`](../midi-settings/midi.md) for a link to the page with more information on available hotkeys.

{% embed url="https://www.youtube.com/watch?v=rnZ8HM9FL4I" %}
How to remote control with MIDI
{% endembed %}

## Related

{% content-ref url="../midi-settings/midi.md" %}
[midi.md](../midi-settings/midi.md)
{% endcontent-ref %}




---
description: '"The stream ID you are publishing to is already in use" and other such errors'
---

# Already in use or claimed errors

### "The stream ID you are publishing to is already in use"

Understanding[ stream IDs](../getting-started/stream-ids.md) will help potentially avoid these errors in the future, but the basic notion is any media stream being published over VDO.Ninja needs to register itself with a stream ID. This is specified by using the [`&push`](../source-settings/push.md) URL parameter, such as `&push=STREAMID`.

The moment you connect to the system or start streaming, your stream ID gets registered to your connection, and so as long as you remain connected and online, you keep that stream ID. If you close the browser, hang up, or lose your Internet connection, then your stream ID unregisters automatically as well.

If a stream ID you are trying to claim is already in use by another stream, and that other connection is still actively online, then you'll get an error about it being already in use. In this case, you will need to wait for that other user to hang up or disconnect before you can attempt to register the stream ID yourself.

There are some subtleties to the above, such as if using passwords or self-hosted instances of VDO.Ninja, then stream IDs are isolated to their own unique realm, allowing you to use the same stream ID as someone else from a different realm. So if a stream ID is already in use, you can just change or add a password, and that will resolve the issue.

Of course, when you want to invite several people to a group room, you can't have different passwords, so you will want each guest to have their own unique stream ID still. By default with VDO.Ninja, if you do not use `&push` in the URL to specify a stream ID, then VDO.Ninja will auto generate a random stream ID for the guest. The system will also auto add the `&push=STREAMID` parameter to the guest's URL, so if the guest refreshes their page, they will keep the same stream ID.

The above is where there are sometimes issues, as if you join a room without a `&push` value specified, and then after connecting connecting you copy/share your URL with someone else, your URL might now contain your stream ID. When you then share it with someone else, they won't be able to connect as you are already using the stream ID that is specified.

In the above case, when distributing invite URLs to guests, either ensure each guest has a unique stream ID assigned to them, or ensure that there is no `&push` parameter added to the URL, allowing the system to generate a random stream ID for each guest.\
\
Manually creating a stream ID for each guest is recommended if you want each guest to appear in the same solo-view-link every time they re-join, as otherwise they may have a random new stream ID everytime they join. Many show producers will use a spreadsheet to keep track of who has what stream ID, their settings, and the corresponding invite link. Some of these spreadsheets are pretty sophisticated, with the ability to generate obfuscated invite links based on a few parameters.

If manually creating stream IDs, please just note that they need to be alphanumeric, with no special characters, are should be ideally less than roughly 30-characters long. If using a password, the uniqueness of the stream ID doesn't matter so much, but if not using a password, please ensure you create unique values that can't be easily guessed or accidentally duplicated by someone else.

Additional tools and options are available to create and assign stream IDs, such as [`&permaid`](../advanced-settings/setup-parameters/and-permaid.md), and other methods to store stream IDs via local user storage, but those options are out of the scope of this article.

### "The room is already claimed by someone"

This error indicates that there is already someone in a group room that has joined the room in the role of a director. The first director to join a room claims the room as theirs, and it remains theirs until they go offline or close their browser, as the room is assigned to their active connection. Another director will then be able to claim the room then, once the main director disconnects.

Claiming a room doesn't inherently mean much, other than anyone who joins the room will only acknowledge them as the main director. Acknowledging someone as a director will simply mean that director has certain privileges when requesting actions of a guest or scene. A validated director can ask a guest to hang up, for example, while otherwise such a request will be rejected.

Since VDO.Ninja is built on the concept of peer to peer connections, claiming a room is the same concept as claiming a stream ID, and those claims are tied to your active connections. Everything beyond that is really a matter of peers agreeing to a certain set of rules amongst themselves. If someone does claim a room and forgets to close their browser, you'll need to close that browser, change rooms, or change room passwords if you wish to have someone else become the main director.




# Appearing then disappearing guest

In this case, it sounds like the remote guest is failing to create a WebRTC peer connection with the director.

The handshake works, so each other knows someone is trying to join, but they are unable to find themselves.  The system will time out and try again, when this occurs, causing the guest's box to continually partially appear, and then go away again.

This is sometimes caused by blocked UDP traffic, where the TURN relay servers are unable to help for some reason.  Security software, privacy-focused VPNs, corporate firewalls, and certain browser extensions are common causes.

Sometimes other guests in the room will see the problematic guest, and in this case, there could just be a network routing issue.  Peer to peer connections across the Internet are not common, with most clients these days talking to servers instead, so residential to residential connections may occasionally fail due to bad Internet routes or caches.

Things that often work:

* Switch browsers, with Firefox being a common winner when Chrome fails. Perhaps also try Edge or even the [Electron Capture app](../steves-helper-apps/electron-capture.md).
* Use a VPN designed for streaming, such as [speedify.com](https://speedify.com/). Free VPNs exist as Chrome extensions, if you need something quick.
* Switch networks; if using WiFi, switch to Cellular, and vice-versa.
* If behind a corporate firewall, have the IT administrators allow WebRTC traffic, or use a different.
* [Meshcast.io](../steves-helper-apps/meshcast.io.md) is a server-based WebRTC system, and it may work in place of VDO.Ninja for simple needs.
* If nothing above works, join the Discord support community for personalized help at [discord.vdo.ninja](https://discord.vdo.ninja).




---
description: When data is lost or delayed during transfer between peers
---

# Packet Loss

Packet loss can cause low quality video, audio distortion, clicking, and is the cause for numerous other video problems.

WiFi is often the main contributor to packet loss, but it's not the only cause. Still, eliminate WiFi as a possible culprit by removing it from your setup and from the guest's setup.

An Ethernet connection is highly recommended over WiFi.

#### That said, there are things to try still if WiFi is needed:

* Make sure the guest is plugged in and powered; battery mode with some laptops can cause issues.
* Try to sit closer to the WiFi router and try to limit the traffic on the network; the more that's going through the air, the more packet loss.
* If the guest can use the 4G LTE instead of WiFi (tethered via USB), that will often be much better than WiFi.
* The guest can also Tether their 4G LTE /w their WiFi using bonding apps like Speedify or with hardware from Peplink; these services can give you more control over network settings.
* If using a smartphone, consider using a USB to Ethernet adapter instead. I have a video demonstrating how to do this here: [https://www.youtube.com/watch?v=abCuANblE5w](https://www.youtube.com/watch?v=abCuANblE5w)
* Some users have mentioned that reducing their network's MTU size, or the size of their packets, has helped reduce packet loss over bad WiFi. You'll need to experiment with this, but 800 to 1000 might be in the range you can try in this case.
* Improving the Wi-Fi network, such as switching network bands (5hz / 2.4ghz), buying a mesh-based multi-node access point setup for larger homes, changing network channels to account for frequency interference, updating to Wifi-6 or newer technologies, and moving the closer to the access point.

### If the issue isn't WiFi related

* Try to have the guest use a different browser. For example, if using Firefox, use Chrome, and vice versa. Some browsers are optimized for privacy over performance, and that may hinder video quality, and even Chrome can sometime be configured in a way that hinders VDO.Ninja from working well.
* Disable any Anti-virus software or any security software that may disable WebRTC IP leaking.
* Advanced network firewalls, like _pfsense_, may block UDP packets or force traffic through a TURN relay server. VDO.Ninja uses mainly UDP packets in the high port range.
* If your connection with a guest is going thru a TURN relay server, such as perhaps due to a security or privacy setting, resolving that may fix issues. VDO.Ninja offers publicly accessible and free TURN servers as part of its service, but these may introduce packet loss. You can always host your own TURN servers instead, but avoiding them if not needed is usually the best option.
* Restart your Internet router; sometimes a router or network equipment just needs a good reset or update.
* If your router is double-natted, such as if you have a router plugged into another router at home, it can cause VDO.Ninja to send video via relay servers instead of the preferred direct peer to peer. Commonly, to address this, either set the second router as an AP access point instead, or configure the first router to be in bridge mode.

#### Routing issues

Sometimes two peers just can't get a good connection, while with other peers they can. This is often largely dependent on your ISPs, and it can be challenging to fix.

* Host your OBS Studio on a premium cloud server, like Amazon AWS Workspaces or Google GCP. These providers have good networks optimized for most users to access, and hosting a VPN, TURN server, or the entire OBS Studio can help you control for network routing issues.
* Forcing the TURN relay servers into use may help at times; adding [`&relay`](../general-settings/and-relay.md) to the links can enable this mode. It may add some latency though, as the video traffic will take a longer, but different, network routing path that may be more reliable. Hosting your own TURN server on a local premium server, and specifying VDO.Ninja to use it, has been a good solution for some.
* As mentioned above, you can also use a VPN, perhaps one with the server is hosted on a local Google Cloud server or perhaps use a VPN service that offers local edge network access onto a premium network. If all guests connect via the VPN, you'll have more control over the routing quality.
* Change your ISP (Internet provider) to another provider; this maybe needed on either your end or the remote guest's end. Some network providers, especially consumer-grade residential providers, can have really bad packet loss issues, especially during the evening hours.
* Use cellular connections instead, especially if the issue is intermittent and perhaps only during peak Internet usage hours. Cellular connections are optimized for audio and live streaming, and so while they may have limited bandwidth or be expensive, they can also be the last refuge of hope sometimes. This is especially true of 5G connections.
* If your router or connection supports IPv6, but you don't have it enabled, try enabling it. Sometimes if limiting yourself to IPv4 or IPv6, your ISP may send your traffic through an IPv4<>IPv6 translation server, which could introduce delays, throttling, and packet loss.
* Some cellular providers limit and throttle UDP packets, which are used by VDO.Ninja. Using a service such as Speedify, in TCP-mode, can bypass this limitation by wrapping the UDP packets as TCP and relaying them thru servers. Check with the cellular provider before purchasing a SIM card to ensure they do not throttle UDP packets as well, if intending to travel.
* As mentioned before, sometimes the TURN relay severs get used, and this might be the case with cellular connections or corporate firewalls; hosting your own TURN server or finding a way to bypass them can sometimes help improve the quality of connections.

#### More generic options to try

* Using [`&chunked`](../newly-added-parameters/and-chunked.md) mode on the sender's side can enable an alternative way of sending video data, but this option is only supported by Chrome and other Chromium-based browsers. It also is fairly CPU intensive and may require some tweaking of bitrates and buffers to have it work well for you situation
* Try using [`&codec=av1`](../advanced-settings/view-parameters/codec.md#av1) on the viewer side; this won't solve packet loss issues, but the AV1 codec is more efficient than the default codecs, and so it may offer better video quality despite the packet loss.
* Try adding [`&buffer=500`](../advanced-settings/view-parameters/buffer.md) to the viewer link, as this might allow for more time for lost packets to arrive.
* Reduce the bitrate of your video streams. If your connection can only handle 30-mbps in and 10-mbps out, trying to push it to do more will cause network thrashing and packet loss. In this case, try to ensure that your connection's up and download links are not saturated by more than 80% of their tested max capacity. Leaving some headroom will reduce latency and packet loss, ultimately leading to better quality.
* Consider using Meshcast or a WHIP/WHEP server-based SFU provider, and use that with VDO.Ninja instead of a direct peer-to-peer connection. I have a [guide for setting up Cloudflare ](https://cloudflare.vdo.ninja/)to be used in this regard, but any WHIP+WHEP SFU can work. This can provide more advanced buffering and SVC options not available with direct browser to browser options.
* Use [Raspberry.Ninja](../steves-helper-apps/raspberry.ninja/) or OBS Studio's WHIP output as a video source, instead of the browser. Raspberry.Ninja in particular supports double redundant video streams for added error correction, and while it uses more bandwidth, it can tolerate heavy packet loss and force a specified video quality. While packet loss will still exist, you might find the outcome is more to your liking.
* If screen sharing, you can use [`&contenthint=detail`](../advanced-settings/video-parameters/and-contenthint.md), which can tell the system to prioritize frame resolution, than frame rate. While this isn't suitable for gaming, it might be a good option for screen shares, where packet loss might otherwise might text unreadable.

### Audio issues due to packet loss

* Turning down the audio bitrate ([`&audiobitrate=128`](../advanced-settings/view-parameters/audiobitrate.md)) will be less prone to clicking issues vs something high, like 256-kbps. The default is 32-kbps.
* You can add [`&enhance`](../advanced-settings/view-parameters/enhance.md) on the viewer side to try to prioritize the audio over the video. This might help with audio clicking issues.
* Using [`&audiocodec=red`](../advanced-settings/audio-parameters/minptime-1.md#red) on the viewer side can increase the amount of error correction data being sent, reducing packet loss. This will double the audio bandwidth, but that shouldn't be an issue for most modern connections.

### YouTube Video guide on packet loss + VDO.Ninja

I have a video talking about packet loss, with details on how to setup Speedify as well: [https://www.youtube.com/watch?v=je2ljlvLzlYAnd](https://www.youtube.com/watch?v=je2ljlvLzlYAnd)

## Connection testing tools and statistics

There is a speedtest that the local user can try out to give them feedback on their packet loss. This is a special speedtest, different than normal tests, as it does not test for available bandwidth, but network quality and packet loss: [https://vdo.ninja/speedtest](https://vdo.ninja/speedtest)

If you'd like to remotely test a guest's connection, you can also have them perform the VDO.Ninja pre-check test. This is a comprehensive system and network test, which allows you to review the results of the guest remotely: [https://vdo.ninja/check](https://vdo.ninja/check)

You can also do a peer-to-peer test by just making a VDO.Ninja connection with the guest. If you hold down CTRL (cmd) and click on their video, you'll see the stats. Packet loss is a listed stat, as well as the candidate type. If a guest is connecting to you via RELAY candidate type, that implies there is a firewall or security setting blocking a direct peer to peer connection. Addressing this will likely resolve your issues.

When doing a pre-check or speed test, make sure to test during the hours of the day you intend to go live. Mornings will often have less packet loss than evenings, with around 7pm to 10pm being especially bad.

### Asking ChatGPT about it..

_So I asked ChatGPT about improving the network quality between two peers, and its response is below._&#x20;

Understanding the root causes of UDP packet loss across different network paths can be quite complex, particularly because the internet is a mesh of countless routes, and performance can be affected by a multitude of factors that are often beyond the control of end users. Here are some points to consider when trying to diagnose these issues:

1. **Path Specifics**: Even if all users have good connections to a common server like Google's, the path packets take to reach your specific service might be vastly different. This can be due to the routing policies of ISPs, peering agreements, or simply the geographic distance the packets need to travel.
2. **Network Congestion**: One of the most common causes of packet loss and latency is network congestion. This can occur at any point along the path and can be temporary (like peak usage times) or could indicate a more chronic issue with a particular segment of the network.
3. **Quality of Service (QoS)**: ISPs may implement QoS policies that prioritize certain types of traffic over others. For instance, UDP traffic may be deprioritized in favor of TCP traffic, which could negatively impact applications that rely on UDP.
4. **NAT and Firewall Configuration**: Users behind strict NATs or firewalls might experience connection issues if certain ports are blocked or if the NAT type is restrictive (Symmetric NAT), which can cause problems for UDP traffic in particular.
5. **Hardware Issues**: Problems with user hardware (like routers or modems) or even the quality of the local network (like Wi-Fi interference) can cause increased packet loss.
6. **ISP Issues**: Issues within an ISP's network, such as faulty routing, misconfigured equipment, or even under-provisioned transit links, can lead to increased latency and packet loss.
7. **Server Performance**: On your end, the server's performance and its connection to the internet could also affect the user experience. Overloaded servers or servers with a poor connection to the backbone can be a bottleneck.
8. **Packet Inspection**: Some ISPs may perform deep packet inspection which can introduce latency and potentially drop packets if they are deemed to be non-essential or if they match certain patterns.
9. **Transit Providers**: Different users may have different transit providers between them and your server, which can result in different latency and packet loss characteristics.

To diagnose these issues, you could:

* Implement more detailed logging and monitoring on your server to see if there are patterns in the connectivity issues.
* Ask users to run traceroutes and path analysis tools from their location to your server and back to determine where delays or losses are occurring.
* Use network diagnostic tools that can simulate UDP traffic and measure performance across different network paths.
* If feasible, provide alternative connection points or relay servers in different geographical locations to see if routing through these points improves performance.

Ultimately, diagnosing network performance issues often requires cooperation from ISPs and a deep dive into network performance metrics. Tools like MTR (My Traceroute) can be more informative than a simple traceroute as they provide information on packet loss at each hop and over time, which can help in pinpointing where issues are occurring.

#### 👍🍀




---
description: Some causes and solutions for robotic audio issues
---

# Robotic Audio Distortion

## Troubleshooting Robotic Audio Distortion in VDO.Ninja

### Overview

When experiencing robotic audio distortion in VDO.Ninja, the issue could stem from several sources - your system settings, OBS Studio, or even your browser. Below, we'll explore the various causes and their solutions.

### System Configuration Issues

One of the most common sources of audio distortion relates to your system's audio settings. Users with high sample rates (such as 384-khz) on their microphone or default system device often encounter problems. Similarly, 32-bit audio sampling can create issues. VDO.Ninja performs best with 48-khz sampling rate and either 16- or 24-bit depth. This is particularly relevant for users with FiiO audio DACs.

Some users have found that certain software features can interfere with audio quality. For instance, the _MyAsus_ software's AI Noise-Cancelling Speaker feature, when enabled for the default audio output device, has been known to cause distortion. Simply switching this setting to OFF has resolved the issue for many users.

Gaming peripherals can also be a source of trouble. Users with surround sound headphones, particularly 5.1/7.1 Logitech or Corsair gaming headsets, may experience distorted audio. To resolve this, try setting your headphones and speakers to 2.0 stereo audio and disable any surround sound / DTX effects.

If problems persis&#x74;**,&#x20;**<mark style="background-color:yellow;">**consider switching to a different non-gaming headset.**</mark>

### OBS Studio-Related Problems

When using OBS Studio, you might notice the issue becomes more pronounced when the browser source is minimized or running in the background. Some users have found success by simply <mark style="background-color:yellow;">**running OBS in Administrator mode**</mark>, suggesting the problem may be related to system priority settings.

If you see "Max audio buffering reached!" in your OBS log files, your computer might be struggling with CPU load. You have several options: reduce the demands on your CPU, upgrade your hardware, or try using the [Electron Capture app ](../steves-helper-apps/electron-capture.md)instead of the OBS Browser source for audio and video capture.\
\
DO NOT use OBS's CPU monitor to judge CPU usage — it's deceptive and never close to accurate. Instead, use the Windows Task Manager, or whatever system resource manager there is. It will offer a more accurate total system CPU usage value, and if its near or at 100%, then that can cause OBS to have delayed or robotic audio.\
\
Try not monitoring the audio of sources in OBS, especially browser sources; for some users, this has fixed the issue. You can monitor the audio of guests via VDO.Ninja instead directly, or by using the Electron Capture app instead.

### Audio Routing and Echo Issues

If you're using virtual audio cables or a professional audio mixer, audio buffer issues might manifest as clicking sounds or distortion. Increasing the audio buffer size in your virtual audio cable settings often resolves these problems.

Echo cancellation can create unexpected robotic effects, particularly in specific scenarios. Having multiple VDO.Ninja tabs open on the same computer can create feedback loops that trigger echo cancellation. Similarly, if you have a mobile phone or second computer nearby that's streaming into the same VDO.Ninja group, you might experience feedback loops resulting in echo cancellation issues.

Do not test audio with two devices side by side, or even in the room next door. Smartphones have sensitive microphones and echo-cancellation can cause issues even if the test device is somewhere else in the house.

### Network and Connection Problems

High packet loss can significantly impact audio quality. While adding `&enhance&red` to your view/scene link might help, addressing the underlying packet loss is usually more effective. If you're using a VPN or operating behind a strict firewall that forces the use of relay servers, try to resolve these network constraints first.

Avoid WiFi and bad network connections.\
\
Ensure that OBS is allowed through your system's firewall; sometimes a user might block OBS from accessing the Internet in full, and that can cause network issues.\
\
OBS also has an issue where it hides local IP addresses when making peer connections; this can in some cases force connections that should stay on a local network to be forced over the Internet. This can add network instability and packet loss, which at times may cause bad audio. If you're comfortable lowering the web security of your browser engine within OBS, you can do this by starting OBS with the following command line parameters:\
\
`obs64.exe --disable-web-security --allow-running-insecure-content --ignore-certificate-errors --use-fake-ui-for-media-stream`

### Version-Specific Considerations

Different versions of VDO.Ninja may handle audio processing differently. If you're experiencing persistent issues, you might want to try an older version, such as https://vdo.ninja/v23/. For systems under heavy load, adding `&noap` to your VDO.Ninja URL will disable web-audio processing, which can help with robotic audio effects caused by audio buffer underruns.

If you notice that the audio issues are specific to certain versions, please report them through the Discord community (https://discord.vdo.ninja). Your feedback helps improve the platform for everyone.\
\
Different versions of OBS Studio also can cause issues.  Try different versions of OBS if facing issues, especially new issues, and consider not using new versions of OBS for production purposes until doing tests. I like to skip versions if the current version is working well, only upgrading when needed.

### Electron Capture app

If Chrome or OBS is having an issue with audio, consider using the [Electron Capture app](../steves-helper-apps/electron-capture.md) instead. It's optimized for good performance and avoids browser extensions from interfering with VDO.Ninja.

### More resources and support

While you can drop by Discord (https://discord.vdo.ninja) for support, check out this related guide that has common issues for [audio clicking and audio distortion](audio-clicking-popping-distortion.md). It offers quite a few other possible causes of audio issues.

{% content-ref url="audio-clicking-popping-distortion.md" %}
[audio-clicking-popping-distortion.md](audio-clicking-popping-distortion.md)
{% endcontent-ref %}




---
description: Audio Troubleshooting Guide for VDO.Ninja
---

# Audio Clicking / Popping / Distortion

## Common Issues and Solutions

### OBS Studio related audio issues

There are numerous known causes of audio drop out or audio distortion in OBS. Often it's caused by OBS Studio being throttled by the system, or perhaps a firewall setting is causing network issues. So try the following first, if the issue is OBS specific:

* <mark style="background-color:yellow;">👉 Consider running OBS Studio in</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">**Administrator mode,**</mark> <mark style="background-color:yellow;"></mark><mark style="background-color:yellow;">if on Windows  👈</mark>
* Restarting OBS or addressing heavy CPU load may also help prevent buffer underruns, which sometimes appear in the OBS logs as a max buffer reached error.
* Make sure the computer isn't running near 100% load to ensure it's not just overloaded.
  * Do not rely on the OBS CPU usage value, but instead use Windows Task Manager to judge CPU usage
* Try a different version of OBS Studio.
* Perhaps add OBS Studio to the allowed Firewall apps list

<figure><figcaption><p>Try adding OBS or your Browser to the Firewall allow list</p></figcaption></figure>

### Bluetooth Microphone Clicking/Popping

Bluetooth microphones can cause clicking or popping sounds. Consider using a wired microphone for better reliability.

### Sample Rate Mismatch

VDO.Ninja uses 48kHz audio (48000hz). To ensure maximum compatibility:

* If different sample rates are used, conversion may cause issues in rare situations.

#### High Sample Rate Devices

Devices like FiiO DAC can sometimes have very high audio sample rates, potentially causing buffer underruns and clicking problems.

**Recommended Audio Settings:**

* Set playback audio device and microphone capture device to 48000hz.
* Use no more than 24-bit audio depth.
* Disable any Audio Enhancements in your audio drivers
* Ensure to only use mono or stereo audio with your devices; surround can cause issues.
* Adjust these settings in Windows audio settings.

.png>)

### Disable surround sound or DTX audio

* You might think you disabled the surround sound on your headphones, but you might only think you did
* Try with a different pair of headphones; something less fancy, if you are using a Bluetooth or Surround sound gaming headset.

### Buffer Size Issues

* Increase audio buffer packet sizes for any  virtual audio cables or pro audio gear.
* Small audio buffers on mic preamps or virtual audio cables can lead to clicking or distortion.

### System Overload

* Restart OBS or address heavy CPU load to prevent buffer underruns.
* Ensure the computer isn't running near 100% load.
* Consider running OBS Studio in admin mode.
* Consider reducing video resolution and bitrate to free up CPU resources for audio processing.

### Surround Sound Headphones

Some surround sound headphones (e.g., Logitech, Corsair) can cause audio problems:

* Symptoms: robotic noises, distortion
* Solutions:
  * Disable surround sound / DTX mode
  * Disable Enhanced Audio settings in your Windows audio driver&#x20;

### MacOS-Specific Issues

Ensure your Mac is plugged into a power outlet, not running on battery power.

* If an older Macbook, 2016-era for example, overheating is very likely.
* Consider having the guest join with `&meshcast&q=2`, to reduce CPU load,&#x20;

### Network-Related Issues

#### Wi-Fi vs. Ethernet

* Avoid using Wi-Fi for streaming high-quality music.
* Use wired Ethernet connections on both ends to prevent packet loss and clipping.
  * Sometimes changing Ethernet cables can help, or actually even switching to WiFi oddly
* Using cellular (tethered / hotspot), might validate if a network issue

#### Bandwidth Usage

* Keep bandwidth usage below 80% of total upload capacity.
* Using 100% of bandwidth can cause packet stalling and audio clicking.
* https://vdo.ninja/speedtest can help you judge your max bandwidth

#### Packet Loss Solutions

1. Enable TCP transfer:
   * For WHIP/WHEP services, configure to use TCP instead of UDP.
   * Use a VPN service like Speedify.com with TCP transfer mode.
   * For VDO.Ninja, add `&relay&tcp` to the publishing link.
2. Use a TURN relay server in TCP mode:
   * Add `&relay&tcp` to the VDO.Ninja publishing link. Example: `https://vdo.ninja/?webcam&relay&tcp`
3. Enable RED audio mode:
   * Add to `&audiocodec=red` the viewer-side links
   * This will switch from OPUS Forward Error Correcting to OPUS Redundancy mode

### Meshcast /WHIP / WHEP / Servers

Audio packet loss may occur if broadcasting WebRTC media via an SFU server, where the viewer isn't able to receive the transmitted stream without error or hiccup.\
\
Adding `&buffer=2000` to the viewer's URL might help, trying a different server or lowering the audio/video bitrate could be another option.\
\
OPUS with FEC (error control) common avoid these issues, but if FEC isn't on, or if PCM is used, then then clicking may be a bit expected.

### Additional Troubleshooting Steps

#### Audio Processing tweaks

Try adding these URL parameters to viewer and sender links:

* `&noaudioprocessing`
  * This disables web-audio nodes, which disabling will break some functionality of VDO.Ninja
* `&samplerate=48000`
* `&micsamplerate=48000`

### Disable Hardware Acceleration

While it's an odd ball option, sometimes disabling Hardware Acceleration in OBS or Chrome can fix strange driver or hardware issues.

### Browser / System performance throttling

Rarely, but sometimes audio may glitch of the browser itself is throttling performance. While using the [Electron Capture app](../steves-helper-apps/electron-capture.md) instead of Chrome can minimize the odds of this happening, below are steps that might also help:

* Browser may pause non-visible windows, so you may need to disable this behaviour in your browser.&#x20;
  * To do so, "Disable" the option located at `chrome://flags/#enable-throttle-display-none-and-visibility-hidden-cross-origin-iframes`.&#x20;
  * Also "Disable" the flag `chrome://flags/#calculate-native-win-occlusion`.&#x20;
  * Restart the browser after saving the changes.
* Plug the computer into a power-outlet if using a laptop.
  * Laptops when running on battery power may throttle performance aggressively, so keep your device plugged in.
  * Avoiding being in a low-battery  or power-saving state
* Avoid minimizing any windows.&#x20;
  * Things work best if windows are kept visible and open, but if you need to put them in the background, don't minimize them at least.
  * This isn't normally an issue, but it might be if using digital effects, like a digital zoom or the whiteboard feature
* Browsers may also sometimes stop tabs/windows after an hour of inactivity.&#x20;
  * Disable any option in your browser under `chrome://settings/performance` related to performance throttling or background tabs, such as "Throttle Javascript timers in background".
* You can go to `chrome://discards/` and toggle off "Auto Discardable" on the VDO.NInja or other windows of interest.

* Try to keep the VDO.Ninja pages active and if possible, even partially visible on screen.&#x20;
  * If the windows are hidden or minimized, they may stop working if the system is designed to optimize.
* Another option to avoid throttling, if using Windows, is to do Win + Tab, and have two virtual Desktops on your PC.&#x20;
  * Put the chat windows into one virtual desktop, and use OBS in the other.&#x20;
  * Win+Tab can let you switch between desktops/windows.
* You can also try the Electron Capture desktop app, as that has more controls and will avoid common throttling / visibility issues found while using Chrome.

#### Further Resources

For issues with audio distortion or robotic voices, [you can see this article.](robotic-audio-distortion.md)

{% content-ref url="robotic-audio-distortion.md" %}
[robotic-audio-distortion.md](robotic-audio-distortion.md)
{% endcontent-ref %}




---
description: >-
  OBS Studio is just black in the browser source; potentially you hear audio,
  but nothing else.
---

# Nothing shows up in OBS

### Common causes for no video showing up in OBS are the following:

* Check OBS hardware acceleration settings
  * Enable or disable "Browser Source Hardware Acceleration" in OBS advanced settings
* Run OBS as Administrator (for Windows users)
  * This can resolve permission-related issues affecting video capture
* Try a different network connection
  * Switch between WiFi and cellular, or use a VPN to bypass potential network restrictions, or disable any VPN in use
* Your stream ID changed, entered incorrectly, or other setting / parameter is incorrect
* Try using a different browser to publish with; try Firefox, Edge, Chrome, or even the [native app](../steves-helper-apps/native-mobile-app-versions.md).

### If suffering from choppy video,

* Switch to Ethernet or try to [improve your WiFI ](packet-loss.md)/ Internet connection
* Increase the [video bitrate](../advanced-settings/video-bitrate-parameters/bitrate.md), especially if[ streaming a game](../guides/how-to-screen-share-in-1080p.md)
* Ensure your computer is not overloaded, especially in [larger group rooms](nothing-shows-up-in-obs-or-it-is-choppy.md#performance-optimization)
* If issues only exist for guests in a room, consider using [\&meshcast](../steves-helper-apps/meshcast.io.md) or increase the [total room bitrate](../advanced-settings/video-bitrate-parameters/totalroombitrate.md)

{% content-ref url="packet-loss.md" %}
[packet-loss.md](packet-loss.md)
{% endcontent-ref %}

## VDO.Ninja Troubleshooting Guide

### Platform-Specific Issues

#### Windows

* Ensure that the "Enable Browser Source Hardware Acceleration" checkbox is checked in the advanced settings.
* If you get black video when it's checked:
  * Try unchecking the Hardware Acceleration checkbox (may be choppy and use more CPU)
  * Run OBS Studio as an Administrator
  * Update OBS Studio to the newest version (fully uninstall old version first)
  * If using OBS 64-bit, try the 32-bit version instead
  * Enable Compatibility Mode for OBS (right-click OBS icon → properties)
* Ensure you have started in Administrator mode

<figure><figcaption><p>Make sure that the custom frame rate is not set</p></figcaption></figure>

#### macOS

* Old versions of OBS, such as OBS v24 to v26.0 do not natively support VDO.Ninja, but version 26.1.2 and newer does.
  * Use the Electron Capture app if you are using a non-compatible version of OBS. > [Get it here](https://github.com/steveseguin/electroncapture) <

#### Mobile Devices

* For Android smartphones, try using Firefox instead of Chrome if having issues
* For Samsung A-series smartphones (especially Galaxy A12), try different browsers or the native Android app
* Restart your smartphone if it suddenly stops working properly
  * Commonly when this happens the video output might be just black

### Network and Connectivity Issues

#### General Network Troubleshooting

* Run the speed test at [https://vdo.ninja/speedtest](https://vdo.ninja/speedtest) or [https://vdo.ninja/check](https://vdo.ninja/check) to verify the connection works
* Use diagnostic tools at [https://vdo.ninja/browsercheck](https://vdo.ninja/browsercheck), https://browserleaks.com/webrtc, or https://networktest.twilio.com/ to ensure WebRTC is enabled
* Check the stats while using VDO.NInja by adding `&stats` to the VDO.Ninja URL&#x20;
* If video is choppy, ensure there is no packet loss and that your computer is not overloaded

#### Firewall and Security Issues

* If in Iran, China, Russia, or other sanctioned/restricted country, WebRTC may be blocked; try using a VPN or self-host VDO.Ninja instead.
* If behind a corporate firewall, try switching to cellular network or talking to your IT department
* If using PFSense or a PiHole:
  * Try bypassing it or using a different network
  * Whitelist the IP address of the remote camera source
  * Allow webRTC-related UDP traffic to prevent frame loss
* Disable any anti-virus or other security software temporarily for testing
* Make sure you have not disabled webRTC in your browser settings
* If using Brave or other privacy focused browser, ensure the VPN isn't turned on
* Try a different browser in general, or a different computer/network

#### Connection Types

* If on cellular, try switching to a different network
* If issues persist on one network type, try another (WiFi vs. cellular)
* Try with or without a VPN, such as speedify.com, to see if it helps.
  * Speedify does offer a 1GB free usage tier I believe that's suitable for testing

### Performance Optimization

#### Hardware Issues

* Update your graphics card drivers, especially after a fresh install
* Switch the GPU used by OBS if using an NVidia GPU (via Nvidia control center)
* For laptops:
  * Check this guide: https://obsproject.com/wiki/Laptop-Troubleshooting#for-nvidia-based-laptops
  * Disable power-saving mode
  * Connect power directly to wall outlet

#### Resource Usage

* If your computer is running at high CPU/GPU load:
  * Lower browser source resolution to 1280x720 or even 640x360
  * Try using H264 codec (add `&codec=h264` to the view links)
  * Specify custom frame rate of 30 in browser source options
  * Try adding \&meshcast to your push link to use the SFU service

#### Video Codec Options

* Try different video codecs by adding parameters:
  * `&codec=h264` (often best for performance)
  * `&codec=vp9` (may help with specific devices)

### OBS-Specific Solutions

#### Hardware Acceleration

* If hardware acceleration is unchecked, check it and restart
* If it's checked but not working, try unchecking it
*   In OBS Settings → Advanced menu, try toggling "Browser source hardware acceleration"\
    \

     (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)

#### Alternative Solutions

* Download Electron Capture app instead of using OBS browser source:[ http://electroncapture.app](http://electroncapture.app)
* Consider using Cloud-hosted version of OBS (Paperspace or AWS with Parsec)

#### OBS WHIP Issues

* WHIP protocol may have NAT traversal issues (not fully supported yet)
* Can't publish WHIP via OBS outside your LAN? [Download our patched OBS version](https://backup.vdo.ninja/OBS_VDO_Ninja.zip). [\[source\]](https://github.com/steveseguin/obs-studio/)
* Try alternative connection methods if WHIP fails to connect

### Additional Recommendations

* Restart all devices involved (computer, phone, router) before extended troubleshooting
* If a device was working before but suddenly isn't, try a simple restart first
* For persistent issues, consider trying an entirely different device or browser
* Consider network congestion during peak hours as a possible cause of intermittent issues
* If you're experiencing issues with PFSense, check its logs for blocked connections
* Make sure you haven't limited the frame rate in the OBS browser source to something like 30-fps
* Always update to the latest browser versions as WebRTC support improves with each update
* Try an older version of VDO.Ninja, such as [https://vdo.ninja/v27.4/](https://vdo.ninja/v27.4/)




# Video freezes mid-stream

If the stream or camera _freezes_ after a while, there could be many reasons. Let's explore some causes and solutions below.

### Camera / USB issues

If cycling the camera to a different camera, or refreshing the camera via the settings menu, fixes the issue, then this normally implies the issue is with the camera or its USB connection.

As a stop-gap solution, the director has the remote control ability to toggle the camera of a guest to unfreeze it. This can be done without the guest's permission even if the [`&consent`](../source-settings/consent.md) flag is added to the guest's URL ahead of time. In a pinch, this can at least give the director some comfort to go live, fixing any stuck camera within a few seconds themselves, versus asking the guest to refresh their page.

If not using a group room, the publisher of a stream can also refresh their own camera via the settings menu, and clicking the refresh icon next to the camera.

\

To fix the problem though, a bit of troubleshooting may be needed. More often than not, if using a USB 3.x camera, the cause is a USB-related issue.

* Try a different USB 3.0 cable; ideally a short cable that conforms to the USB 3.1 specification or newer.
* Do not plug any USB camera into a USB hub, dock, or use it alongside other high-bandwidth USB devices.&#x20;
* Try a different USB port; try them all if needed; a blue USB 3.0 port is normally required.
* Reduce the frame rate and/or resolution of the camera. Lowering the bandwidth over the USB connection may help. 1280x720 @ 30fps is recommend trying, if possible.
* Update the drivers on the computer, especially those for the USB controller and camera. Update the operating system as well, if needed, re-installing old drivers if possible.
* If using an AMD motherboard, update the BIOS of your motherboard, and perhaps set your PCIe lane speed to Gen3, instead of Gen4.
* If using a laptop in particular, ensure the USB port is not set to go to sleep; this would be a Windows setting. Also, enabling _Performance Mode and being plugged into the wall,_ may help as well. See the below images:

 (1) (1).png>).png>)

### Internet /connection issues

\
If the issue is not fixed by toggling your camera, make sure your internet connection is stable and you're device is not overloaded. Bad connections, network firewalls, or VPNs can cause the video to lose connection and then reconnect, causing the picture to appear to freeze for several seconds or longer.

VDO.Ninja requires a solid Internet connection with no interfering services to work its best. On some networks, especially during prime-time evening hours of the day, connections can drop out for seconds at the time constantly.&#x20;

Mobile devices may also have the video freeze for a few moments at a time if switching between cellular networks and WiFi networks, but in these cases things will auto-reconnect within a few seconds normally.

Services like [https://speedify.com](https://speedify.cm) can offer a VPN with bonding, designed for streaming, and it can help avoid network issues on mobile networks, where IP addresses or wireless connections constantly are changing.

### iPhone specific issues

Regarding mobile, iOS users can only send video to 3 viewers at a time if using the H264 hardware encoder. Newer versions of VDO.Ninja will try to keep track of how many H264 streams are being used, and revert to VP8-software-based encoding when the hardware encoders are maxed out, however VP8 encoding can cause iPhones to get very warm. If forcing H264 with an iPhone or iPad, and you max them out, you might cause videos to freeze or go black though.\
\
View links and scenes can sometimes can use an iPhone H264's encoder, even if the video isn't visible in OBS. If having issues, try to avoid forcing the H264 encoder or using it sparingly for only the active sources. If using [`&broadcast`](../advanced-settings/view-parameters/broadcast.md) mode, only the director and scenes could possibly contribute to using an H264 encoder; other guests won't have access to the guest's video stream, so they won't count towards this H264 encoder total.

### H264 specific issues

Some Windows computers that can offer H264 hardware encoding with AMD or NVIDIA GPUs run into the same limitations that an iPhone device may have. That is, if more than 2 or 3 video streams are being published that use H264 encoding, the hardware encoder on those devices may fail.

If someone if using OBS to publish H264 video via RTMP using NVIDIA's NVenc, while also publishing H264 video to VDO.Ninja, conflicts may arise, and video streams may fail. This shouldn't happen really, but in theory, it's something to be aware of.




---
description: Permission denied when trying to access the camera or microphone
---

# Enable Camera / Microphone permissions

Once camera / microphone permission have been denied, often accidentally, the browser won't let VDO.Ninja ask for it again. You'll need to manually change the permission to fix it, or use a different browser. How to change the permission depends on the browser and operation system.

I've provided links to some guides. If these guides are helpful for you, I'll offer a guide in [VDO.Ninja](https://vdo.ninja/) to help future users when I detect permissions have been denied.

### _**How to change a site's camera & microphone permissions**_

[https://support.google.com/chrome/answer/2693767?hl=en\&co=GENIE.Platform%3DAndroid\&oco=0](https://support.google.com/chrome/answer/2693767?hl=en\&co=GENIE.Platform%3DAndroid\&oco=0)

### **Android - Chrome Browser**

1. On your Android device, open the Chrome app
2. To the right of the address bar, tap More -> Settings
3. Tap Site Settings
4. Tap Microphone or Camera
5. Tap to turn the microphone or camera on or off; If you see the site you want to use under Blocked, tap the site -> Access your microphone -> Allow

**If you’ve turned off microphone access on your device**, you can [control your app permissions on Android](https://support.google.com/googleplay/answer/6270602?hl=en) to use your mic.

**If you're using a Chrome device at work or school**, your network administrator can set camera and microphone settings for you. In that case, you can't change them here. [Learn about using a managed Chrome device](https://support.google.com/chromebook/answer/1331549).

### **Chrome Desktop**

1. Open Chrome
2. At the top right, click More -> Settings
3. Click Privacy and security -> Site settings -> Camera or Microphone
4. Select the option you want as your default setting\
   &#x20;    \- Review your blocked and allowed sites\
   &#x20;    \- To remove an existing exception or permission: To the right of the site, click Delete\
   &#x20;    \- To allow a site that you already blocked: Under "Not allowed," select the site's name and change the camera or microphone permission to "Allow."

If you still have issues, try a different browser; perhaps Firefox.

 (1) (3).png>)

### **Firefox Desktop**

[https://support.mozilla.org/en-US/kb/how-manage-your-camera-and-microphone-permissions](https://support.mozilla.org/en-US/kb/how-manage-your-camera-and-microphone-permissions)

### **Firefox Mobile**

In Firefox Mobile, you can try going to **Settings** -> **Site permissions** -> **exceptions** (at bottom) -> **VDO.Ninja**, and then manually set the permissions for the camera and microphone to **enabled**.

If Firefox Mobile still gives you issues afterwards, try in incognito mode, try a different browser, or fully restart the device.

### Vivaldi / Brave / Opera

You can try following the same steps needed for Chrome above, however if that fails, ensure VDO.Ninja is not being loaded via an IFrame.

In the case of [invite.cam](https://invite.cam/) for example, which loads VDO.Ninja via an IFrame, you may need to give microphone and camera permissions to both the invite.cam and VDO.Ninja domains.

You can visit [invite.cam](https://invite.cam/) and [vdo.ninja](https://vdo.ninja/), and for each domain, ensure the microphone and camera permissions are set to allow.

### **iOS**

On an iPhone, it's a bit more complicated:\
[https://gagonfamilymedicine.com/how-to-give-an-app-permission-to-access-your-microphone-on-an-iphone-or-ipad/](https://gagonfamilymedicine.com/how-to-give-an-app-permission-to-access-your-microphone-on-an-iphone-or-ipad/)

If the issue persists, fully close Safari and try again. Sometimes updating your version of iOS and restarting can help solve issues with camera permissions as well.

### IFrame permissions not provided

If embedding VDO.Ninja into a site as an IFrame, you'll not be allowed access to camera or microphones unless that IFRAME-element has allowed said permissions.\
\
See the documentation for more details

{% content-ref url="../guides/iframe-api-documentation.md" %}
[iframe-api-documentation.md](../guides/iframe-api-documentation.md)
{% endcontent-ref %}

### Try safe mode

Adding [`&safemode`](../newly-added-parameters/and-safemode.md) or [`&videodevice=0`](../source-settings/videodevice.md)[`&audiodevice=0`](../source-settings/audiodevice.md) to the [https://vdo.ninja/](https://vdo.ninja/) link can either try the camera in safe mode or disable the camera/microphone completely.

In either mode, you might be able to bypass the initial camera selection page, or start the system with the default camera settings.

If you are able to start the session in this mode, you can go to the VDO.Ninja gear icon (settings), click on User settings, and then clear the local storage. You can then retry, refreshing the page, and try to connect again.




---
description: >-
  For those on macOS, if the camera works in Safari, but not Chrome, try the
  following options
---

# Camera works in Safari; not Chrome

### Check if its VDO.Ninja specific or browser-wide

Often the camera will not just fail to load in VDO.Ninja, but fail to load with any web app in Chrome or browser.

You can confirm its not VDO.Ninja specific by going to the following page and seeing if the camera works with this simple camera app: [https://webrtc.github.io/samples/src/content/devices/input-output/](https://webrtc.github.io/samples/src/content/devices/input-output/)

If it fails only within VDO.Ninja, make sure you've enabled the Camera and Microphone permissions for VDO.Ninja.

<figure><figcaption><p>Make sure VDO.Ninja has access to the camera and microphone</p></figcaption></figure>

### Close other apps or restart the computer

Sometimes another app is using the camera, and closing all other apps or restarting the operating system can fix it up. You cannot use your camera in OBS and in Chrome at the same time, for example.

### Force close the camera app

You can try running the following from your Terminal in MacOS:

```
sudo killall appleh13camerad
sudo killall VDCAssistant 
sudo killall AppleCameraAssistant
```

You can also close the camera app in MacOS via&#x20;

```
Apple Logo > Force Quit > Select All Apps > (find 'Camera process') -> Force Quit.  
```

### Turn off hardware acceleration

In Chrome, you can turn off "Use hardware acceleration when available" in the `chrome://settings/system` page. You'll want to restart the browser after

### Make sure Chrome has access to your microphone and camera

Go to your Security & Privacy page in your MacOS settings, select the privacy tab, and make sure Google Chrome has access to your camera and microphone.

### Reinstall Chrome

Do a full and complete uninstall of Chrome and then re-install. Perhaps try using the Chrome Beta version.  Also make sure not to have any browser extensions install, as they can conflict.

### Try a different camera

Maybe your camera is not working or compatible, for whatever reason. Try a different camera and see if it works.

### Update or reinstall your macOS

As a last resort, reinstalling the system fresh might be an option.




---
description: Accessing the wide-angle or zoom lens on your camera
---

# Can't select a camera lens on mobile

Some camera lenses are not easily accessible in native mobile applications, and many are not available at all in the browser.

The [native app versions](../steves-helper-apps/native-mobile-app-versions.md) of VDO.Ninja may sometimes offer additional lens options not found in the browser, but adding all options is still a work-in-progress.

On Android, you can try Firefox Mobile as well as Chrome or other browsers to see if your camera lens appears there. Some manufacturers offer better support for their cameras than others, making lens selection more accessible to browsers and app developers.

Sometimes you can zoom in and the cameras will switch automatically, but this is rare.

### Digital zoom

There is the option to digitally zoom with VDO.Ninja, [\&effects=7](../source-settings/effects.md), will allow you to adjust the digital zoom via the browser. This isn't an ideal solution, but it may work in some cases where optical zoom isn't available.

### Smartphones that support more than one rear camera

Below is a non-exhaustive short list of smartphones that appear to support more than one rear camera in the browser:

* Samsung Galaxy S23 v13.0 supports 2 front, 2 rear
* Samsung Galaxy S24 v14.0 supports 2 front, 2 rear
* Samsung Galaxy S24 Ultra v14.0 supports 2 front, 2 rear
* Samsung Galaxy S22 Ultra v12.0 supports 2 front, 2 rear
* Samsung Galaxy A52 v11.0 supports 2 front, 2 rear

* Huawei P30 v9.0 (/w MS Edge) supports 1 front, 4 rear&#x20;

*   iPhone 15 Pro v17.0 and iPhone 15 Pro Max supports:

    * back triple camera
    * back dual wide camera
    * back ultra wide camera
    * back dual camera
    * back camera
    * back telephoto camera
    * front camera

*   iPhone 15 v17.4 supports:

    * back dual wide camera
    * back ultra wide camera
    * back camera
    * front camera

*   iPhone 14 v16 supports:

    * back camera
    * back ultra wide camera
    * desk view camera
    * back dual wide camera
    * front camera

* iPhone 14 Pro v16 supports
  * back camera
  * back telephoto camera
  * back ultra wide camera
  * desk view camera
  * front camera\

* iPhone 13 v16 supports
  * back camera
  * back ultra wide camera
  * desk view camera
  * front camera

This list was based on results obtained using BrowserStack.com, so cloud-hosted devices. There may be errors with the results obtained, however you can check yourself on BrowserStack usually for free if a camera is supported or if the results have changed.

<div align="left">

<figure><figcaption><p>The iPhone 15 Pro offers extensive camera options</p></figcaption></figure>

</div>

### WHIP mode

VDO.Ninja supports the [WHIP](../advanced-settings/whip-parameters/and-whip.md) streaming protocol, so if there is a native camera app that has proper WHIP-output support, and has the camera features you are looking for, using that can be used with VDO.Ninja.

Currently WHIP support in VDO.Ninja is a bit experimental, but the publishing URL for a WHIP-enabled device to stream to is:

_`https://whip.vdo.ninja/STREAMIDHERE`_

To view a WHIP stream then on VDO.Ninja, have open the following link in your browser:

_`https://vdo.ninja/alpha/?whip=STREAMIDHERE`_

### Lens adapter

There are camera lens adapters available for smartphones for fairly cheap; anywhere from $3 on aliexpress to $20 on Amazon. While not the best solution, it may be a solution available in a pinch that works across all mobile applications and services.

<div align="left">

<figure><figcaption></figcaption></figure>

</div>

### USB  external cameras

With the newest development builds of the Android native app of VDO.Ninja, many external (USB/UVC) cameras are supported.\
\
With iPhones/iPads, USB-based models (iPhone 15 Pro) seem to support some USB video devices as well, via the USB 3.0 port.\
\
Developments around USB/External camera support is ever evolving.




---
description: My camera isn't appearing in Chrome on macOS anymore. why?
---

# Camera on macOS doesn't show?

If your camera isn't appearing in Chrome on macOS, there are several possible reasons and solutions you can try:

#### 1. Check Camera Permissions

Ensure that Chrome has permission to access the camera:

* Open **System Preferences** > **Security & Privacy** > **Privacy**.
* Select **Camera** from the left-hand menu.
* Ensure that **Google Chrome** is checked.

#### 2. Update Chrome

Make sure you're using the latest version of Chrome:

* Open Chrome and go to **Settings** > **About Chrome**.
* Chrome will automatically check for updates and install them if available.

#### 3. Check Site Permissions

Verify that the website has permission to use your camera:

* Open the website where you are trying to use the camera.
* Click the **lock icon** in the address bar.
* Ensure that **Camera, and also the microphone if needed,** is set to **Allow**.

#### 4. Restart Chrome

Sometimes, a simple restart of Chrome can resolve the issue:

* Close Chrome completely.
* Open Chrome again and check if the camera works.
* Or just restart the computer to ensure Chrome has completely been restarted

#### 5. Check for Conflicting Applications

Ensure no other application is using the camera:

* Close any other applications that might be using the camera (e.g., Zoom, Skype, Discord).
* A camera can only be used by one application at a time, so closing other applications may help

#### 6. Reset Chrome Settings

Resetting Chrome settings can help resolve the issue if it's due to a misconfiguration:

* Open **Settings** > **Advanced** > **Reset settings**.
* Click **Restore settings to their original defaults** and confirm.

#### 7. Test Camera in Another App

Verify that your camera works with other applications:

* Open an application like **Photo Booth** or **FaceTime** and check if the camera works.

#### 8. Reinstall Chrome

If the above steps don't work, try reinstalling Chrome:

* Uninstall Chrome from your Mac.
* Download the latest version from Google Chrome's website and reinstall it.

#### 9. Check macOS Updates

Ensure your macOS is up to date:

* Open **System Preferences** > **Software Update**.
* Install any available updates.

#### 10. Hardware Issues

If the camera still doesn't appear, there might be a hardware issue:

* Try connecting an external webcam if you have one.
* If the external camera works, it may indicate an issue with the built-in camera.
* Try plugging the camera into another USB port or such
* Make sure any HDMI adapter has an input that's compatible with the browser, so 8-bit, 30 or 60-fps, and not requiring special drivers to use

#### 11. Browser Extensions

Disable any browser extensions that might be interfering with the camera:

* Go to **chrome://extensions/** and disable extensions one by one to identify if any of them are causing the issue.

#### 12. Try another browser instead

Firefox or Safari or another Chromium-based browser might work, if Chrome does not.

#### 13. Use a virtual camera as an adapter

If your camera works with OBS, perhaps use that to load the camera and then use the OBS Virtual Camera as the camera source.

* Some cameras are only compatible with OBS, and may not work with the browser

#### 14. Some virtual camera drivers on macOS are limited to 1080p30

Many virtual camera drivers on macOS are limited to 1080p30, and in fact, may only work at that specific resolution. If using a virtual camera or a pass-thru camera source, make sure it's outputting 8-bit 1080p 30fps video, to ensure maximum compatibility.

* Vertical or portrait modes are often not supported by virtual camera drivers on macOS
* Chrome and most browsers do not support higher than 60-fps, nor h264-based video devices

#### 15. Try on a Windows PC or an iOS 17 device that has USB 3.0

While a last resort, changing host hardware may work. Windows is popular with live streaming applications due to greater software and hardware compatibly, and if compelled to keep in the Apple ecosystem, you may find your device works with newer iPhones / iPads, which have a USB 3.0 port.





---
description: Using Smartphone as Virtual Camera with VDO.Ninja across multiple applications
---

# Use a Virtual Camera more than Once

### Problem

When using your smartphone as a camera via VDO.Ninja, you may want to use the camera feed in multiple applications simultaneously. By default, most video inputs can only be accessed by one application at a time.

### Solutions

#### 1. OBS Studio Virtual Camera with Multiple VDO.Ninja Streams

OBS Studio has a built-in virtual camera feature with an important limitation:

* **The standard OBS Studio installation only provides ONE virtual camera output**
* However, smartphones on a LAN can often handle sending 2-3 VDO.Ninja streams simultaneously:
  * You can create multiple VDO.Ninja push links from your phone (e.g., one link for OBS, another for StreamLabs)
  * Each application receives its own direct stream from your phone
  * This works well on strong networks and with newer smartphones, though it increases battery usage

This approach allows you to bring separate phone camera streams into different applications (like OBS Studio and StreamLabs) without relying on a single virtual camera.

**Note**: While OBS Studio itself only offers one virtual camera by default, other applications like StreamLabs OBS offer their own virtual cameras. This means you could potentially use both the OBS virtual camera and StreamLabs virtual camera simultaneously for two different outputs.

#### 2. Using Electron Capture App

The Electron Capture app provides a flexible window-capture solution:

* Install Electron Capture from [https://electroncapture.app](https://electroncapture.app/)
* Load VDO.Ninja into Electron Capture
* Multiple applications can capture the Electron Capture window simultaneously

This approach allows you to have multiple applications access your phone's camera feed via window capture, rather than as a virtual camera.

#### 3. Single Browser Method

If all your applications support browser access, this method is simple:

* Open your applications that need camera access in the same browser (Chrome, Firefox, etc.)
* Connect your smartphone to VDO.Ninja in one browser tab
* Open Discord, Google Meet, Microsoft Teams, etc. in other tabs of the same browser
* Each application can access the smartphone camera stream simultaneously

This works because browsers manage camera permissions across all tabs and windows of the same browser instance.

#### 4. NDI Method (Advanced)

For professional setups requiring multiple distinct outputs:

* Connect your smartphone to VDO.Ninja
* Capture in OBS with the NDI plugin installed
* Output NDI streams from OBS
* Use NDI Virtual Input to create virtual cameras from these streams
* Different applications can use these separate virtual camera feeds

#### Future Developments

Multiple virtual cameras may be added to the Electron Capture app in the future, but this feature is not planned for the near term.




---
description: >-
  Last updated November 17th 2021; keep in mind, this article may become dated
  quickly.
---

# iOS (iPhone/iPad)

[VDO.Ninja](https://vdo.ninja/) has been tested with iOS v12 thru v17, but iOS v10 and under is strictly not supported. Older iPad and iPhone devices as a result are not compatible and likely never will be; an iPhone 5 for example will never be supported.

Please upgrade your iOS to at least v16 to avoid some critical bugs, although even newer is generally better.&#x20;

### 1080p mode

H264 is the default video encoder on iOS, yet H264 only supports up to 720p30 on iOS 14 or older. On iOS 15 devices, H264 (the default codec used), supports 1080p30. A frame rate of 60-fps is still not supported though. Newer iOS devices may even support 1080p60 with certain cameras.

Both new and old iOS devices support 1080p30 when using the VP8 codec, which uses software-encoding rather than hardware. You may need to manually specific [`&width`](../source-settings/and-width.md) and [`&height`](../source-settings/and-height.md) to access 1080p mode on iOS 14 and older, but you can use also [`&quality=0`](../advanced-settings/video-parameters/and-quality.md) on iOS 15 and newer.

VP9 is supported on iOS 14, but you have to enable it as an experimental flag in the iOS Safari advanced settings. It supports 1080p, software-based encoding, and acts a lot like VP8. It generally is finicky, with low-frame rates being common, so use at your own risk.

The AV1 video codec is now also supported with modern iOS versions and works quite well with newer iOS devices. You may need to enable this however in the experimental advanced settings though in your Safari settings.

### External microphones and audio device support on iOS

Some external microphones are supported by Safari on iOS, however iOS devices are very finicky as to which microphones are supported. Just because your device is listed, doesn't mean it will work or stay selected.\
\
This is a long-known issue with iPhones, as per their bug tracker: it's not an issue with VDO.Ninja. [https://bugs.webkit.org/show\_bug.cgi?id=211192](https://bugs.webkit.org/show_bug.cgi?id=211192)\
\
I've made a video going over possible solutions here: [https://www.youtube.com/watch?v=BBus\_S8iJUE](https://www.youtube.com/watch?v=BBus_S8iJUE), although many of the points covered in the video can be found below also.

Users with an **iPhone 15 Pro or iPad, which have with USB 3.x support**, have reported success usually with external USB-based microphones, where as devices with Lightning or USB 2.0 ports have had poor success. Given these user reports, I'd recommend getting an iPhone 15 Pro (rather than an iPhone 15 or iPhone 14), or perhaps a newer iPad, if wanting to stay in the Apple ecosystem.

That all said, I did find that some certified Lightning-based TRRS microphone adapters, which register as headsets, sometime seem to work better than other devices. Using a XLR to 3.5mm adapter, I've been able to connect professional microphones to an older iPhone 11 for example.

One Lightning-based TRRS adapter that I have tested for myself that seems to usually work is this one: [https://www.amazon.ca/gp/product/B07Q49SVYR](https://www.amazon.ca/gp/product/B07Q49SVYR)

Many of those cheap Amazon wireless Lightning-based lavalier microphones do not seem to work though, and while they may work with specific applications, they are not well supported by Safari. In testing I can't get them to work, however it's perhaps possible they will in future iOS updates.

AirPods do seem to also often work, if needing something wireless though. **AirPods** can however create clicking or distortion if used as a microphone; please ensure that they are fully-charged if you intend to use them in a live production. If they are on low-power, they will create audible problems.\
\
If willing to use Android, some users have noted that Firefox for Android often works with USB microphones. Firefox mobile on Android supports USB microphones reliably, if that is a potential solution. Since Apple does not allow for third-party browser engines, Chrome and Firefox for iOS are essentially just a re-skinned version of Safari, so they will not work any better unfortunately.

### Low quality audio from iOS

Audio quality from an iOS generally is pretty low quality. Disabling audio enhancements can sometimes help improve the clarity. It is recommended that the user be wearing headphones though to avoid any feedback issues.

iOS does not work with the volume visualizer meter; it causes clicking noises when used, so it has been disabled.

### Random issues

* If full-screening a video on iOS devices, sometimes that can cause the outbound video to freeze.
* Video out from an iOS device may initially be choppy; this usually smooths out over the course of seconds to a minute. If not, try to lower the resolution.
* If your camera does not load or fails to load, fully close Safari / Chrome, and then try again. There seems to be an issue where old tabs or idle apps can block VDO.Ninja from accessing the camera.
* Video shared by an iPhone/iPad to other guests in a group room may be choppy or of low-quality. This is intentional, as otherwise the iPhone would overheat or become too slow to use. Adding [`&forceios`](../advanced-settings/mobile-parameters/and-forceios.md) to the URL of a specific guest can force a different, smoother, behavior for them, but use it sparingly.

### Limited features; no focus/exposure control

iOS does not yet support for many features that VDO.Ninja would like to make use of. It lacks zoom, focus, screen-sharing, exposure, and many other advanced options. These are features Apple needs to enable and allow the browser to access, which currently it does not.

### Native app option

{% embed url="https://apps.apple.com/us/app/vdo-ninja/id1607609685" %}

There is a basic native iOS app provided by VDO.Ninja at this time, but it is extremely basic. It lacks useful screen-capture support, group-room support, and password support. It does work with the Torch light function though, you can zoom with it also, and it's useful to have when Safari refuses to work.

Supporting a native app for iOS takes a lot of resources and time, so it's being developed in tandem with the Android native app using a mobile development framework.




---
description: Mobile app version of VDO.Ninja and other Android related topics
---

# Android

[VDO.Ninja](https://vdo.ninja/) generally works quite well with Android; even older Android devices tend to work reasonable well. The browser-based version of VDO.Ninja is recommend for most users, although there is an native mobile app version for Android that solves some limitations of the web-version.

### Native Android app

The native mobile app for Android is fairly simple, as it can be only used for one-way publishing. It does support screen-sharing though, so it has its value.  It will also work while in the background, and sometimes works on certain devices when the browser-version won't.\
\
Please note, the native app requires a modern version of Android, while the web-based version of VDO.Ninja has been tested with Android 5.1 using Chrome.

The **Google Play Store**  hosted version is here: \
[https://play.google.com/store/apps/details?id=flutter.vdo.ninja](https://play.google.com/store/apps/details?id=flutter.vdo.ninja)  \
(It will auto-update when I push new releases.)

As well, the Android APK file for direct-downloading is hosted here:[\
https://drive.google.com/file/d/1M0kv5nWLtcfl2JOnsAGiG1zUmkeIVLyZ/view?usp=sharing](https://drive.google.com/file/d/1M0kv5nWLtcfl2JOnsAGiG1zUmkeIVLyZ/view?usp=sharing)\
(Manually installing will requires manual updating, as well.  APK last updated May 12, 2022)

Source-code for building the Android app is here:\
[https://github.com/steveseguin/vdon\_flutter/](https://github.com/steveseguin/vdon\_flutter/)

### External camera support

UVC-based video devices are not supported currently with most Android devices via browser, but a few perhaps, like the Yolobox, may support it. \
\
There is an experimental version of the VDO.Ninja Android app that has USB-video input support, which you can download and sideload from here: [https://drive.google.com/file/d/1L8meslXPEzivocH3wz48abNtJ926hQUr/view?usp=drive\_link](https://drive.google.com/file/d/1L8meslXPEzivocH3wz48abNtJ926hQUr/view?usp=drive\_link)\
\
It may not work with Android 14 however, and USB audio isn't supported I believe.\
\
If that doesn't work, screen-sharing is an option to make it work, where you can load up an app that does support UVC/USB cameras, and simply screen share that output to VDO.Ninja using the native Android app.\
\
Newer iOS/iPad devices with USB-3 support may have USB media support, and the Raspberry Ninja project also supports HDMI/USB input, if you have a mobile Linux system, like an Orange Pi 5 Plus. The Orange Pi 5+ has a built-in HDMI input port.

### USB audio device support

USB-based audio devices have limited support with VDO.Ninja on Android. Some Android devices will support USB audio using Chrome, although many will not.

**Firefox mobile seems to support USB audio devices fairly often,** so give Firefox a go if looking for support there. So definitely try Firefox out if using Android and looking to use USB microphones.

If nothing works, using a 3.5mm to USB adapter will sometimes work, if your audio device has 3.5mm mic out as an option. You may also need a TRRS (not TRS) adapter. Below are a couple that I use  successfully on my Google Pixel smartphone:\
[https://www.amazon.ca/gp/product/B08NVRV6G9](https://www.amazon.ca/gp/product/B08NVRV6G9)\
[https://www.amazon.ca/Headphone-Splitter-KOOPAO-Compatible-Microphone/dp/B08RML676M](https://www.amazon.ca/Headphone-Splitter-KOOPAO-Compatible-Microphone/dp/B08RML676M)\
\
Often a USB audio device that is treated as a headset/communication device, rather than just a microphone or game device, will work.

### Samsung phones

For most users, using Chrome on Android is the recommended way of connecting. There are some exceptions, such as for Samsung users. Using the Samsung Galaxy browser is recommended instead of Chrome for Samsung devices if issues with Chrome exist. On the Galaxy S21 for example, it seems that you can get 60-fps when using the Galaxy browser, but only 30-fps when using Chrome. Chrome might have advantages over the Samsung browser though, such as maybe zoom-functionality, so perhaps try both and see which works better for you.

### Battery life

If battery life or heat is an issue on Samsung or other Android devices, limiting the frame rate to 30-fps and possibly the resolution to 720p can allow the H264 hardware encoder to work ([`&codec=h264`](../advanced-settings/view-parameters/codec.md)). The default target frame rate of 60-fps may prevent H264 from working on some phones, causing heat issues due to software-encoding being used.&#x20;

### Firefox

Firefox on Android seems to fix a couple Chrome-specific issues. Chrome will mute the microphone after a minute if the screen is turned off, but Firefox doesn't seem to do that. With Samsung devices, Chrome combined with H264 hardware encoding may have color issues with the OBS Browser source, but that issue isn't present when using Firefox as the mobile browser. So, for Samsung devices, you might find Firefox, with [`&fps=30`](../advanced-settings/video-parameters/and-fps.md) and [`&codec=h264`](../advanced-settings/view-parameters/codec.md) as parameters (push and view side respectively), may help keep things cool.

### Internal Cameras

Not all cameras may appear as options when using a mobile device; this comes down to the manufacturer of the phone really. If you cannot select your fish-eye camera, try instead buying a fisheye lens adapter from Amazon for a couple dollars; it will offer better performance probably anyways. The Android APK version of VDO.Ninja will reveal a few extra cameras (wide angle, for example), versus the browser, but it may still not support all.

### Screen sharing

Screen sharing on mobile devices is not support via the Browser, although Android devices can screen sharing using the native Android app (linked previously). The screen sharing function may not include audio, or at least it might be unstable, and this will hopefully be addressed over time with additional development of the mobile app.

For iPhone screen sharing, you can refer to [this guide](../guides/screen-share-your-iphone-ipad.md). It conceptually might also work for Android users, if the native app provided by VDO.Ninja does not work.

### Performance issues

Android devices are not powerhouses; disabling video sharing for mobile users in group rooms if there are problems. More than around 7 guests in a room will probably require the Android users add [`&roombitrate=0`](../advanced-settings/video-bitrate-parameters/roombitrate.md) to their URL invite links, to disable their video sharing to other group members.

### Camera selection page freezes

If using Android 11 and the camera selection page in VDO.Ninja freezes, push the browser to the background and then open it to the foreground again. This will unfreeze the window. This is a bug in Android 11; not VDO.Ninja.

### Corrupted video; green or grey pixels

Pixel devices have problems in Portrait mode, where the video may glitch to be all green or such at times. Using [`&codec=vp9`](../advanced-settings/view-parameters/codec.md) on the viewer side or [`&scale=20`](../advanced-settings/view-parameters/scale.md) can offer some solutions, maybe though. Try starting the device in landscape mode, then move to portrait, also to see if that helps.

### External audio

USB audio devices should work with Android devices, but it will depend on numerous factors. In most cases, the 3.5mm headset port on some Android phones will be the most reliable way to attach an external headset or microphone.\
\
3.5mm TRRS inputs often work, and some USB devices that work as headset devices work with Chrome.\
\
Firefox tends to work with more USB audio devices than Chrome, but you might find MS Edge mobile works also.\
\
Bluetooth devices are hit and miss at the moment

### On-screen overlays blocking access

On-screen overlay apps may cause some Android devices to get errors when trying to select their camera via the browser. Disable any apps on your device that may be causing an overlay on the screen or has the power to do so. Try the native Android app if this fails still.

### Supported Android versions

VDO.Ninja has been tested to work on a Nexus 9 running Android 5.1 and Chrome. Performance wasn't great, but usable as a remote webcam.




# macOS

{% hint style="info" %}
As of January 2021, OBS for macOS now supports VDO.Ninja natively. Update to OBS v26.1.2 for macOS to obtain access.
{% endhint %}

Please note that only H264 hardware decoding is supported, so you may wish to specify [`&codec=h264`](../advanced-settings/view-parameters/codec.md) in your OBS view links to reduce CPU load.

For those using older versions of OBS or StreamLabs, I recommend instead using the Electron Capture app to assist: [https://github.com/steveseguin/electroncapture](https://github.com/steveseguin/electroncapture). Follow the link for instructions and files.

## Capturing audio

{% hint style="info" %}
_Please note: This section is obsolete now, unless you are still using the Electron Capture app on macOS. For other users, update to OBS v26.1.2 to obtain audio capture support directly in OBS itself. (Be sure to select "Control audio via OBS" when setting up your browser source in OBS to allow for this)_
{% endhint %}

To capture audio on macOS using the Electron Capture app, you'll need a virtual audio cable; something to loopback the audio-output back into the system as an input source. Some software options include:

| Software      | Price        | URL                                                                                                                                                                                  |
| ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Blackhole     | **Free**     | [https://existential.audio/blackhole/](https://existential.audio/blackhole/)                                                                                                         |
| VB Cable      | Donationware | [https://vb-audio.com/Cable/](https://vb-audio.com/Cable/)                                                                                                                           |
| Loopback      | _Paid_       | [https://rogueamoeba.com/loopback/](https://rogueamoeba.com/loopback/)                                                                                                               |
| Audio Hijack  | _Paid_       | [https://rogueamoeba.com/audiohijack](https://rogueamoeba.com/audiohijack)                                                                                                           |
| iShowU        | _Paid_       | [https://obsproject.com/forum/resources/os-x-capture-audio-with-ishowu-audio-capture.505/](https://obsproject.com/forum/resources/os-x-capture-audio-with-ishowu-audio-capture.505/) |
| Soundflower   | **Free**     | [https://rogueamoeba.com/freebies/soundflower/](https://rogueamoeba.com/freebies/soundflower/)                                                                                       |
| GroundControl | **Free**     | [https://www.gingeraudio.com/](https://www.gingeraudio.com/)                                                                                                                         |

With the above software, you can also share and stream your macOS desktop audio: [Guide Here](https://kast.zendesk.com/hc/en-us/articles/360031463111-How-to-stream-computer-audio-on-a-Mac)

If your mac is unable to handle OBS and VDO.Ninja, another solution use the cloud to host OBS remotely.

Here is an example of a pay-by-the-hour cloud server you can rent for a few dollars: [https://console.cloud.google.com/marketplace/details/nvidia/nvidia-gaming-windows-server-2019](https://console.cloud.google.com/marketplace/details/nvidia/nvidia-gaming-windows-server-2019) It works great, but takes some time to setup for novices. You can also use Paperspace or AWS Workstations as a remote Windows options; Paperspace is easier to get going with. When picking a VM to use, you'll want a machine with a dozen or more vCPU cores, and/or a system with an Nvidia GPU. A GPU works quite well to accelerate RTMP video encoding and VDO.Ninja video decoding.

## Safari on macOS

While Safari may work with VDO.Ninja, it is generally advised to not use Safari with macOS. The microphone may become muted if the tab is minimized, echo-cancellation doesn't quite work as well as with Chromium-based browsers, video/audio issues are more common, and many of the advanced features offered by VDO.Ninja are not supported on non-Chromium-based Browsers. Consider using the Electron Capture app if adverse to installing or using Chrome, as it is based no Chromium but community created specifically for VDO.Ninja.




# Opera GX

As of this writing, with Opera GX v75, playback of h264 video seems to fail. This implies that iOS devices will not playback optimally, if at all, on Opera GX. Using [`&codec=vp8`](../advanced-settings/view-parameters/codec.md) can sometimes solve this issue.




# Firefox

Firefox is not fully supported, although we try to maintain basic support for remote guest usage. It is recommend that you use:

* Chrome on PC
* Chrome on Android (maybe Opera if issues arise with Chrome)
* Chrome on macOS
* Safari on iOS

Firefox can sometimes work when Chrome does not. With some video camera devices, Chrome may fail to load a camera device, while Firefox will work.

OBS uses Chromium (CEF v75 currently), so there should be fewest issues if you stick to using Chrome or another Chromium-based browser. Chromium v75 is quite dated, so OBS will not have support for things like video buffers (ie: [`&buffer=300`](../advanced-settings/view-parameters/buffer.md)), while if using Chrome for playback, you will. Firefox is much the same; it has support for some features, but many features that are offered in Chrome are not yet available in Firefox.

Firefox does not support desktop audio sharing when using screensharing. Chrome does support desktop and tab audio sharing.

Firefox may lack support for some features like remote zoom and detailed debug stats.

Firefox supports up to around 2.5-mbps for 720p video and up to around 6-mbps for 1080p. It offers little control over video bitrates.

Firefox does not treat Stereo audio in the same way that Chrome does. Results using [`&stereo`](../general-settings/stereo.md) and Firefox may vary.




---
description: Disables the video button; guests can't mute video
---

# \&novideobutton

Sender-Side Option! ([`&push`](../source-settings/push.md))

## Aliases

* `&nvb`

## Details

Disables the video button. Guests can't mute their video input.

 (1).png>)

## Related

{% content-ref url="nomicbutton.md" %}
[nomicbutton.md](nomicbutton.md)
{% endcontent-ref %}

{% content-ref url="../source-settings/and-nospeakerbutton.md" %}
[and-nospeakerbutton.md](../source-settings/and-nospeakerbutton.md)
{% endcontent-ref %}




---
description: Lets the director perform alongside guests, showing up in scene-view links
---

# \&showdirector

Director Option / Viewer-Side Option! ([`&director`](director.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&sd`

## Options

Example: `&showdirector=3`

<table><thead><tr><th width="211">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code> | (no value given)</td><td>should allow everything from the director into the scene, except webpage shares and widget shares</td></tr><tr><td><code>2</code></td><td>allows the director's video from the director in scenes, but not audio</td></tr><tr><td><code>3</code></td><td>should allow the director's screen share to appear scene links, but not their main camera stream</td></tr><tr><td><code>4</code></td><td>allows everything, including iframe/webpage shares</td></tr></tbody></table>

## Details

This URL value can be added to the director's URL (`&director=roomname&showdirector`) or to the scene link (`&scene&showdirector`) when you wish the director to appear in those links. You can also enable this flag a couple other ways.

* As a director, you will now appear as a performer kind of like other performers.
* The ability to add/remove the director's camera/audio from scenes becomes available, including a new highlight guest option, the ability to record, re-order, and more.
* By default, a director normally won't appear in any scene link or group link, and has limited functions available.

 (1) (1) (1).png>) (1) (1) (1) (1).png>)

* When a director enables their camera, while in `&showdirector` mode, they gain access to following set of options for the director's camera feed specifically:

 (1) (1) (1).png>)

## Related

{% content-ref url="director.md" %}
[director.md](director.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/view-parameters/scene.md" %}
[scene.md](../advanced-settings/view-parameters/scene.md)
{% endcontent-ref %}




---
description: Enters a room as the director, instead of a guest and have full control
---

# \&director

Director Option!

## Aliases

* `&dir`

## Options

Example: `&director=RoomName`

<table><thead><tr><th width="211">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>opens the director page</td></tr><tr><td>(room name)</td><td>room name to enter as the director</td></tr></tbody></table>

## Details

Directors have powers over some aspects of those in a group room and its scenes.

<figure><figcaption></figcaption></figure>

{% hint style="warning" %}
**First** director **to join** a room **claims the room**. There can be ONLY ONE! (1)
{% endhint %}

In the newer versions there is an option to have multiple directors aka [`&codirector`](../director-settings/codirector.md).

## Related

{% content-ref url="../director-settings/codirector.md" %}
[codirector.md](../director-settings/codirector.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/director-parameters/and-roomkey.md" %}
[and-roomkey.md](../advanced-settings/director-parameters/and-roomkey.md)
{% endcontent-ref %}

{% content-ref url="../director-settings/cleandirector.md" %}
[cleandirector.md](../director-settings/cleandirector.md)
{% endcontent-ref %}

{% content-ref url="and-showdirector.md" %}
[and-showdirector.md](and-showdirector.md)
{% endcontent-ref %}




---
description: Disables the mic button; guests can't mute audio
---

# \&nomicbutton

Sender-Side Option! ([`&push`](../source-settings/push.md))

## Aliases

* `&nmb`

## Details

Disables the mic button. Guests can't mute their audio input.

.png>)

## Related

{% content-ref url="and-novideobutton.md" %}
[and-novideobutton.md](and-novideobutton.md)
{% endcontent-ref %}

{% content-ref url="../source-settings/and-nospeakerbutton.md" %}
[and-nospeakerbutton.md](../source-settings/and-nospeakerbutton.md)
{% endcontent-ref %}




# IFRAME API





# add

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action            | Value              | Required | Description |
| ----------------- | ------------------ | -------- | ----------- |
| target (required) | '\*' \| (streamID) | yes      |             |
|                   |                    |          |             |
|                   |                    |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "target": "*",
    "add": true
});
```




# advancedMode

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "advancedMode": true
});
```




---
description: Set a video bitrate for a video; scene or view link; kbps. Lockable.
---

# audiobitrate

## Type

number

## Co-actions

| Action | Type    | Required |                                                        |
| ------ | ------- | -------- | ------------------------------------------------------ |
| "lock" | boolean | No       | Locks bitrate (prevents the automixer from overriding) |

### Example

```
iframe.contentWindow.postMessage({ "audiobitrate": 3000, "lock": true });
```




---
description: Stop the auto mixer if you want to control the layout and bitrate yourself
---

# automixer

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
|        |       |          |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "automixer": true
});
```




---
description: Set a video bitrate for a video; scene or view link; kbps. Lockable.
---

# bitrate

## Type

number

## Co-actions

| Action | Type    | Required |                                                        |
| ------ | ------- | -------- | ------------------------------------------------------ |
| "lock" | boolean | No       | Locks bitrate (prevents the automixer from overriding) |

### Example

```
iframe.contentWindow.postMessage({ "bitrate": 3000, "lock": true });
```




---
description: Mutes/unmutes camera
---

# camera

Sender Option! ([`&push`](../../source-settings/push.md))

| Value    | Description    |
| -------- | -------------- |
| true     | Turns mic on   |
| false    | Turns mic off  |
| "toggle" | Toggles on/off |

### CODE EXAMPLE

```
iframe.contentWindow.postMessage({ "camera": true });
```




# changeAudioDevice

## Type

number

### Example

```
iframe.contentWindow.postMessage({ "changeAudioDevice": 1 });
```




# changeAudioOutputDevice

## Type

number

### Example

```
iframe.contentWindow.postMessage({ "changeAudioODevice": 1 });
```




# changeVideoDevice

## Type

number

### Example

```
iframe.contentWindow.postMessage({ "changeVideoDevice": 1 });
```




---
description: Disconnect and hangup all inbound streams.
---

# close

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Aliases

hangup

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
|        |       |          |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "close": true,
});
```




# Director Options





# General Options





---
description: Mutes / unmutes the speaker
---

# mute

General Option! ([`&push`](../../../source-settings/push.md), [`&room`](../../../general-settings/room.md), [`&view`](../../../advanced-settings/view-parameters/view.md), [`&scene`](../../../advanced-settings/view-parameters/scene.md), [`&director`](../../../viewers-settings/director.md))

## Related URL Param

{% content-ref url="../../../source-settings/and-mutespeaker.md" %}
[and-mutespeaker.md](../../../source-settings/and-mutespeaker.md)
{% endcontent-ref %}

## Options

| Value    | Description         |
| -------- | ------------------- |
| true     | Mute speaker        |
| false    | Un-mute speaker     |
| "toggle" | Toggle speaker mute |

## Example

```javascript
iframe.contentWindow.postMessage({
    "mute": true
});
```




---
description: Insert a custom style sheet
---

# getDetailedState

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
|        |       |          |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "style": "{ border: dashed 4px tomato }"
});
```




# getDeviceList

## Type

true

### Example

```
iframe.contentWindow.postMessage({ "getDeviceList": true });
```




# getEffectsData

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
|        |       |          |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "getEffectsData": true,
});
```




# getLoudness

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
|        |       |          |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "getLoudness": true,
});
```




# getRemoteStats

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| (any) |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
|        |       |          |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 

});
```




---
description: >-
  Webrtc send message to every connected peer; like send and request; a hammer
  vs a knife.
---

# getStats

Sender Option! ([`&push`](../../source-settings/push.md))

## Options

| Value | Description    |
| ----- | -------------- |
| (any) | Reloads iframe |

### Example

```

iframe.contentWindow.postMessage({ 
    "getStats": null,
});
```




---
description: >-
  Get a list of stream Ids, with a label if it is present. label = false if not
  there
---

# getStreamIDs

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
|        |       |          |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "getStreamIDs": true,
});
```




---
description: >-
  Get a list of stream Ids, with a label if it is present. label = false if not
  there
---

# getStreamInfo

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
|        |       |          |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "getStreamInfo": true,
});
```




# keyframe

| Value | Description   |
| ----- | ------------- |
| true  | Send keyframe |

### CODE EXAMPLE

```
iframe.contentWindow.postMessage({ "keyframe": true });
```




# panning

| Value   | Description                |
| ------- | -------------------------- |
| (0-180) | set stereo panning (0-180) |

### CODE EXAMPLE

```
iframe.contentWindow.postMessage({ "panning": 100 });
```




# previewMode

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
| layout |       | no       |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "previewMode": true
});
```




---
description: >-
  Webrtc send message to every connected peer; like send and request; a hammer
  vs a knife.
---

# reload

Sender Option! ([`&push`](../../source-settings/push.md))

## Options

| Value | Description    |
| ----- | -------------- |
| (any) | Reloads iframe |

### Example

```

iframe.contentWindow.postMessage({ 
    "reload": null,
});
```




# remove

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action            | Value              | Required | Description |
| ----------------- | ------------------ | -------- | ----------- |
| target (required) | '\*' \| (streamID) | yes      |             |
|                   |                    |          |             |
|                   |                    |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "target": "*",
    "remove": true
});
```




# requestStatsContinuous

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| (any) |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
|        |       |          |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "requestStatsContinuous": true
});
```




# requestStream

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "requestStream": true
});
```




# scale

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
| UUID   |       | no       |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "scene": true
});
```




# scene

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action | Value | Required | Description |
| ------ | ----- | -------- | ----------- |
| layout |       | yes      |             |
|        |       |          |             |
|        |       |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "scene": true
});
```




---
description: Tells the connected peers if they are live or not via a tally light change.
---

# sceneState

## Type

boolean

### Example

```
iframe.contentWindow.postMessage({ "sceneState": true });
```




# sendChat

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

| Value    | Description  |
| -------- | ------------ |
| (string) | Chat message |

### CODE EXAMPLE

```
iframe.contentWindow.postMessage({ "sendChat": "Hello" });
```




---
description: >-
  Send generic data via p2p. Send whatever you want I guess; there is a max
  chunk size of course.
---

# sendData

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

| Value | Description                      |
| ----- | -------------------------------- |
| (any) | Small amount of data to send P2P |

### CODE EXAMPLE

```
iframe.contentWindow.postMessage({ "sendData": { foo: "bar" });
```




---
description: Mutes / unmutes mic
---

# mic

Sender Option! ([`&push`](../../../source-settings/push.md))

## Related URL Param

{% content-ref url="../../../source-settings/and-mute.md" %}
[and-mute.md](../../../source-settings/and-mute.md)
{% endcontent-ref %}

## Options

| Value    | Description    |
| -------- | -------------- |
| true     | Turns mic on   |
| false    | Turns mic off  |
| "toggle" | Toggles on/off |

## Example

```
iframe.contentWindow.postMessage({
    "mic": true
});
```




---
description: Webrtc send to viewers
---

# sendMessage

## Type

string

### Example

```
iframe.contentWindow.postMessage({ "sendMessage": "HELLO" });
```




---
description: >-
  Webrtc send message to every connected peer; like send and request; a hammer
  vs a knife.
---

# sendPeers

Sender Option! ([`&push`](../../source-settings/push.md))

## Options

| Value    | Description |
| -------- | ----------- |
| (string) |             |

### Example

```
```




---
description: Webrtc send to publishers
---

# sendRawMIDI

Sender Option! ([`&push`](../../source-settings/push.md))

## Options

| Value  | Description |
| ------ | ----------- |
| (midi) |             |

## Modifiers

| Action   | Value    | Required | Description |
| -------- | -------- | -------- | ----------- |
| UUID     | (string) | no       |             |
| streamID | (string) | no       |             |

### Example

```
iframe.contentWindow.postMessage({ 
    "sendRawMIDI": "11110001",
    "streamID": "someid"
});
```




# settings

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

| Value | Description |
| ----- | ----------- |
| true  |             |
| false |             |

## Modifiers

| Action            | Value              | Required | Description |
| ----------------- | ------------------ | -------- | ----------- |
| target (required) | '\*' \| (streamID) | yes      |             |
|                   |                    |          |             |
|                   |                    |          |             |

### Example

```

iframe.contentWindow.postMessage({ 
    "target": "*",
    "add": true
});
```




---
description: Insert a custom style sheet
---

# style

General Option! ([`&push`](../../source-settings/push.md), [`&view`](../../advanced-settings/view-parameters/view.md), [`&scene`](../../advanced-settings/view-parameters/scene.md))

## Options

### Example

```

iframe.contentWindow.postMessage({ 
    "style": "{ border: dashed 4px tomato }"
});
```




---
description: >-
  This sets the fundamental audio bitrate target, but does not necessarily
  "lock"
---

# targetAudioBitrate

## Type

Number (0+)

### CODE EXAMPLE

```
iframe.contentWindow.postMessage({ "targetAudioBitrate": 1000 });
```




---
description: this sets the fundamental bitrate target, but does not necessarily "lock"
---

# targetBitrate

| Value type         | Description              |
| ------------------ | ------------------------ |
| (positive integer) | Set target bitrate to 30 |

### CODE EXAMPLE

```
iframe.contentWindow.postMessage({ "panning": 100 });
```




---
description: Sets the speaker (output) volume of a video element
---

# volume

## Related URL Param

{% content-ref url="../../../advanced-settings/upcoming-parameters/and-volume.md" %}
[and-volume.md](../../../advanced-settings/upcoming-parameters/and-volume.md)
{% endcontent-ref %}

## Options

| Value   | Description                      |
| ------- | -------------------------------- |
| (0-100) | audio playback volume as percent |
| (0-1.0) | audio playback volume as decimal |

## Modifiers

|          | value      | Required | Description                   |
| -------- | ---------- | -------- | ----------------------------- |
| "target" | (streamID) | no       | Targets a guest by streamID   |
| "target" | "\*"       | no       | Targets every guest (default) |
|          |            |          |                               |

## Example

```
iframe.contentWindow.postMessage({
    "volume": 0.5,
    "target": "*"
});
```




---
description: Typically only supported with H264 video and often hit and miss
---

# Hardware-accelerated video encoding

Hardware-accelerated video encoding is a tricky topic; it can sometimes work, but when it does, it doesn't always work as hoped.

It generally only works with H264 video, but it may work with other codecs in rare cases.

On a Windows PC, a Chromium-based browser offers your best chance of it working. Every month it seems the support for hardware encoding improves, which is great. The viewer just needs to request H264 video from your computer for it to have a chance of working. [`&codec=h264`](../advanced-settings/view-parameters/codec.md)

If it works, in the video stats window (`CTRL + Click`), you'll see the video codec type to be listed as External Encoder, if the hardware acceleration is working. CPU load may not decrease always, and there isn't an easy way to tell which encoder is being used, but if it says the codec is `h264`, then it's likely still using just software.\

 (1) (1).png>)

Despite software using a lot of CPU, it offers better compatibility, fewer glitches, and technically can still handle dozens of video streams at a time if your CPU is fast enough. Hardware however can be finicky, where glitching is common and a hardware encoder typically can only support three video encoding sessions at a time.

What's really strange about hardware encoding on a PC is that it may actually use MORE CPU than the software-based openH264 alternative. If your goal is to save CPU power, a hardware encoder may just introduce more problems and offer no benefit at all; at least if encoding with a PC.&#x20;

You can specify whether to use software or hardware H264 by changing the H264 profile ID; this can be specified, for example, using `&h264profile=42e01f`. `42e01f` should trigger the OpenH264 software encoder, if available.&#x20;

AMD systems, and some Intel systems, the default H264 hardware encoder will limit bitrates. Using VP8 or a software-based H264 encoder could allow for higher bitrates. The software VP8 encoder does seem to use more CPU than the H264 encoders, but it often is more stable, especially for screen shares.

On a MacOS system, Chrome may drop frame rates suddenly when using the H264 encoder.&#x20;

On older versions of iOS, the H264 encoders can sometimes only support 720p30, while the VP8 software encoder on iOS can support 1080p. This recently changed with the iOS \~15, so newer iPhones  can now support 1080p30 with H264. Your iPhone may still get very hot, so I am unsure if its actually hardware-accelerated; newer iPhones will do better than older.\
\
In the past, iOS devices were limited by how many videos could be encoded using H264, often just three total, so keep that in mind. This might have changed with newer iPhones however; untested.

### Android

Many Android phones may not support H264 encoding in Chrome; this seems to vary based on the browser version, device chipset, and other factors. Trying to force H264 with such incompatible devices might result in no video, as the browser isn't always smart enough to know it isn't working. Chrome on Android doesn't seem to have a software-based H264 encoder.\
\
One user has reported that while using Chrome, Brave, and Firefox with their Samsung S23+ has poor performance with video encoding, likely due to using software encoding, Microsoft's Edge browser on Android did make use of the hardware encoding. Performance in this case was near comparable to an iPhone 14 Pro's encoding performance. Users with other devices that also use a Snapdragon GPU may wish to try MS Edge if having lackluster video encoding performance.

With non-Snapdragon GPUs, such as found in entry-level and some mid-range smartphones, the hardware H264 encoder may not be available regardless of browser used. Using software-based encoders may trigger overheating or CPU throttling, especially at higher resolutions, so if you are unable to trigger hardware-encoding on a slower Android device, you may need to be content with lower resolutions and bitrates.

On the Google Pixel the H264/VP8 encoder will glitch like crazy when used in Portrait mode, however it's glitch free when using the VP9 codec via software encoding.

### NVIDIA

If a director, choosing to publish video to your group with H264 might reduce some CPU load, but if using an NVIDIA graphics card, you may end up forfeiting your ability to use NVENC encoding for RTMP or MKV file recording, since NVIDIA only offers typically three encoders. You can unlock this limit, but the benefits of using NVENC with VDO.Ninja often provides no benefits it seems over a software H264 option.

If using a CDN-service like meshcast.io, where a server redistributes the video to a large audience, H264 is highly compatible with most viewers, but this is only true for the OpenH264 profile ID `42e01f` of H264. Hardware-encoded version of H264 may not be compatible with all browsers, such as with Safari viewers, so its not advised.

OperaGX tends to have issues with H264 encoding.

On the bright side, H264 is supported well on macOS, and it seems to use less CPU to decode than VP8. H264 on OBS 27.1 and older (for PC) offers lower packet-loss-induced "rainbow puke" than the VP8 codec, but this isn't a factor anymore with OBS 27.2 and newer. On PC, VP8 and H264 seem to use about the same CPU to decode in OBS. I'd advise you to do your own testing though.

### Minimum resolutions

For many devices that are offering hardware accelerated encoding, a minimum or specific resolution is needed, else the device may switch back to software based encoding.

Sometimes this minimum resolution is 640x360, but other times it might be 1920x1080.

### Embedded and Linux hardware-encoding support

If you're comfortable with Linux, basic publishing into VDO.Ninja is available using GStreamer and Python. The project is located here: [https://github.com/steveseguin/raspberry\_ninja/](https://github.com/steveseguin/raspberry_ninja/)

Hardware encoding with multiple viewer per encoded stream is supported with this option, although features are limited. It is not for the faint of heart; generally this approach is still reserved for hobbyists, enthusiasts, and developers. A Raspberry Pi can publish 1080p30 to VDO.Ninja, and supports HDMI connected cameras; at least when using this project's code.

Code and quick start deployment images are available for the Raspberry Pi and NVIDIA Jetson embedded development boards, along with hardware-encoding support for those platforms.

Other Linux systems are support with the provided code, but it is up to you to ensure the hardware driver and configuration is setup correctly in those cases.

The project will hopefully keep expanding, to include more devices and operating systems.

### H265 / HEVC / AV1

While AV1 hardware encoders are not common at the moment, they should be supported as they are adopted by browsers and hardware manufactures. `&codec=av1`\
\
H265/HEVC however isn't commonly supported by browsers, although Thorium / Safari browsers may support it, it's not an officially supported option. You can give it a try however by using `&codec=h265`.\
\
Update, as of December _2024_: If running Chrome on PC, you try enabling H265 support by using the following command line to start your Chrome instance:\
\
`chrome.exe --enable-features=PlatformHEVCEncoderSupport,WebRtcAllowH265Receive,WebRtcAllowH265Send --force-fieldtrials=WebRTC-Video-H26xPacketBuffer/Enabled`

You can see if your Chrome browser has H265 support enabled by going to https://vdo.ninja/whip and checking out the drop-down list of available codecs.

### OBS WHIP and WHEP

With OBS v30 supporting WHIP output, it's now possible to stream video directly from OBS to VDO.Ninja via WebRTC with hardware accelerated encoding.

There are limitations with OBS's WHIP implementation in version 30 however, which may get addressed in the future, but without a server supporting OBS's WHIP output currently, this option is primarily limited for single point to point video distribution on controlled networks.

You can however use OBS's WHIP output with an SFU server however, such as Cloudflare's WHIP/WHEP server, and VDO.Ninja can ingest the WHEP output from that. This setup would work a bit like how Meshcast works with VDO.Ninja currently, except with the source being specified as WHEP-based, rather than from Meshcast.




---
description: >-
  Maintaining a smooth 1080p60 can be tricky, but there are variety of options
  to achieve the desired results
---

# How to screen share in 1080p

### Bandwidth requirements

To maintain a high quality 1080p60 stream, especially if screen sharing game content, you'll want at least 12-mbps to 20-mbps of upload bandwidth.

You'll also need a pristine Internet connection to maintain a low-latency and smooth result; you can test your connect at [https://vdo.ninja/speedtest](https://vdo.ninja/speedtest). High packet loss will limit the possibility of maintaining both low-latency and high quality video; in such a case, you'll need to prioritize one over the other.

## How to create reusable screen-share links

### Push Link (Sender)

[`https://vdo.ninja/?push=SOMESTREAMID&screenshare&quality=0`](https://vdo.ninja/?push=SOMESTREAMID\&screenshare\&quality=0)\
\
Alias:  [`https://vdo.ninja/?push=SOMESTREAMID&ss&q=0`](https://vdo.ninja/?push=SOMESTREAMID\&ss\&q=0)\
\
Copy one of the two links above and **change&#x20;**_**SOMESTREAMID**_**&#x20;into a different name**. The name picked just needs to be a unique alphanumeric value is not already in active use.

You can also add [`&fps=60`](../advanced-settings/video-parameters/and-fps.md) to the link, to attempt to force 60-fps, but the default with [`&quality=0`](../advanced-settings/video-parameters/and-quality.md) is already 60-fps.

### View Link (Viewer)

[`https://vdo.ninja/?view=SOMESTREAMID&videobitrate=10000&scale=100`](https://vdo.ninja/?view=SOMESTREAMID\&videobitrate=10000\&scale=100)\
\
Alias:  [`https://vdo.ninja/?v=SOMESTREAMID&vb=10000&scale=100`](https://vdo.ninja/?v=SOMESTREAMID\&vb=10000\&scale=100)\
\
Copy one of the two links above and change SOMESTREAMID in the same name as you did for the Push Link. You can change [`&videobitrate=10000`](../advanced-settings/video-bitrate-parameters/bitrate.md) to another value if you want to change the bitrate.

### Explanation

| Parameter                                                                         | Explanation                                                                 |
| --------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| Push Link                                                                         |                                                                             |
| [`&push=SOMESTREAMID`](../source-settings/push.md)                                | Sets a unique stream ID                                                     |
| [`&screenshare`](../source-settings/screenshare.md)                               | Selects screen sharing instead of webcam                                    |
| [`&quality=0`](../advanced-settings/video-parameters/and-quality.md)              | Sets the resolution to 1920x1080p                                           |
| View Link                                                                         |                                                                             |
| [`&view=SOMESTREAMID`](../advanced-settings/view-parameters/view.md)              | Selects the stream ID                                                       |
| [`&videobitrate=10000`](../advanced-settings/video-bitrate-parameters/bitrate.md) | Sets the video bitrate to 10,000-kbps, you can change the value if you want |
| [`&scale=100`](../advanced-settings/view-parameters/scale.md)                     | Tells the system to not scale down the screen share                         |

{% hint style="info" %}
If you have problems maintaining good video quality, you can add [`&codec=av1`](../advanced-settings/view-parameters/codec.md) to the viewer's side to see if it makes the screen share any better. AV1 is a newer codec with better compression efficiency. H264, VP8, and VP9 are other options to try.
{% endhint %}

### Framerate

Screen sharing at 60-fps is the default, but sometimes this does not always work.

You can try forcing 60-fps by adding [`&fps=60`](../advanced-settings/video-parameters/and-fps.md) to the source (sender-side link). If you get an error, you can try using [`&maxframerate=60`](../source-settings/and-maxframerate.md) instead.

Try disabling variable refresh rates, such as those offered by Freesync or G-Sync.

{% hint style="warning" %}
You may not achieve 60 FPS depending on your hardware, the browser or the type of screen share you use or the viewer uses.\
\
Sharing a chrome window or tab is the best way to get 60 FPS consistently. If you share your screen or any other window you might only get 30 FPS.\
\
Screen sharing a "Window" with Chrome (chromium) tends max out at \~42 FPS, while screen sharing via "Entire Screen" tends to make out close to 59 FPS.
{% endhint %}

### Frame rate or resolution

You can use the [`&contenthint`](../advanced-settings/video-parameters/and-contenthint.md) parameter in some browsers to suggestion whether to prioritize frame rate or resolution. Sometimes getting both high isn't possible.

[and-contenthint.md](../advanced-settings/video-parameters/and-contenthint.md "mention")\
[and-screensharecontenthint.md](../advanced-settings/screen-share-parameters/and-screensharecontenthint.md "mention")

These parameters take detail or motion as a value, based on whether you value resolution or frame rate.

### Versus.cam&#x20;

For an e-sports optimized version of VDO.Ninja, with many of the settings pre-configured for 1080p60 streaming, check out [Versus.cam](../steves-helper-apps/versus.cam.md).

It's free and uses VDO.Ninja, while adding a nifty management dashboard for monitoring inbound game streams. The management page makes it easy for you to remotely change resolution and bitrate without modifying the URL while live.

{% content-ref url="../steves-helper-apps/versus.cam.md" %}
[versus.cam.md](../steves-helper-apps/versus.cam.md)
{% endcontent-ref %}

## Still not getting 60-fps?

Using _Entire Screen_ or _Chrome Tab_ capture, instead of _Window_ capture, can increase the frame rate when screen sharing via the Chrome browser:

For some reason, when screen sharing a _Window_ with Chrome, the frame rate is limited to around 42-fps.\
\
Some users also might find that if they are using FIrefox, they are limited to 30-fps or low-bitrates (around 5-kbps). Please try using Chrome or Edge, or a Chromium-based browser, to see if that improves things.

If you're needing exactly 60-fps, or are still having issues, continue on for more options:

### Using OBS Studio to capture

#### With the browser and a virtual camera

For the best screen-share results, you can use OBS Studio to capture the gameplay, and bring that into VDO.Ninja via the OBS Virtual Camera. This is an annoying added step, but OBS does a better job at capturing gameplay than the browser does.

Frame rates should be close to 60-fps in this mode, but may vary still vary a bit.

#### Using WHIP from within OBS

An alternative to using the Virtual Camera and browser though is to use a feature in OBS to publish directly to VDO.Ninja.

This is an newer feature it may require a special version of OBS at the moment to work, but WHIP support is now included in OBS v30, but it may be another version or two before OBS supports WHIP properly. \
\
If having issues with using OBS WHIP with VDO.Ninja over the Internet, I do have a custom version of OBS that has proper WHIP support [available for Win64 here.](https://backup.vdo.ninja/OBS_VDO_Ninja.zip) \[[fork](https://github.com/steveseguin/obs-studio)]  This version should let you publish WHIP via VDO.Ninja across the Internet, regardless of Firewall. This OBS binary was last built November 2024, but hopefully future releases of OBS make this custom version redundant. :)\

Check out a demo YouTube video of how to accomplish publishing WHIP into VDO.Ninja:\
[Publishing from OBS directly to VDO.Ninja](https://www.youtube.com/watch?v=ynSOE2d4Z9Y)

This mode should give OBS Studio control over frame rate and bitrate, so with a good connection it should be possible to lock in a solid 60-fps.

{% embed url="https://www.youtube.com/watch?v=ynSOE2d4Z9Y" %}
Using WHIP to publish to VDO.Ninja directly from OBS
{% endembed %}

### Using [\&chunked](../newly-added-parameters/and-chunked.md) mode

A fairly experimental, yet very exciting option to streaming over VDO.Ninja is the use of [\&chunked ](../newly-added-parameters/and-chunked.md)mode.

Chunked mode sends the video and audio over the data-channels, as if streaming via RTMP, rather than via the browser's default method of transmitting video. This provides VDO.Ninja more low-level control over the video, frame rate, and buffering.

This mode is more resistant to packet loss and will not vary the frame rate / resolution during the stream.  It does however mean that if you are connection hiccups or is having problems, it will not be able to react and dynamically reduce quality to continuing streaming.

Chunked mode also uses more CPU than the normal mode and so may not respond well to computers that are maxing out their CPU.

To ensure reliability as a result, a buffer is needed; upwards of 1-second buffer delay may be needed to ensure reliable performance.

To screen share using chunked mode, the following is a sample sender-side link:

```
https://vdo.ninja/alpha/?chunked=2000&screenshare&push=STREAMIDHERE
```

A unique part of chunked mode is that the sender sets the bitrate via `&chunked=N`, where N is the kilobits per second of the video.&#x20;

Viewing the stream is the same as normal:

```
https://vdo.ninja/alpha/?view=STREAMIDHERE&buffer=500
```

[`&buffer`](../advanced-settings/view-parameters/buffer.md) can be used to specify the default buffer delay, which accepts a value in milliseconds. The default may change depending on version of VDO.Ninja, but it's roughly between 500ms and 1s in most cases.  Going below 200ms is not advised unless using it over a LAN.

Please provide request/feedback if you use `&chunked` mode, as it's experimental and still being improved upon.

### Meshcast and servers

You can explore using [`&meshcast`](../newly-added-parameters/and-meshcast.md) and [`&relay`](../general-settings/and-relay.md) as options as well. While it is a server-based method of sending video, it can sometimes allow for 1080p video where network conditions are poor.

Meshcast in particular can help stream 1080p video to multiple viewers at once, if the sender does not have a computer and network capable of doing so on their own.

Meshcast may not always be able to achieve 20-mbps speeds, sometimes only 2 to 3-mbps is possible, so it may not always be the best option for those streaming e-sports.

{% content-ref url="../advanced-settings/screen-share-parameters/" %}
[screen-share-parameters](../advanced-settings/screen-share-parameters/)
{% endcontent-ref %}




# How to stream 4K video using VDO.Ninja

{% hint style="warning" %}
Sending a 4K video feed with VDO.Ninja is very CPU intensive. Be prepared to use all of 8 real cpu cores (not threads).
{% endhint %}

## How VDO.Ninja handles video quality

VDO.Ninja has 3 predefined [`&quality`](../advanced-settings/video-parameters/and-quality.md) levels:

* `&quality=0` tries to do 1080p (1920x1080 @ 60fps).
* `&quality=1` is the default. It tries to select 720p (1280x720 @ 30fps ) for both screen capture and webcam.
* `&quality=2` tries to do 360p (640x360 @ 30 fps).
* also there's `&quality=-1` , which will use the device's default resolution, but this could be anything, low or high, so it's a niche option.

By “trying”, I mean that if the resolution is not available, VDO.Ninja defaults to another resolution that the camera supports instead. This way, no errors are thrown and a compatible stream is sent, even if it’s not exactly what you might have desired.

VDO.Ninja is however capable of doing higher resolutions and custom resolutions however; you just need to manually specify the resolution you want. When you manually specify a resolution, if it doesn’t work, an error is thrown.

While I could make a selectable option for 4K in the user interface, another problem with 4K is that it requires a LOT of CPU power to encode. Most users will always select the highest resolution allowed, not understanding that it might actually be a bad idea. Maxing out your CPU can actually result in worse quality with lower frame rates than selecting a lower, safer, resolution.

## Pushing 4K resolution

That all said, you can give “4K” a go by adding [`&width=3840`](../source-settings/and-width.md)[`&height=2160`](../source-settings/and-height.md) to the invite link.

For example then, [https://vdo.ninja/?push=inviteGuest123\&width=3840\&height=2160](https://obs.ninja/?push=inviteGuest123\&width=3840\&height=2160)

If the guest does not support 4K, this will give an error to the guest, stating that the video device is over-constrained.&#x20;

The default frame rate is 60-fps, although if their device does not support that, it will use a lower support frame rate. If you manually specify a frame rate, and the camera or display does not support it, it will also give an error.

### Smartphones

If streaming from a smartphone, not all phones can do 4K; my old LG V30 I believe could do 4K30 via [VDO.Ninja](https://vdo.ninja), but my Pixel 4a seems stuck at 1080p30. As well, an iPhone 11 might only be able to 1080p30, an iPhone 12 might be able to do 1080p60, while an iPhone 15 might be able to do 4K30. It might depend on the iOS version, where older iOS versions are pretty limited, so things will change overtime.

A common question I also get is that a certain phone can record 4K60 in the native phone app, so why not also in VDO.Ninja? Well, just because you can record to disk at 4K does not mean the manufacture has added support for 4K streaming via the browser. It requires additional development, nor is it always possible if the hardware encoder used does not support the advanced requirements of WebRTC.

Samsung devices can sometimes use the built in Samsung Internet browser instead of Chrome to get access to higher resolutions and frame rates; 1080p60 for example with new flagship devices. Sometimes changing cameras or video codecs can allow for higher resolutions as well.

The native mobile app version of VDO.Ninja may at some point support additional cameras that the browser does not, but at present there are not enough development resources available for this. It's desired however.

## What about the bitrate?

Next, while you might have selected 4K, with the exception of static video screen shares, you cannot transfer 4K video with the default video bitrates set. For action, you will need closer to 40-mbps video bitrates set on the viewer’s end. For talking head videos, you will want over 10-mbps and possibly even more. Without a high enough bitrate set, the video will not stream at 4K and more than likely not maintain 60-fps.

To set a target bitrate add [`&videobitrate=20000`](../advanced-settings/video-bitrate-parameters/bitrate.md) for 20-mbps for example. This goes on the viewer link.

## Scaling

You may need to add [`&scale=100`](../advanced-settings/view-parameters/scale.md) to the view link to have the video stream at 4K, if the playback window is smaller than 4K. VDO.Ninja by default resizes incoming videos to fit the playback area, and [`&scale=100`](../advanced-settings/view-parameters/scale.md) overrides that, requesting 100% of the available resolution; so unscaled if possible.

### Codec

A bit like bitrate and scaling, changing the video codec can sometimes help with achieving 4K video. [`&codec=av1`](../advanced-settings/view-parameters/codec.md#av1) can help if the bandwidth is limited, as it is more efficient than other codecs. [`&codec=vp8`](../advanced-settings/view-parameters/codec.md#vp8) is universal, while [`&codec=h264`](../advanced-settings/view-parameters/codec.md#h264) can often trigger the hardware encoder to be used. Using a hardware encoder can help reduce CPU load, allowing for 4K if the system would otherwise be CPU-bottlenecked.

Normally you shouldn't need to change codecs, but sometimes it does make a difference.

## Performance issues

As a result, to successfully stream 4K video, you generally need a computer system with 8 real CPU cores or more, running at 3.6GHz or higher. A modern AMD 3900X-series CPU or Intel 9900K CPU are ideal for this task, but a quad-core laptop will not be. You might be able to get away with lesser bitrates and lesser CPU requirements if just screen-sharing text, but it still is not for the faint of heart.

Lastly, macOS users may find that 4K is simply not possible or very difficult. If you do manage to get it working, it might only operate at 5-fps or so. I don’t quite know why this is, but if you intend on sharing 4K video, you might be better off using a Windows PC. It seems to perform better.

We've successfully streamed 4K50 over 5G cellular Internet at 65-mbps using a MacBook Air M1 and VDO.Ninja.




---
description: >-
  A common question on how to achieve the highest quality capture into OBS for a
  remote interview.
---

# How to get highest video quality (for an interview)

The highest quality possible is a bit tricky, as that will depend on certain factors that may be hard to determine without testing and tweaking in advanced.

Depending on what you're trying to do exactly, how many people are being interviewed, and your technical level of savviness, different options may appeal to you.

### Group Room method

The VDO.Ninja group room has a director role, with everyone else being a guest.

The [director](../viewers-settings/director.md) can record locally in browser, to their own disk, or they can record remotely, to the guest's computer. The highest quality recording possible will be to record to the guest's own computer directly, bypassing the Internet. This however currently requires the guest send the recording to you afterwards, which introduces a risk of failure, nor is it always feasible.

While recording the stream as the director themselves is an option, via VDO.Ninja's director control center, better performance and more reliable results can be obtained by using OBS Studio to record the stream.

When using OBS to record, you may wish to use the provided solo-links for each guest, putting each into its own OBS Studio instance, and recording each guest independently. OBS Studio can be opened multiple times, and hardware accelerated encoding is often available up to 3 streams or more. You can also consider checking out [https://obsproject.com/forum/resources/source-record.1285](https://obsproject.com/forum/resources/source-record.1285/), which is a plugin for OBS that lets you record multiple sources at a time with one OBS instance.

If using OBS to record, configure OBS to record at a high bitrate, let's say 20,000-kbps, at perhaps 1920x1080 resolution. For each OBS browser source, which contains the solo-links, will we ensure they are 1920x1080 resolution also, and we will append [`&videobitrate=12000`](../advanced-settings/video-bitrate-parameters/bitrate.md)[`&audiobitrate=160`](../advanced-settings/view-parameters/audiobitrate.md) to each view link.

You can speak to the guest via the director's control center, which will provide echo cancellation for the director's mic, and this provides the easiest setup and operation. If you want even more control over settings and optimizations though, but don't want a director role, you may way to try the next method.

### Manual push/view links method

In this mode, there is no group room, and all guest stream IDs need to be manually specified. You can typically get excellent 1080p recording quality though with the following parameters:\
\
**Guest link:** [`https://vdo.ninja/?push=GUEST_ID&quality=0&proaudio&view=HOST_ID&vb=200&ab=16`](https://vdo.ninja/?push=GUEST_ID\&quality=0\&proaudio\&view=HOST_ID\&vb=200\&ab=16)

**Host link:** [`https://vdo.ninja/?push=HOST_ID&view=GUEST_ID&vb=50&ab=16`](https://vdo.ninja/?push=HOST_ID\&view=GUEST_ID\&vb=50\&ab=16)

**OBS link\*:** [`https://vdo.ninja/?view=GUEST_ID&vb=12000&ab=128&scale=100`](https://vdo.ninja/?view=GUEST_ID\&vb=12000\&ab=128\&scale=100) \
\
&#xNAN;_\* Note the OBS Browser source should be set to a width of 1920 and a height of 1080._

The idea here is both you and the guest can talk to each other in the browser, at relatively very low quality, while in OBS you are capturing a very high quality version of just the guest. I'd imagine you can record the host locally in OBS, without needing VDO.Ninja in most cases.

I am also assuming the guest is wearing headphones; if not, you may need to remove [`&proaudio`](../advanced-settings/audio-parameters/and-proaudio.md) from their invite link. Removing it will lower the audio quality, but with it added you will not have echo cancellation enabled.

You can improve the quality a small bit further with some added complexity, by having the host use OBS as the video/audio monitor when speaking to the guest, rather than pulling any audio/video in via a browser window. You can also consider using the [Electron Capture app](../steves-helper-apps/electron-capture.md), instead of an OBS browser source, which will let you share one guest video stream with several apps via window-capture.

For the highest quality, you'll want to record the guest at their native resolution, so if each guest is 1080p resolution, you can capture 4 guests in OBS if OBS is recording at 4K resolution, or you can record each guest as their own independent video. Common options here could be to have multiple OBS instances being open, or by using the source-record plugin for OBS: [https://obsproject.com/forum/resources/source-record.1285](https://obsproject.com/forum/resources/source-record.1285/).

### Added sharpening

If doing screen shares, or overlays, adding a bit of sharpening as an OBS video effects filter can also help the recording look better. Sharpening will make lines and fine details, like hair, pop out a bit more. This is especially helpful for text, which is usually a bit soft in video otherwise.

### AV1 video codec

The relatively new AV1 video codec offers better colors, better compression, and often better frame rates than other codecs. If your guest supports it, with a computer that won't overheat because of it, it might be worth trying.

Add [`&codec=av1`](../advanced-settings/view-parameters/codec.md#av1) to the solo- or view-link of the guest you are recording, to get the system to prefer using it instead.

### Packet loss and connection quality

The biggest impact and limitation is normally the connection itself; please sure that both sides have excellent high-quality connections. Bad connections will ruin a stream.

Sometimes using [`&relay`](../general-settings/and-relay.md) or [`&meshcast`](../newly-added-parameters/and-meshcast.md) can help with certain bad connections, in rare cases at least. Meshcast can be used on the sender's side, while `&relay` can be used on either/both side. Normally just avoiding WiFi can resolve many such packet loss issues though.&#x20;

If the guest is on a mobile device, consider using a USB (lightning) to Ethernet adapter for that phone, to connect it to the Internet router directly, rather than using WiFi. If that isn't an option, bonded cellular connections may be an option for some users as well.

[packet-loss.md](../common-errors-and-known-issues/packet-loss.md "mention")

{% embed url="https://www.youtube.com/watch?v=je2ljlvLzlY" %}

If packet loss is a still serious issue, then there is a feature in VDO.Ninja to let you record the video directly on the guest's computer, remotely, bypassing the Internet during the recording itself. It's experimental though, so it might only be useful as a backup, but when it works, it's fantastic! The [`&record`](../advanced-settings/recording-parameters/and-record.md) option, added to the guest's link, will let them control the recording, if there is no director present to start/stop the recording.

### Smartphone / computer overheating

If your phone is getting warm, putting a metal heatsink on the backside of the phone directly can help keep it from thermal throttling. You can also try changing codecs, to see if perhaps there is a better option.

As for laptops, ensure they are plugged in and are not overheating.

### Update your smartphone or change browsers

Some smartphones will have limited functionality if using an older version of the operating system. This is especially true of iOS devices, where iOS 16 has several core improvements over iOS 16, for example.

Certain browsers, such as Firefox, should also be avoided in most cases. Chromium-based browsers will offer better control over video bitrates, with more options and features to use.

### As per audio

Avoid Bluetooth or mobile devices for audio sources.

Also refer to [`&audiobitrate`](../advanced-settings/view-parameters/audiobitrate.md) or [`&proaudio`](../advanced-settings/audio-parameters/and-proaudio.md) for options to improve audio bitrate.




# Options to record streams

There are several ways to record, with more ways coming. I'll list some of the ways here, although they may not be exactly what you had in mind. Regardless of which method you prefer, having a backup recording going is always advisable.

### Local / Remote Recording in VDO.Ninja

The VDO.Ninja room director has the option to record streams locally and remotely.

You can also add \&record to guest invite URL to introduce a recording button, for that publisher to start/stop their own local recording. Local recordings of this type are often of high quality.

You can also right-click and record any video within VDO.Ninja.

Depending on the type of video, and whether its local or remote, recording the video with this method may use up extra resources from the publisher's computer, including CPU and bandwidth.

Another issue is the format saved is WebM, which sometimes will need post-processing to make it compatible with many popular video editors. If the browser crashes, that also may cause the video recording to become lost, so it might not be the most reliable option.

That said, this is an easy option and available for free within VDO.Ninja.

Given thesmall chance the browser will fail with recording, you can use features like `&splitrecording` to automatically segment the video as its being recorded, saving perhaps 5-minute portions of the video at a time. You will need to concatenate the video chunks together however afterwards, but helps reduce the likelihood of the entire recording being lost due to a system crash.

### Using OBS to record; or multiple OBS

You can open multiple OBS Studios. Each OBS can record a full-window video if needed. This is useful if doing an interview with someone, and you intend to post process edit it.

OBS has advanced hardware accelerated encoding options, and so this is good option if wanting to have a few high-resolution recordings taking place, as you can offload the encoding to the GPU if available.

If adding `&channel=8` to your view/scene link in OBS, and enabling 7.1-channel audio in OBS, you can have a specific guest be recorded to a specific audio channel in your OBS recording. This is a bit finicky, given how 7.1-channel audio is hard to downmix into a proper stereo output, but for recording a podcast it might be a great option still to help in post-production ease. As of VDO.Ninja v26, the director has options to control these channels dynamically, under a guest's scene-settings menu.

<figure><figcaption><p>Multiple channels available for recording; one per guest, for example.</p></figcaption></figure>

### OBS Source Record plugin

For OBS, there is a source-record plugin that allows you to record each Guest in OBS as its own dedicated video source. By pulling in a single high quality ISO (solo) feed per guest into OBS, and mixing videos using OBS, you can get high quality footage for post-production efforts. [https://obsproject.com/forum/resources/source-record.1285/](https://obsproject.com/forum/resources/source-record.1285/)

This is nice because you can have one OBS Studio open, and that's it. The downside is, you won't be able to use the VDO.Ninja auto-mixer if using solo-links instead.

### Electron Capture et al

[Electron Capture](../steves-helper-apps/electron-capture.md) ([https://github.com/steveseguin/electroncapture](https://github.com/steveseguin/electroncapture)) or [Vingester.app](https://vingester.app/) are similar concepts to source-recording, but instead you can capture in an application that isn't OBS. From there you window capture or NDI capture those streams locally into OBS, or/and other applications at the same time. These options do add complexity, but I sometimes will use these approaches, especially if I want to interact with the stream or pin it on top of other apps.

If interested in Vingester, as it has NDI output options, consider downloading it from here:\
[https://github.com/steveseguin/vingester](https://github.com/steveseguin/vingester) , as the official repo for it is no longer maintained, and has an audio bug in it. Vingester does use quite a bit of CPU.

### Chunked mode

If using the [`&chunked`](../newly-added-parameters/and-chunked.md) mode of [VDO.Ninja](https://vdo.ninja/), a video stream is encoded once, and that is sent to all viewers and even the local/remote recordings. This is experimental and still pretty high CPU, due to the high quality of the stream being shared, but it might be lower CPU than trying to do two high quality encodings.

There is no server-side support for chunked mode at the moment, but I will continue to improve it and work on it as requests come in.

### Recording via WHIP/WHEP service

You can use a WHIP/WHEP services to relay video via a server. In this case, the server itself can make a copy of the stream; the same stream everyone else in the room will see. There's also [SVC scalability support](../advanced-settings/whip-parameters/and-svc.md), so if your server supports that, you can push high-bitrates. ([https://vdo.ninja/alpha/whip](https://vdo.ninja/alpha/whip) for some common tooling)

You could in theory record to Twitch or paid WebRTC service via their WHIP ingest, but if you deploy your own SFU server, such as MediaMTX, you can configure it to record via WHIP as well. There's even a dedicated option for configuring MediaMTX with VDO.NInja: `&mediamtx` (v26 of VDO.Ninja)

### Recording to Google Drive / Dropbox

I have been working when I can on a way to auto-sync the local/remote recordings to Google Drive, Dropbox and other cloud providers. The code is there, but it still is a bit buggy and the user interface is lacking. This will record a local copy to disk, but automatically stream that local recording to the cloud as well; before or during the stream.

If there is of great interest to users, please let me know on Discord in the Feature Request channel how you'd like it to work, which provider, etc. I'm trying to figure out where best to invest my time on that feature, and with so little time, unless there's active interest, I let some tasks idle.

\*update: Google Drive recording has a dedicated button in the Director's control room, which will let the director have remote guests upload their video to their Google Drive account automatically.

### Headless recording

This is a bit like having a headless version of OBS in the cloud, where it's configured to take a [VDO.Ninja](https://vdo.ninja/) browser link and publish it using FFmpeg to RTMP. Works with DigitalOcean or even an Orange pi.

[https://github.com/steveseguin/browser-to-rtmp-docker](https://github.com/steveseguin/browser-to-rtmp-docker)

You can very easily configure the FFmpeg script to save to MP4/MKV format though, so if you were wanting to record the guest in the cloud, this is an option. It still will put a load on the guest, as they are encoding a high quality stream that won't be used live really, but if you want to do isolated guest recordings, and don't have the local CPU for it, this might help.

### [Raspberry.Ninja](options-to-record-streams.md#raspberry.ninja)

[Raspberry.Ninja](https://raspberry.ninja/) is my project for Linux systems (and Windows WSL also), which lets you both publish and record Raspberry Ninja streams, without a browser at all.

While it's mainly used for publishing video to [VDO.Ninja](https://vdo.ninja/) using the hardware encoder in small embedded computers, like the Raspberry Pi, it can also record video streams to disk, as perfect copies. No transcoding is done.

If you are enterprising, you can have [Raspberry.Ninja](https://raspberry.ninja/) record the incoming guest streams to disk without transcoding, and then transcode them, before window-sharing them or publishing them to NDI. NDI output support is available with Raspberry.Ninja, however it does require transcoding currently.&#x20;

### Recording an entire window/scene to disk as a mixed output

If you want to record more than a single guest, but rather an entire scene, using URL parameters you can achieve this. We are essentially doing a screen share of the output window, and recording that.\
\
**Record entire scene to disk:** [https://vdo.ninja/?scene=0\&layout\&remote\&clean\&chroma=000\&ssar=landscape\&nosettings\&prefercurrenttab\&selfbrowsersurface=include\&displaysurface=browser\&np\&nopush\&publish\&record\&screenshareaspectratio=1.7777777777777777\&locked=1.7777777777777777\&room=ROOMNAME](https://vdo.ninja/?scene=0\&layout\&remote\&clean\&chroma=000\&ssar=landscape\&nosettings\&prefercurrenttab\&selfbrowsersurface=include\&displaysurface=browser\&np\&nopush\&publish\&record\&screenshareaspectratio=1.7777777777777777\&locked=1.7777777777777777\&room=ROOMNAME)\
**Publish entire scene to a WHIP endpoint:**\
[https://vdo.ninja/?scene=0\&layout\&remote\&clean\&chroma=000\&ssar=landscape\&nosettings\&prefercurrenttab\&selfbrowsersurface=include\&displaysurface=browser\&np\&nopush\&publish\&whippush\&screenshareaspectratio=1.7777777777777777\&locked=1.7777777777777777\&room=surprisethinP](https://vdo.ninja/?scene=0\&layout\&remote\&clean\&chroma=000\&ssar=landscape\&nosettings\&prefercurrenttab\&selfbrowsersurface=include\&displaysurface=browser\&np\&nopush\&publish\&whippush\&screenshareaspectratio=1.7777777777777777\&locked=1.7777777777777777\&room=surprisethinP)

<figure><figcaption></figcaption></figure>

### Contact me for more discussion / updates

If you want to follow up with me on some of these options, please contact me on Discord at [https://discord.vdo.ninja](https://discord.vdo.ninja/).

As well, things change quickly with VDO.Ninja; this post may already be out of date by the time you read it. Feel free to ask for updates.




---
description: >-
  WebRTC/P2P connections may not work always in OBS Studio, perhaps due to
  firewalls.
---

# Enabling WebRTC Sources in OBS

This guide will help you troubleshoot and resolve issues with WebRTC/P2P-based browser sources in OBS (Open Broadcaster Software). We'll cover several methods that can ensure these sources work properly, assuming the sources work fine in a normal browser already, and just fail within OBS.

Often the issues with VDO.Ninja or Social Stream Ninja not appearing in OBS are not firewall related, but rather glitches in the matrix, so we'll cover a few common solutions there also.

### Method 1: Adding OBS to Windows Firewall

1. Open the Windows Control Panel.
2. Navigate to "System and Security" > "Windows Defender Firewall".
3. Click on "Allow an app or feature through Windows Defender Firewall" on the left side.
4. Click the "Change settings" button.
5. Click "Allow another app..."
6. Browse to the OBS installation directory (usually `C:\Program Files\obs-studio\bin\64bit`) and select `obs64.exe`.
7. Click "Add" and ensure both "Private" and "Public" checkboxes are ticked for OBS.
8. Click "OK" to save the changes.

### Method 2: Running OBS as Administrator

1. Right-click on the OBS shortcut or executable.
2. Select "Run as administrator".
3. If prompted, click "Yes" to allow the app to make changes.

To always run OBS as administrator:

1. Right-click on the OBS shortcut or executable.
2. Select "Properties".
3. Go to the "Compatibility" tab.
4. Check the box next to "Run this program as an administrator".
5. Click "Apply" and then "OK".

### Method 3: Use Electron Capture app instead

1. You can use the [Electron Capture app](https://docs.vdo.ninja/steves-helper-apps/electron-capture) instead of the OBS Browser source
2. Window capture the Electron Capture output into OBS instead.
3. You can window-capture the audio via OBS or with a virtual audio cable.

### Method 4: Disable hardware acceleration and check settings

1. Try to disable hardware acceleration for browser sources in the OBS settings

You may need to scroll down in the browser source settings to find the follow.

1. Make sure "Shutdown source when not visible" is NOT checked in the browser source settings.
2. Make sure "Refresh browser when scene becomes active" is NOT checked in the browser source settings.
3. Clear the browser cache in the OBS Browser source using the "Refresh cache of current page" button.

### Method 5: Allowing OBS Through Third-Party Firewall Software

If you're using third-party firewall software:

1. Open your firewall software's settings.
2. Look for an option to allow applications through the firewall.
3. Add OBS (`obs64.exe`) to the list of allowed applications.
4. Ensure OBS has permissions for both incoming and outgoing connections.

### Method 6: Disabling Web Security to enable local IP sharing

OBS browser sources seems to hide local IPs by default, which may cause Internet usage via forced TURN-server usage, rather than direct peer-to-peer. Not ideal!

If you start OBS with the following command-line arguments, peer to peer connectivity issues may be resolved. To quickly test if this is a potential issue, add `&turn=0` to the VDO.Ninja view URL added to OBS, and see if you can establish a connection. \
\
While it's not going to impact most users, it may be a problem for some. If it is a problem, you can just ignore it, use the [ElectronCapture.app](../steves-helper-apps/electron-capture.md) instead, or if you don't mind lowering the security browser inside OBS, you can use the following command-line to start OBS:

`obs64.exe --disable-web-security --allow-running-insecure-content --ignore-certificate-errors --use-fake-ui-for-media-stream`

To further help diagnose the above issue, and to compare results across different browsers, please see: [https://vdo.ninja/stun](https://vdo.ninja/stun)

### Troubleshooting Tips

* Clear browser cache: As already mentioned, in OBS, right-click on the browser source, select "Properties", then click "Refresh cache of current page".
* Test in different browsers: If a WebRTC source works in Chrome but not in OBS, try using a different browser like Firefox or Edge to isolate the issue.
* Check network settings: Ensure your network allows WebRTC connections and that no VPN or proxy is interfering.
* Disable hardware acceleration: As already mentioned, in OBS settings, go to "Advanced" and uncheck "Enable browser source hardware acceleration".
* Update OBS Studio: Certain versions of OBS may have issues with browser sources. Fully uninstall OBS Studio and then update with a recent stable version.
* Check your links: Sometimes you have an old link in OBS, one that might contain an invalid password, stream ID, or session value. Delete the old browser source, make a new one, and use a freshly obtained link to ensure you haven't made a simple oversight.

If you're still experiencing issues after trying these methods, consider reaching out to the OBS community forums or support channels for further assistance.




---
description: How to control the video bitrate inside of a room
---

# Video bitrate in rooms

This guide will show you how to control and set up the bitrate in rooms as a director and as a guest.

## Default settings

Every guest is viewing video streams in a room with a combined bitrate of 500-kbps. If there is only one video stream, the guest will view the video on 500-kbps. Two video streams: 250-kbps per video.

## Director

As a director of a room you can control the total room bitrate dynamically.

<div align="left">

<figure><figcaption><p>Open the room settings via this button as a director</p></figcaption></figure>

</div>

<div align="left">

<figure><figcaption><p>The default is (as explained before) 500-kbps. You can increase it op to 4000-kbps.</p></figcaption></figure>

</div>

You can control the total room bitrate also with a URL parameter: [`&totalroombitrate=6000`](../advanced-settings/video-bitrate-parameters/totalroombitrate.md)

<div align="left">

<figure><figcaption><p>Default is 6000-kbps now with <code>&#x26;totalroombitrate=6000</code></p></figcaption></figure>

</div>

The default setting for the room is now 6000-kbps. You can decrease it dynamically though if the guests have any problems.

## Guest

If you add [`&roombitrate=2000`](../advanced-settings/video-bitrate-parameters/roombitrate.md) to the guest's link all the other guests can view the video of the guest with a bitrate of 2000-kbps. So three other guests watching the video stream of the guest -> 6000-kbps outgoing bitrate. [`&roombitrate`](../advanced-settings/video-bitrate-parameters/roombitrate.md) limits any guest viewer in the group chat room from pulling the video stream at more than the specified bitrate value.

You can also use [`&totalroombitrate`](../advanced-settings/video-bitrate-parameters/totalroombitrate.md) on the guest's URL if you want to have different settings for each guest. So adding `&totalroombitrate=4000` to a guest's URL, the guest can view all video streams in the room with a combined bitrate of 4000-kbps.

If you use [`&controlroombitrate`](../advanced-settings/video-bitrate-parameters/and-controlroombitrate.md) on the guest's URL, the guest can change the total room bitrate dynamically via a slider. If you add `&controlroombitrate&totalroombitrate=4000` to the guest's URL the guest can change the bitrate between 0 and 4000-kbps. It doesn't affect what other guest's are viewing.

.png>) (1) (1) (1) (2) (1).png>)

## Examples

[https://vdo.ninja/?director=TestRoomName\&push=directorStreamID\&broadcast\&totalroombitrate=5000](https://vdo.ninja/?director=TestRoomName\&push=directorStreamID\&broadcast\&totalroombitrate=5000)\
When adding `&broadcast&totalroombitrate=5000` to the director's URL the guests can only see the video of the director with a bitrate of 5000-kbps. So they get pretty good video quality. If you have three guests in the room the outgoing bitrate fot the director is 15000-kbps, so it's pretty high.

If you want a guest to appear in scenes (for example in OBS) but you don't want other guests to see their video stream you can add `&roombitrate=0` to the guest's URL. [`&roombitrate`](../advanced-settings/video-bitrate-parameters/roombitrate.md) only affects the bitrate in the room, not in scenes.

Adding [`&maxbandwidth=80`](../advanced-settings/video-bitrate-parameters/and-maxbandwidth.md) to the guest's URL will allow to them to put 80 % of their available bandwidth into the video stream. This is useful for high quality gaming streams for example.

## Scenes

For scenes in OBS or other softwares ([`&scene`](../advanced-settings/view-parameters/scene.md) or [`&solo`](../advanced-settings/mixer-scene-parameters/and-solo.md)) use [`&videobitrate`](../advanced-settings/video-bitrate-parameters/bitrate.md) to specify the bitrate per video stream or [`&totalscenebitrate`](../advanced-settings/video-bitrate-parameters/and-totalscenebitrate.md) to get a combined bitrate for all videos in the scene.

3 guests in a scene -> `&videobitrate=3000`\
The bitrate of each guest will be 3000-kbps.

3 guests in a scene -> `&totalscenebitrate=3000`\
The bitrate of each guest will be 1000-kbps.

## Meshcast

If you are using [`&meshcast`](../newly-added-parameters/and-meshcast.md) on the director's or guest's URL remember that you control the bitrate via [`&meshcastbitrate`](../meshcast-settings/and-meshcastbitrate.md) on the sender's side.

## More Parameters

There are more parameters to control the bitrate. You can find them here:

{% content-ref url="video-bitrate-for-push-view-links.md" %}
[video-bitrate-for-push-view-links.md](video-bitrate-for-push-view-links.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/video-bitrate-parameters/" %}
[video-bitrate-parameters](../advanced-settings/video-bitrate-parameters/)
{% endcontent-ref %}




---
description: How to control video bitrates for basic push/view links
---

# Video bitrate for push/view links

## The default settings

The default video bitrate for simple push/view links is 2500-kbps.

[https://vdo.ninja/?push=streamid](https://vdo.ninja/?push=streamid)\
[https://vdo.ninja/?view=streamid](https://vdo.ninja/?view=streamid)\
\
By default, both outgoing and incoming video bitrates are set at 2500-kbps.  This default setting and parameters are different if using [Rooms ](../getting-started/rooms/)and explained in detail [here](video-bitrate-in-rooms.md).

There are five parameters we will take a look at:

1. [\&outboundvideobitrate (\&ovb)](../advanced-settings/video-bitrate-parameters/and-outboundvideobitrate.md) -> push side
2. [\&maxvideobitrate (\&mvb)](../advanced-settings/video-bitrate-parameters/and-maxvideobitrate.md) -> push side
3. [\&limittotalbitrate (\&ltb)](../advanced-settings/video-bitrate-parameters/limittotalbitrate.md) -> push side
4. [\&videobitrate (\&vb)](../advanced-settings/video-bitrate-parameters/bitrate.md) -> view side
5. [\&totalscenebitrate (\&tsb)](../advanced-settings/video-bitrate-parameters/and-totalscenebitrate.md) -> view side

## On the source side ([\&push](../source-settings/push.md))

### The push link sets the target and maximum outgoing video bitrate

[`&outboundvideobitrate (&ovb)`](../advanced-settings/video-bitrate-parameters/and-outboundvideobitrate.md)\
Sets the target and maximum outgoing video bitrate on the source side.

[https://vdo.ninja/?push=streamid\&ovb=4000](https://vdo.ninja/?push=streamid\&ovb=4000)\
[https://vdo.ninja/?view=streamid](https://vdo.ninja/?view=streamid)\
\
The push link sets the outgoing and incoming video bitrate to 4000-kbps. The view link doesn't need an additional parameter as its bitrate is set at 4000-kbps because the push link is using `&ovb.`

### The push link sets the video bitrate per stream out

[`&maxvideobitrate (&mvb)`](../advanced-settings/video-bitrate-parameters/and-maxvideobitrate.md)\
`&mvb` is similar to `&ovb` but it sets the target and maximum bitrate per stream out.

[https://vdo.ninja/?push=streamid\&mvb=1000](https://vdo.ninja/?push=streamid\&mvb=1000)\
[https://vdo.ninja/?view=streamid](https://vdo.ninja/?view=streamid)\
\
Every view link has a video bitrate of 1000-kbps.

### The push link limits the video bitrate to a maximum defined value

[`&limittotalbitrate (&ltb)`](../advanced-settings/video-bitrate-parameters/limittotalbitrate.md)\
Limits the total outbound video bitrate to a defined value.

[https://vdo.ninja/?push=streamid\&ltb=5000](https://vdo.ninja/?push=streamid\&ltb=5000)\
[https://vdo.ninja/?view=streamid](https://vdo.ninja/?view=streamid)\
\
The incoming video bitrate will still default to around 2500-kbps but permits the viewer to increase it on their end with `&ltb` telling the push link to not get higher than 5000-kbps total outgoing bitrate.

## On the viewer side ([\&view](../advanced-settings/view-parameters/view.md))

### The view link sets the video bitrate per stream in

[`&videobitrate (&vb)`](../advanced-settings/video-bitrate-parameters/bitrate.md)\
The view link is setting the target and maximum video bitrate per incoming stream.

[https://vdo.ninja/?push=streamid](https://vdo.ninja/?push=streamid)\
[https://vdo.ninja/?view=streamid\&vb=2000](https://vdo.ninja/?view=streamid\&vb=2000)\
\
The view link is setting the bitrate per incoming stream (in this case 2000-kbps). So if you have a view link with three incoming video feeds: `&view=stream1,stream2,stream3` - every source is pushing 2000-kbps as `&vb=2000` and the view link has a combined bitrate of 6000-kbps.

### The view link sets the total video bitrate for all incoming streams combined

[`&totalscenebitrate (&tsb)`](../advanced-settings/video-bitrate-parameters/and-totalscenebitrate.md)\
This is similar to [`&vb`](video-bitrate-for-push-view-links.md#the-view-link-sets-the-video-bitrate-per-stream-in) but it sets the target and maximum bitrate for all incoming streams combined.

[https://vdo.ninja/?push=streamid](https://vdo.ninja/?push=streamid)\
[https://vdo.ninja/?view=streamid\&tsb=3000](https://vdo.ninja/?view=streamid\&tsb=3000)\
\
So if you have a view link with three incoming video feeds: `&view=stream1,stream2,stream3` - every source is pushing 1000-kbps as `&tsb=3000`.&#x20;

## Mixing the parameters

As doing some testing there were these results:

All the three push parameters are always limiting the maximum. So if you set one of the three parameters to a value, the outgoing video bitrate will never be higher than you set it.

`&tsb` also always limits the bitrate on the viewer side, whereas `&vb` is overwritten by `&ovb` and `&mvb`.

* `&ovb` is overwriting `&vb`
* `&mvb` is overwriting `&vb`
* `&tsb` is stronger than `&ovb`

## Related

{% content-ref url="../advanced-settings/video-bitrate-parameters/" %}
[video-bitrate-parameters](../advanced-settings/video-bitrate-parameters/)
{% endcontent-ref %}

{% content-ref url="video-bitrate-in-rooms.md" %}
[video-bitrate-in-rooms.md](video-bitrate-in-rooms.md)
{% endcontent-ref %}




---
description: You can host a VDO.Ninja media stream on a website, via the IFRAME API
---

# How to use VDO.Ninja on a website

### Basic embedding

Embedding VDO.NInja into a website should be pretty simple; we're just using the IFRAME element and setting the source to the VDO.Ninja URL we wish to load

```
<!DOCTYPE html>
<html>
<head>
    <title>VDO.Ninja Embedded Iframe</title>
</head>
<body>
    <iframe 
        src="https://vdo.ninja/?view=JkYwyxy" 
        allow="camera; microphone; autoplay" 
        width="640" 
        height="360">
    </iframe>
</body>
</html>
```

You may want to add or remove certain permissions, such as geolocation. Please note that while enabling auto-play is an IFRAME option, unless the parent window has already had a user-gesture interaction, the video inside VDO.Ninja will not autoplay; at least not with audio. Auto-playing of audio is controlled by the browser to limit annoying ads from auto-playing also; overriding this isn't really feasible.

### Adding some security for public deployments

If wanting to use this page for public use, I'd probably want to secure things a bit more.  Such as using the `&audience` parameter, which makes it so the viewer can't just publish to your stream ID when you stop streaming yourself. \
\
The audience parameter is available with VDO.Ninja v25.2 and newer.

1. An example push link is this: [https://vdo.ninja/alpha/?audience=12345abcPublishingToken\&push=JkYwyxy](https://vdo.ninja/alpha/?audience=12345abcPublishingToken\&push=JkYwyxy)
2. The view link you'd be provided woudl be something then like this: [https://vdo.ninja/alpha/?audience=HrDrNy3jiA50QzlU\&view=JkYwyxy](../getting-started/vdo.ninja-basics.md)

<figure><figcaption><p>Example of the provided audience key to use</p></figcaption></figure>

### Advanced IFRAME API options

There's a sandbox that lets you play with the IFRAME API here: [https://vdo.ninja/iframe](https://vdo.ninja/iframe) , but it might be more complex than you need.\
\
More about the[ ](how-to-use-vdo.ninja-on-a-website.md#advanced-iframe-api-options)[IFRAME API here.](https://docs.vdo.ninja/guides/iframe-api-documentation)

### Transparency

Setting the `allowtransparency` attribute on the IFrame to `true` will allow for the contents to be transparent. You can then make VDO.Ninja transparent by adding `&transparent` to the URL, which sets the page's background to `rgba(0,0,0,0)`.&#x20;

[https://vdo.ninja/iframe ](https://vdo.ninja/iframe)can demonstrate this by opening [https://vdo.ninja/?transparent](https://vdo.ninja/?transparent) with it.

### Accessing media frames directly for use in a video element

This is a more complex request, but it's possible.\
\
https://versus.cam makes use of the `&sendframes` parameter to send raw video frames to the parent IFRAME, for use in a video element. This requires the VDO.Ninja deployment and the parent frame to share the same site origins, however depending on how you want the domains to appear, this could require some fancy request header manipulation, etc.\
\
Another easier option is to use the IFRAME API to make a request using `getVideoFrame`, such as: `{getVideoFrame:true, streamID:"abc123xyc"}`.  This will return a video frame, a PNG image of the current video stream with stream ID `abc123xyc`, which allows for a crude video stream. If perhaps a guest's browser doesn't support the `&sendframes` option, this could be a fallback.\
\
Anyways, these are advanced and complex options of loading a video element with a VDO.Ninja source. Normally just using the IFRAME as the playback window, and interacting with it via the IFRAME API is suggested.\
\
If you really want another way to access VDO.Ninja streams,  you may need to consider using a server to convert from VDO.Ninja into an HLS stream, however that both carries cost and incrasese the latency of the stream dramatically.




# How to capture without browser sources

### Vingester.app

Vingester.app can let you do VDO.Ninja to NDI. It uses a browser window and can be used to export a copy of the window to FFmpeg, NDI, or make the source available for window-capture. It is a bit heavy on CPU usage, but on a dedicated computer, it works quite well for hosting a few NDI streams.

[https://github.com/steveseguin/vingester](https://github.com/steveseguin/vingester)

### Electron Capture

Electron Capture is the officially supported tool for doing window capture of VDO.Ninja. It's very light weight and has quite a few command line options to batch start several windows at a time, along with support for hotkeys and other nifty VDO.Ninja specific tasks.

[https://github.com/steveseguin/electroncapture](https://github.com/steveseguin/electroncapture)

If using Electron Capture on Windows, you can currently do `Win+Tab` to switch between virtual desktops --- and sometimes this lets you can put all the VDO.Ninja windows in one desktop, and have a second desktop for vMix etc. It works with some windows setups, and in others, might just show black videos when trying to capture.

### Virtual Cameras and Virtual Audio devices

While this approach will still use a browser source, you can ingest VDO.Ninja into a browser source for an app like OBS Studio, or even something paid like ManyCam, and then export the captured video stream via their Virtual Camera features into another app that supports webcam / video input devices.

Audio can be exported directly via VDO.Ninja into a virtual audio device, either their the [`&audiooutput`](../advanced-settings/setup-parameters/and-audiooutput.md) feature, or from even the right-click context menu, where you can specify which audio output device an audio stream should be played into it. If a virtual audio cable is selected as the output destination, you can then bring that virtual audio cable into any audio application as a raw audio stream, as if it was a microphone or line-in source.

### WHEP / WHIP

There's also WHEP/WHIP output from VDO.Ninja, which is relatively a new technology/feature, and so not quite a replacement for browser sources. That said, OBS Studio is starting to support this ingestion approach, along with GStreamer, many WebRTC CDN servers and services, and perhaps over the coming years something like vMix will adopt this new technology as well. Please provide feedback and requests if using WHIP/WHEP, so i can continue to improve it.

[https://vdo.ninja/whip](https://vdo.ninja/whip)

### Raspberry.Ninja

There's also Raspberry.Ninja ([https://github.com/steveseguin/raspberry\_ninja](https://github.com/steveseguin/raspberry\_ninja)), which supports saving raw VDO.Ninja media streams to disk. While there is a bug that's blocking things from working soothingly, can technically use it to pull raw video sources from VDO.Ninja and push to not just disk, but even NDI, system sockets/pipes, RTSP servers, and much more.

While Raspberry.Ninja need more time to cook when it comes to video ingestion, it is more capable than using WHEP/WHIP alone, and supports the data-channel transport protocol, allow for dynamic settings to be applied and meta information to be transmitted, such as tally-light indicators.

### Third parties

There are some third parties that have integrated with VDO.Ninja already, which are able to pull from VDO.Ninja and make the streams available as RTSP sources or such, but I do not have access to their code sources and so cannot promote their paid services here, but you can perhaps search around to find them online.&#x20;




---
description: >-
  System requirements for streaming using with OBS Studio, including a VDO.Ninja
  source
---

# System requirements for streaming

### Introduction

This guide outlines a general sense of system requirements and options for streaming using VDO.Ninja in combination with OBS Studio, targeting multiple platforms such as Kick, Twitch, and YouTube. \
\
System requirements will vary from user to user, and use case to use case, so there is no official minimum system requirement. Even a Raspberry Pi may be sufficient for some users, while others may need to rethink their strategy completely if their idea is outside the bounds of current physics.

### System Requirements for the average streamer

#### CPU

* Minimum suggested: Intel Core i5-8400 or AMD Ryzen 5 2600
* Recommended: Intel Core i7-12700K or AMD Ryzen 7 5800X
* High-end for flexibility: Intel Core i9-14900K or AMD Ryzen 9 7950X

Note: More powerful CPUs will handle multiple streams and VDO.Ninja cameras better. Each additional VDO.Ninja published stream will require more CPU power due to WebRTC's CPU-intensive nature. If using a GPU to accelerate the video encoding, a quad-core computer may also be minimally sufficient.

**Cooling**

* Your computer should have an active cooling solution, especially the CPU
* If using a laptop or mini PC, it should have at least an internal fan to keep the system cool

#### GPU

* Minimum: NVIDIA GTX 1660 or AMD RX 570
* Recommended: NVIDIA RTX 3060 or AMD RX 6600 XT
* High-end: NVIDIA RTX 4090 or AMD RX 7900 XTX

Note:

* Newer NVIDIA GPUs (RTX 30 and 40 series) offer better NVENC acceleration.
* RTX 40 series and some high-end 30 series cards support AV1 encoding.
* AMD GPUs from RX 6000 series onwards offer improved encoding capabilities.

#### RAM

* Minimum: 8GB
* Recommended: 16GB
* High-end: 32GB or more

#### Storage

* SSD recommended for faster load times and smoother performance

#### Internet Connection

* Upload speed: At least 5 Mbps per 720p stream at 30 fps
* Recommended: 10+ Mbps for single 1080p stream at 60 fps
* Multi-broadcast or group video: 30+ Mbps
* Wired Ethernet recommended for all computers

VDO.Ninja connections made over LAN do not use Internet normally. Also, VDO.Ninja will adapt to the Internet bandwidth available, however quality will suffer if being choked. It's best to not exceed 80% of the available upload and download bandwidth to avoid buffer bloat and other such issues.

### A basic streaming setup with VDO.Ninja as a remote camera

#### VDO.Ninja to OBS Studio

1. Use VDO.Ninja to capture your phone's camera feed.
2. Add the VDO.Ninja source to OBS Studio as a browser source.

#### OBS Studio to Streaming Platforms

1. Set up your scene in OBS Studio, incorporating the VDO.Ninja feed and any other sources.
2. Configure output settings based on your hardware capabilities and target platforms.

### Hardware Encoding Options

* NVIDIA NVENC: Available on GTX 10 series and newer
* AMD AMF: Available on RX 400 series and newer
* Intel Quick Sync: Available on most Intel CPUs with integrated graphics

### Multi-Platform Streaming Options

#### Local Solutions

1. OBS Studio with Multiple Outputs:
   * Use the "Multiple RTMP Outputs" plugin for OBS Studio.
   * Configure separate outputs for each platform (Kick, Twitch, YouTube).
2. Restream.io OBS Plugin:
   * Install the Restream.io plugin for OBS Studio.
   * Configure your Restream account with your target platforms.

#### Cloud-Hosted Solutions

1. Restream.io:
   * Stream to Restream's servers, which then distribute to multiple platforms.
   * Reduces local hardware requirements but may introduce slight delay.
2. Castr.io:
   * Another cloud-based multi-streaming service.
   * Offers low-latency options and analytics.

### Quality Considerations

* Start with 720p at 30 fps for a balance of quality and performance.
* Increase to 1080p at 60 fps if your hardware and internet connection can handle it.
* Consider lowering the quality if streaming to multiple platforms simultaneously from a local setup.

### Optimizing Performance

1. Use hardware encoding (NVENC, AMF, or QuickSync) when available.
2. Close unnecessary background applications.
3. Monitor CPU and GPU usage during streams to identify bottlenecks.
4. Consider a dedicated streaming PC for high-quality, multi-platform setups.

### Conclusion

The exact requirements will depend on your specific use case, desired quality, and number of platforms. Start with the recommended specifications and adjust based on your experience and needs. Always test your setup thoroughly before going live.




---
description: Choosing the Right Microphone for Your Live Stream
---

# Picking the right microphone

Audio quality is crucial for a successful live stream. A good microphone can make the difference between a professional-sounding broadcast and an amateur one. This guide will help you choose the right microphone for your live streaming needs.

### Understanding Microphone Types

There are several types of microphones suitable for live streaming:

1. **USB Microphones**: Plug-and-play, good for beginners
2. **XLR Microphones**: Professional-grade, requires an audio interface
3. **Lavalier Microphones**: Small and discreet, good for on-the-go streaming
4. **Shotgun Microphones**: Highly directional, good for noisy environments
5. **Dynamic Microphones**: Robust and good at rejecting background noise
6. **Condenser Microphones**: Sensitive and detailed, great for quiet environments

### Factors to Consider

#### 1. Pickup Pattern

* **Cardioid**: Picks up sound from the front, ideal for single-person streams
* **Bidirectional**: Picks up sound from front and back, good for interviews
* **Omnidirectional**: Picks up sound from all directions, suitable for group discussions
* **Stereo**: Captures a wide sound field, good for musical performances

#### 2. Connection Type

* **USB**: Easy to use, no additional hardware required
* **XLR**: Professional standard, requires an audio interface

#### 3. Sensitivity and Noise Rejection

* Consider how much background noise is in your streaming environment
* Dynamic mics are less sensitive and better at rejecting background noise
* Condenser mics are more sensitive and pick up more detail

#### 4. Budget

* Microphone prices range from under $50 to over $1000
* Consider your needs and how much you're willing to invest

#### 5. Portability

* If you stream from different locations, consider a portable option

### Example Microphones for Different Scenarios

#### For Beginners

1. **Samson Q2U USB/XLR Dynamic Microphone**
   * Pros: Dual USB/XLR outputs, good for beginners but also allows room for growth
   * Cons: May require closer speaking distance for optimal sound

#### For Intermediate Users

2. **Rode NT-USB Mini**
   * Pros: Compact condenser mic with built-in pop filter, high-quality sound
   * Cons: USB only, may pick up more room noise than dynamic mics
3. **Elgato Wave:3**
   * Pros: Designed for streaming, proprietary Clipguard technology prevents distortion
   * Cons: USB only, higher price point

#### For Advanced Beginners / Enthusiasts

4. **Shure MV7**
   * Pros: Hybrid USB/XLR connections, based on the professional SM7B
   * Cons: More expensive, may be overkill for casual streamers
5. **Audio-Technica AT2020USB+**
   * Pros: Studio-quality condenser mic, headphone output with volume control
   * Cons: More sensitive to room noise, requires good acoustic environment

#### For Streamers on the Go

1. **Rode Wireless GO**
   * Pros: Compact wireless system, good for mobile streaming
   * Cons: Limited range, may pick up clothing rustle
2. **Shure MV88+ Video Kit**
   * Pros: Works with smartphones, includes mini tripod
   * Cons: More expensive than basic options

### Setting Up Your Microphone

1. **Positioning**: Place the microphone 6-8 inches from your mouth, slightly off-axis to reduce plosives
2. **Use a Pop Filter**: This reduces plosive sounds ("p" and "b" sounds)
3. **Consider Acoustic Treatment**: Reduce room echoes with foam panels or blankets
4. **Test and Adjust**: Always do a test recording to check levels and sound quality

### Software Considerations

* Many streaming software (OBS, Streamlabs) allow for audio filtering
* Consider using noise suppression, a noise gate, or compression to enhance your audio

### Conclusion

Choosing the right microphone depends on your specific needs, budget, and streaming environment. Start with understanding your requirements and then explore options within your budget. Remember, even a mid-range microphone with proper setup can produce excellent results for your live stream.

Always test your audio setup before going live, and don't be afraid to make adjustments based on feedback from your audience. With the right microphone and setup, you'll be well on your way to providing a professional and enjoyable listening experience for your viewers.




---
description: Two-way low-latency audio-only transmissions
---

# How to get lowest audio latency possible

If you are a musician looking to jam out with a friend, you should be able to achieve under 40ms of latency using [VDO.Ninja](https://vdo.ninja) if both you and them have a good Internet connections. This implies being directly connected via wired Ethernet with low packet loss, rather than via Wi-Fi or cellular.&#x20;

The following link is an example of settings optimized for low-latency audio-only two-way communications. I find most of the latency with a setup like this is outside the scope of VDO.Ninja; so the sound card settings, the capture device, how far away I am from the mic / speakers, etc.

```
https://vdo.ninja/?push=MystreamID123&view=TheirStreamID123&aec=0&agc=0&denoise=0&ab=16&enhance&ptime=10&maxptime=10&novideo&noap
```

Looking at the link, let's explore:

[`&aec=0`](../source-settings/aec.md) disables the echo cancellation; this implies we will need to use headphones

[`&agc=0`](../source-settings/autogain.md) will disable auto-gain, which is preferable if streaming music

[`&denoise=0`](../source-settings/and-denoise.md) will disable the noise filter, which is ideal with music applications.

[`&ab=16`](../advanced-settings/view-parameters/audiobitrate.md) gives us a constant audio bitrate of 16-kbps. Consistency will ensure more reliable latencies, and 16-kbps is so light-weight it shouldn't be boggled down on bad connections. You can increase this value depending on the audio fidelity that you want, but higher could introduce more latency.

[`&enhance`](../advanced-settings/view-parameters/enhance.md), [`&ptime=10`](../advanced-settings/view-parameters/and-ptime.md), and [`&maxptime=10`](../advanced-settings/view-parameters/and-maxptime.md) are advanced settings, that tell the system to prioritize audio packets and limit their size to 10ms. This is the lowest we can set them using a browser, but it might be possible to go lower if using something like the Raspberry\_Ninja hardware project that VDO.Ninja has available for advanced users.

[`&novideo`](../advanced-settings/video-parameters/and-novideo.md) disables video, which can make a big impact on latency, as not streaming video will free up a lot of bandwidth, but also not force the audio to stay in sync with the video. You can send the video in a second tab/session if needed, and that way, it won't try to stay in sync.

[`&noap`](../general-settings/noaudioprocessing.md) just disables any of the advanced web-audio processing, such as compression, gain, level-meters, and panning. This will free up some milliseconds of latency in some cases,

Without much effort, you should be able to achieve 40-milliseconds of latency, or less, with this setup. Achieving between 20- to 30-ms is feasible in cases, but expectations of under 20-ms will require significantly more investment.




---
description: >-
  Syncing your USB microphone in OBS with the incoming VDO.Ninja stream is
  pretty straight forward.
---

# Syncing USB audio with VDO.Ninja -> OBS Virtual Camera

## Connecting OBS to a Virtual Audio Cable with Delay

Here's how to sync your audio in OBS Studio with an incoming VDO.Ninja video source, along with how to route the audio through a virtual audio cable into other applications.\
\
Combined with the OBS Virtual Camera output, you can use VDO.Ninja (eg: via iPhone), OBS Studio, and a USB microphone as a wireless camera in other applications.

### Step 1: Install a Virtual Audio Cable

We need a virtual audio to route the audio from OBS to our external application

There are a few free options for macOS:

* **BlackHole** (recommended): Open-source virtual audio driver
  * Download from: [https://github.com/ExistentialAudio/BlackHole](https://github.com/ExistentialAudio/BlackHole)
  * Install via Homebrew: `brew install blackhole-2ch`
* **Soundflower**: Another free option, though less actively maintained
  * Download from: [https://github.com/mattingalls/Soundflower](https://github.com/mattingalls/Soundflower)

For Windows:

**BlackHole** (recommended): Open-source virtual audio driver

* Virtual Audio Cable: Popular onationware for Windows
  * Download from [https://vb-audio.com/Cable/](https://vb-audio.com/Cable/)

### Step 2: Configure OBS Monitor Output

1. Open OBS
2. Go to **OBS Preferences** (or Settings) → **Audio**
3. Under "Advanced," find the "Monitoring Device" dropdown
4. Select your virtual audio cable (e.g., "BlackHole 2ch")
5. Click "Apply" and "OK"

### Step 3: Enable Monitoring for Your Audio Source

1. In OBS, locate your audio source in the "Audio Mixer" panel
2. Right-click the audio source → **Advanced Audio Properties**
3. Find your audio source in the list. (eg: a USB microphone.)
4. Set "Audio Monitoring" to "Monitor Only" or "Monitor and Output"
5. Click "Close"

### Step 4: Add Audio Delay (200ms)

1. In OBS, locate your audio source in the "Audio Mixer" panel
2. Right-click the audio source → **Advanced Audio Properties**
3. Find your audio source in the list
4. Look for the "Sync Offset" column
5. Enter "200 ms" in the field for your audio source
6. Click "Close"

### Step 5: Verify the Setup

Your audio should now be:

1. Captured in OBS
2. Routed through the virtual audio cable
3. Delayed by approximately 200ms, but you may need to adjust this to ensure perfect sync.
4. Available as an input source in other applications

You can select the virtual audio cable (VAB, BlackHole, or Soundflower) as an input in any other application to receive the delayed OBS audio. Works to sync your audio with an incoming VDO.Ninja video stream.

{% content-ref url="../getting-started/mobile-phone-camera-into-webcam.md" %}
[mobile-phone-camera-into-webcam.md](../getting-started/mobile-phone-camera-into-webcam.md)
{% endcontent-ref %}

{% content-ref url="use-vdo.ninja-as-a-webcam-for-google-hangouts-zoom-and-more.md" %}
[use-vdo.ninja-as-a-webcam-for-google-hangouts-zoom-and-more.md](use-vdo.ninja-as-a-webcam-for-google-hangouts-zoom-and-more.md)
{% endcontent-ref %}




---
description: How to screen-share your iPhone or iPad to VDO.Ninja
---

# How to screen share your iPhone/iPad

If on iOS, there isn't an option available to screen share from within the browser (Safari), but there are some alternatives.

One recently added way to screen share is with the VDO.Ninja native mobile app. It now supports screen sharing, however system audio capture may be missing.

{% content-ref url="../steves-helper-apps/native-mobile-app-versions.md" %}
[native-mobile-app-versions.md](../steves-helper-apps/native-mobile-app-versions.md)
{% endcontent-ref %}

\

When using the native app to screen share, be sure to select the VDO.Ninja Screen Recorder option once prompted by Apple. Then click Start Broadcast.

If you do not see the option, try scrolling down. If you don't see it still, update your iOS system version to the newest available version. Old versions may not support screen sharing, such as v15.x.

If you still cannot find it, check that the app has the correct permissions in your iOS settings, seek support, or try one of the other options below.

You can leave all other settings as default when using the [VDO.Ninja native app](../steves-helper-apps/native-mobile-app-versions.md). Once you start your broadcast, you will be provided a link at the top of the app that you can put into your browser or OBS browser source.

### Other options

Another option to screen share is to use Apple Airplay to wirelessly cast your screen to a computer, and then window capture that output.

Better than Airplay though, if you can connect your iPhone to a mac via USB, as QuickTime supports USB-connected access to an iPhone's camera. This does not require any downloads and offers a high-quality stream. Using a virtual audio device, you can even capture IOS audio with this method.

In this guide we will show you how to screen-share to VDO.Ninja using QuickTime over USB with a MacBook and an iPhone. On Windows, you may wish to use Airplay instead, leveraging one of the free Airplay clients designed for PC.

{% hint style="info" %}
Android users can use the native VDO.Ninja Android app to screen share directly to VDO.Ninja.
{% endhint %}

1. Connect your iPhone to your mac via a USB cable. You may need a USB to USB-C adapter if you do not have a lightning to USB-C adapter already.

 (1) (1).png>)

2\. Open the QuickTime Player on your Mac.

 (1) (1).png>)

3\. From the QuickTime Player menu, select File -> New Movie Recording.

 (1) (1).png>)

4\. The QuickTime Player may show your laptop's webcam initially, but you can select from the hover-over menu the option to select your iPhone's video and audio as a video source instead.

For this to work, your iPhone needs to be connected and turned on. It will not work if locked and sleeping.

 (1).png>)

5a. OPTIONAL: If you want to capture audio from your iPhone, you will need to install a virtual audio driver.

There are several choices, although the popular ones are [Loopback ](https://rogueamoeba.com/loopback/)(\$$), [Blackhole ](https://blackhole.soullabs.com/horizon/dashboard)(Free), and [VB Cable](https://vb-audio.com/Cable/) (Free). Install one of your choice; in this walk-thru we are using Blackhole.

 (1) (1).png>)

5b. OPTIONAL: If using Loopback, you will have the ability to customize the audio routing, but with Blackhole we will just output all the system's audio to the virtual audio cable. In the macOS audio settings, we just need to select the Blackhole audio device as the audio output destination.

 (1) (1).png>)

5.c. OPTIONAL: Assuming QuickTime Player is capturing audio from the iPhone, we simply just need to unmute the QuickTime Player. You won't hear audio playback, as it is being streamed to the Blackhole virtual audio device instead, but you should be able to see the audio meter bouncing around if there is audio.

.png>)

6\. We can now start streaming to VDO.Ninja; we just need to visit the site and click Share Screen. Using Chrome or another Chromium-based browser is required, such as the Electron Capture app. Safari will not work as it lacks the ability to select a window.

. (1) (1).png>) (1).png>)

7\. To start screen sharing, we will want to select "Window" as the capture source, and then select the QuickTime, which should be showing our iPhone.&#x20;

If we want to capture audio, we can also select the Blackhole virtual audio device from the Audio Sources menu in VDO.Ninja, but we can also do this after we start streaming. We can also select our local macBook microphone if we wanted.

 (1) (1) (1).png>)

8\. Once we start streaming, there is a settings menu that we can use to select audio sources. If we select the Blackhole virtual audio device (or Loopback / VB Cable), we will be sharing our audio that we are capturing from the iPhone. We can hold down the `CMD` (⌘) key while selecting audio sources to select and mix more than one audio source.

&#x20;.png>)

9\. Finally, we can add the VDO.Ninja view link to our remote OBS Studio or share it with friends.&#x20;

The view link is normally found at the top of the VDO.Ninja page, but it can be formed based on the stream ID found in the site's URL as well. You can customize it the link and add it to OBS, making sure to enable "Control audio via OBS" and ensuring the resolution matches what you want.

 (1).png>)

10\. If you want to increase the frame rate and quality of the VDO.Ninja stream, adding [`&videobitrate=6000`](../advanced-settings/video-bitrate-parameters/bitrate.md) to the URL will increase the quality by more than double. If you're looking to stream a game, you may want to increase this value even higher, although the default bitrate is more than enough for text and basic screen sharing.

Please see the rest of the documentation for more details on customizing VDO.Ninja.




---
description: How to capture the (free) system Text to Speech audio in Windows with OBS
---

# Windows TTS Audio Capture Methods for OBS

While free text-to-speech options are nice, they come with a few annoying limitations and challenges, which we will discuss below. Solutions will be provided.

### Background

OBS Studio's browser source does not have the ability to capture system-level text-to-speech (TTS) audio. It is capable of capturing premium TTS options, such as those powered by Google Cloud, Speechify, or Elevenlabs, but it cannot do so using the free built-in-to-browser ones.  This is a limitation all browsers face when dealing with free TTS.\
\
Furthermore, not all browsers even support text-to-speech. Opera, Firefox, and others may lack them.

OBS Studio has a limited set of system-level TTS options, with Chrome offer some Google-powered options, and Edge support Microsoft-supported ones, along support for [Windows-installable TTS service pack add-ons](https://www.microsoft.com/en-us/download/details.aspx?id=27224). \
\
You can get a list of support text-to-speech languages that your browser supports at [https://vdo.ninja/tts](https://vdo.ninja/tts)

## How to capture the free TTS and get it into OBS Studio

### Method 1: Default Audio Route

```
1. Set Virtual Cable as Windows default output
   - Sound Settings > Output > Virtual Cable
2. OBS:
   - Add Audio Input Capture
   - Source: Virtual Cable
   - Monitor: Monitor Only
```

### Method 2: Windows 10 App Route

```
1. Sound Settings > App volume and device preferences
2. Find browser in list
3. Output: Virtual Cable
4. OBS setup same as Method 1
```

### Method 3: Windows 11 App Route

```
1. Settings > System > Sound > Volume Mixer
2. Locate browser
3. Output: Virtual Cable
4. OBS setup same as Method 1
```

### Method 4: Audio Router

```
1. Install Audio Router
2. Route browser to Virtual Cable
3. OBS setup same as Method 1
```

### Method 5: Voicemeeter

```
1. Install Voicemeeter
2. Set as Windows default output
3. Route:
   - Hardware out > speakers
   - Virtual out > OBS
4. OBS captures Voicemeeter output
```

### Testing

```
1. Play TTS
2. Check OBS meter
3. Verify system audio
4. Adjust levels if needed
```

### Alternatives

If these options do now work for you, there are paid options available, using Google Cloud, Elevenlabs, and Speechify. You can also try to self-deploy your own self-hosted open-source project that offers TTS for free, but that is out of scope for this article.

## Where is TTS used?

TTS is offered in[ Social Stream Ninja ](../steves-helper-apps/social-stream-ninja/)in several places, to read out messages from audiences. It is also offered by [CAPTION.Ninja](../steves-helper-apps/caption.ninja.md), which offers closed-captioning, transcription, and translation. Both offerings have premium and free TTS options.




---
description: Some cheatsheets to help you get started
---

# Cheat Sheets

#### [VDO.Ninja Basic Concepts Cheatsheet](https://github.com/steveseguin/vdo.ninja/blob/quickstart/basicconcepts/cheatsheet\_obsn\_basic\_concepts.md)

Learn the basic concepts of VDO.Ninja: Rooms, Control Center and Scenes

 (1).png>)

#### [VDO.Ninja Parameters Cheatsheet](https://github.com/steveseguin/vdo.ninja/blob/quickstart/cheatsheet/cheatsheet\_obsn\_parameters.md)

Learn how to use parameters to customize VDO.Ninja's behavior\

 (1).png>)

#### [VDO.Ninja Automation Cheatsheet](https://github.com/steveseguin/vdo.ninja/blob/quickstart/automation/cheatsheet\_obsn\_automation.md)

Learn how to automate starting up VDO.Ninja, automatically join rooms and scenes with camera and audio devices already selected\

 (2).png>)

#### [VDO.Ninja Mac Audio Routing w Loopback Cheatsheet (example 1)](https://github.com/steveseguin/vdo.ninja/blob/quickstart/loopbackrouting1/cheatsheet\_obsn\_loopback\_routing1.md)

Learn how to route guest and application audio on the Mac using Loopback\
\

.png>)

Author:\
[Chris Marquardt](https://chrismarquardt.com/)




---
description: >-
  A detailed guide on how to deploy MediaMTX, a ready-to-use media server, that
  offers Meshcast-like functionality
---

# Deploy your own Meshcast-like service

Okay, here is a detailed guide on how to deploy MediaMTX, a ready-to-use SRT / WebRTC / RTSP / RTMP / LL-HLS media server, to use with VDO.Ninja's Meshcast-like functionality. This guide is written for beginners and advanced users alike, aiming to make the setup process as straightforward as possible.

## Using MediaMTX with VDO.Ninja for Scalable Broadcasting

This guide will walk you through deploying MediaMTX (formerly rtsp-simple-server) as a self-hosted media server to enhance your VDO.Ninja experience, particularly for large audiences. By using MediaMTX, you can create a setup similar to VDO.Ninja's Meshcast feature, offloading the encoding and distribution of your streams to a dedicated server. This significantly reduces the load on your computer and network, enabling you to host more viewers and maintain a high-quality stream.

### Why Use MediaMTX with VDO.Ninja?

VDO.Ninja, by default, uses peer-to-peer connections for video and audio transmission. While this works great for small groups, it can become a bottleneck when dealing with a larger audience. Each viewer adds to the upload bandwidth and encoding burden on the sender's machine.

**Meshcast** is a feature in VDO.Ninja designed to solve this scalability issue. It acts as an intermediary server (SFU or Selective Forwarding Unit) that receives a single stream from the broadcaster and then redistributes it to multiple viewers. This greatly reduces the load on the broadcaster.

**MediaMTX** allows you to replicate the functionality of Meshcast using your own server. By integrating MediaMTX with VDO.Ninja, you achieve:

* **Scalability:** Handle a large number of viewers without overloading your computer or network.
* **Reduced Load:** The broadcaster only needs to encode and upload the stream once to the MediaMTX server.
* **Improved Performance:** Viewers receive a smoother, more stable stream as the server handles distribution.
* **Cost Savings:** While Meshcast is a free service offered by VDO.Ninja, using your own MediaMTX server can be more cost-effective, especially if you already have a server or prefer using a VPS.
* **Control:** You have full control over your media server, including its configuration and security.
* **Flexibility:** MediaMTX supports various protocols beyond WebRTC (WHIP/WHEP), including SRT, RTSP, RTMP, and HLS, opening up possibilities for broader integration.

### Prerequisites

Before we begin, make sure you have the following:

* **A server or computer:** You'll need a machine to host the MediaMTX server. This can be:
  * **Local machine (Windows, macOS, or Linux):** Suitable for testing or small audiences, but you'll need to configure your router for port forwarding, which is not covered in this tutorial.
  * **Virtual Private Server (VPS):** Ideal for larger audiences and production environments. Recommended for best performance and reliability.
* **Domain name (Optional but Highly Recommended):** While not strictly necessary, a domain name (e.g., `yourdomain.com`) simplifies configuration and makes your setup more user-friendly. It's also highly recommended for using free SSL certificates (for HTTPS). Using an IP address directly is not optimal, although you can still have VDO.Ninja generate SSL keys for you if you opt to use an IP address only.
* **Basic command-line knowledge:** You'll need to be comfortable using the command line or terminal for your operating system.
* **VDO.Ninja:** You should be familiar with the basic usage of VDO.Ninja.

### Deployment Guide: MediaMTX

This guide will cover the deployment of MediaMTX on:

* **Linux Server (using a VPS like Vultr)**
* **Windows**
* **macOS**

#### 1. Deploying on a Linux Server (VPS)

**Choosing a VPS Provider**

Several VPS providers offer affordable and reliable services. Some popular options include:

* **Vultr:** [https://www.vultr.com/](https://www.google.com/url?sa=E\&source=gmail\&q=https://www.vultr.com/) - Offers a wide range of plans and locations, starting at around $2.50/month (IPv6 only) or $3.50/month (IPv4). Their High-Frequency Compute options are recommended for better performance.
* **DigitalOcean:** [https://www.digitalocean.com/](https://www.google.com/url?sa=E\&source=gmail\&q=https://www.digitalocean.com/) - Another popular choice with user-friendly interface and good performance.
* **Linode:** [https://www.linode.com/](https://www.google.com/url?sa=E\&source=gmail\&q=https://www.linode.com/) - Known for its excellent customer support and robust infrastructure.
* **AWS Lightsail:** [https://aws.amazon.com/lightsail/](https://www.google.com/url?sa=E\&source=gmail\&q=https://aws.amazon.com/lightsail/) - Amazon's offering, integrating well with other AWS services.

For this guide, we'll use **Vultr** as an example, but the steps are similar for other providers.

**Setting up your Vultr VPS**

1. **Sign up for a Vultr account:** Visit [https://www.vultr.com/](https://www.google.com/url?sa=E\&source=gmail\&q=https://www.vultr.com/) and create an account.
2. **Deploy a new server:**
   * Choose **Cloud Compute**.
   * Select **Optimized Cloud Compute** for CPU & Storage Technology. High Frequency is the recommended option here.
   * Choose a **server location** that's geographically close to your target audience for optimal latency.
   * For **Server Image**, choose a Linux distribution. **Ubuntu 22.04 LTS** is a good option for its stability and long-term support. Debian 11 or 12 are also popular choices for use with Mediamtx.
   * Select a **Server Size** based on your expected audience size. For a small to medium-sized audience, the $6/month plan should be sufficient to start.
   * Enable **IPv4** if needed, or leave it disabled for IPv6 only.
   * Give your server a **Hostname** (e.g., `mediamtx-server`).
   * Click **Deploy Now**.
3. **Wait for the server to be provisioned:** This usually takes a few minutes.
4. **Connect to your server:** Once the server is running, Vultr will display its IP address. You'll need to connect to it using SSH:
   * **Linux/macOS:** Open your terminal and run: `ssh root@your_server_ip` (replace `your_server_ip` with the actual IP address).
   * **Windows:** You can use an SSH client like PuTTY ([https://www.putty.org/](https://www.google.com/url?sa=E\&source=gmail\&q=https://www.putty.org/)).

**Installing MediaMTX**

Once you're connected to your server via SSH, follow these steps:

1.  **Update the package list:**

    Bash

    ```
    sudo apt update
    ```
2.  **Install MediaMTX:**

    Bash

    ```
    wget https://github.com/bluenviron/mediamtx/releases/latest/download/mediamtx_linux_amd64.tar.gz
    tar -xf mediamtx_linux_amd64.tar.gz
    sudo mv mediamtx /usr/local/bin/
    sudo mv mediamtx.yml /usr/local/etc/
    ```

    If you're on a different architecture, like ARM, check the [Mediamtx releases](https://www.google.com/url?sa=E\&source=gmail\&q=https://github.com/bluenviron/mediamtx/releases/) for the correct package.
3.  **Run MediaMTX:**

    Bash

    ```
    mediamtx
    ```

    To configure Mediamtx to auto-start on boot, you can setup a service.

    Bash

    ```
    sudo curl -s https://raw.githubusercontent.com/bluenviron/mediamtx/main/mediamtx.service --output /etc/systemd/system/mediamtx.service
    sudo systemctl daemon-reload
    sudo systemctl start mediamtx
    sudo systemctl enable mediamtx
    ```

**Setting up a Domain Name (Optional but Recommended)**

If you'd like to avoid using IP addresses directly and enable HTTPS, you'll want to use a domain name.

1. **Purchase a domain name:** You can buy affordable domain names from registrars like:
   * **Namecheap:** [https://www.namecheap.com/](https://www.google.com/url?sa=E\&source=gmail\&q=https://www.namecheap.com/) - Often has great deals on domains, especially for the first year. You can get domains for as low as $1/year.
   * **Porkbun:** [https://porkbun.com/](https://www.google.com/url?sa=E\&source=gmail\&q=https://porkbun.com/) - Also offers competitive pricing and user-friendly interface.
2. **Configure DNS records:**
   * After purchasing your domain, go to your domain registrar's DNS settings.
   * Create an `A` record that points your domain (or a subdomain like `media.yourdomain.com`) to your Vultr server's IP address. If you're using IPv6, create an `AAAA` record instead.
   * DNS changes can take some time to propagate (up to 48 hours, but usually much faster). You can use tools like [https://www.whatsmydns.net/](https://www.google.com/url?sa=E\&source=gmail\&q=https://www.whatsmydns.net/) to check the propagation status.

**Enabling HTTPS (Optional but Recommended)**

HTTPS is crucial for security and WebRTC compatibility in many browsers. If you only have an IP address available and no domain name, you can set up Mediamtx to generate and serve the SSL keys for you. This is outlined in the Mediamtx documentation.

If you have a domain name, here's how to set up free SSL certificates using Let's Encrypt with Cloudflare:

**Using Cloudflare for Free SSL**

1. **Create a Cloudflare account:** Go to [https://www.cloudflare.com/](https://www.google.com/url?sa=E\&source=gmail\&q=https://www.cloudflare.com/) and sign up for a free account.
2. **Add your domain to Cloudflare:** Follow the instructions to add your website to Cloudflare. This usually involves changing your domain's nameservers to Cloudflare's nameservers. You will need to update your domain name's DNS records at your domain registrar, replacing them with the ones provided to you by Cloudflare.
3. **Enable SSL/TLS:**
   * In your Cloudflare dashboard, go to the **SSL/TLS** tab.
   * Choose the **Full (strict)** encryption mode. This ensures secure communication between your server and Cloudflare, as well as between Cloudflare and your visitors. If this fails, you can try other SSL options available.
4. **Configure your Nginx configuration file** to redirect HTTP traffic to HTTPS. Or, you can enable the "Always Use HTTPS" option under SSL/TLS -> Edge Certificates.
5. **Enable `proxyProtocol`** under the `http` element of your Mediamtx.yml file.

Cloudflare will now automatically issue and renew SSL certificates for your domain.

**If you are unable to use Cloudflare, you can also try using CertBot.**

1.  **Install Certbot and Nginx plugin:**

    Bash

    ```
    sudo apt install certbot python3-certbot-nginx
    ```
2.  **Obtain and install a certificate:**

    Bash

    ```
    sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
    ```

    Replace `yourdomain.com` and `www.yourdomain.com` with your actual domain name. Follow the prompts to configure HTTPS.
3. **Automatic renewal:** Certbot automatically sets up a cron job or systemd timer to renew your certificates before they expire.

**Opening Firewall Ports**

Your VPS likely has a firewall enabled. You need to open the following ports for MediaMTX to work correctly:

* **8889 (WHEP/WHIP):** Used for WebRTC streaming.
* **8554 (RTSP):** Used for RTSP connections.
* **1935 (RTMP):** Used for RTMP connections.
* **8888 (HLS):** Used for HTTP Live Streaming.
* **80 (HTTP)** Used for Let's Encrypt renewals if not using Cloudflare or for general HTTP access.
* **443 (HTTPS)** Used for secure HTTPS access.

Here's how to open these ports using `ufw` (Uncomplicated Firewall), a common firewall management tool:

Bash

```
sudo ufw allow 8889/tcp
sudo ufw allow 8554/tcp
sudo ufw allow 1935/tcp
sudo ufw allow 8888/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
```

If using `iptables` instead, you can use these commands:

Bash

```
sudo iptables -I INPUT -p tcp --dport 8889 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 8554 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 1935 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 8888 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT -p tcp --dport 443 -j ACCEPT
sudo netfilter-persistent save
```

If your VPS provider has a built-in firewall, you might need to open these ports in their control panel as well.

#### 2. Deploying on Windows

**Installing MediaMTX on Windows**

1. **Download MediaMTX:** Go to the MediaMTX releases page on GitHub ([https://github.com/bluenviron/mediamtx/releases](https://www.google.com/url?sa=E\&source=gmail\&q=https://github.com/bluenviron/mediamtx/releases)) and download the latest release for Windows (e.g., `mediamtx_vX.Y.Z_windows_amd64.zip`).
2. **Extract the archive:** Extract the downloaded ZIP file to a folder of your choice (e.g., `C:\mediamtx`).
3.  **Run MediaMTX:** Open a Command Prompt or PowerShell window, navigate to the extracted folder, and run:

    Bash

    ```
    .\mediamtx.exe
    ```

**Opening Firewall Ports (Windows)**

You'll need to allow MediaMTX through the Windows Firewall:

1. **Open Windows Defender Firewall:** Search for "Windows Defender Firewall" in the Start menu and open it.
2. **Click on "Advanced settings"** on the left sidebar.
3. **Inbound Rules:**
   * Click on "Inbound Rules" in the left pane.
   * Click on "New Rule..." in the right pane.
   * Select "Port" and click "Next".
   * Select "TCP" and enter the following ports in "Specific local ports": `8889, 8554, 1935, 8888, 80, 443` (you can add them as a comma-separated list). Click "Next".
   * Choose "Allow the connection" and click "Next".
   * Select the network profiles (Domain, Private, Public) for which you want to apply this rule. For home use, "Private" is usually sufficient. Click "Next".
   * Give the rule a name (e.g., "MediaMTX Ports") and click "Finish".
4. **Outbound Rules:** You might also need to create outbound rules if you have a strict firewall configuration. Repeat the steps above, but select "Outbound Rules" instead of "Inbound Rules" in step 3.

**Allowing connections through your router's firewall**

You may need to manually forward ports `8889, 8554, 1935, 8888, 80, 443` to the IP address of your local PC. You will need to refer to your router's documentation on how to do this, as this process will vary based on make and model.

#### 3. Deploying on macOS

**Installing MediaMTX on macOS**

1. **Download MediaMTX:** Go to the MediaMTX releases page on GitHub ([https://github.com/bluenviron/mediamtx/releases](https://www.google.com/url?sa=E\&source=gmail\&q=https://github.com/bluenviron/mediamtx/releases)) and download the latest release for macOS (e.g., `mediamtx_vX.Y.Z_darwin_amd64.tar.gz`).
2.  **Extract the archive:** Open a Terminal window and use the `tar` command to extract the archive:

    Bash

    ```
    tar -xf mediamtx_vX.Y.Z_darwin_amd64.tar.gz
    ```

    (Replace `mediamtx_vX.Y.Z_darwin_amd64.tar.gz` with the actual filename).
3.  **Move MediaMTX (Optional):** You can move the `mediamtx` executable to a more convenient location, like `/usr/local/bin/`:

    Bash

    ```
    sudo mv mediamtx /usr/local/bin/
    ```
4.  **Run MediaMTX:** Open a Terminal window and run:

    Bash

    ```
    mediamtx
    ```

**Opening Firewall Ports (macOS)**

macOS has a built-in firewall called `pf`. Here's how to open ports:

1.  **Edit the `pf` configuration file:**

    Bash

    ```
    sudo nano /etc/pf.conf
    ```
2.  **Add the following lines to the end of the file:**

    ```
    pass in proto tcp from any to any port 8889
    pass in proto tcp from any to any port 8554
    pass in proto tcp from any to any port 1935
    pass in proto tcp from any to any port 8888
    pass in proto tcp from any to any port 80
    pass in proto tcp from any to any port 44
    ```
3. **Save the file and exit the editor** (Ctrl+X, then Y, then Enter).
4.  **Load the new `pf` rules:**

    Bash

    ```
    sudo pfctl -f /etc/pf.conf
    ```
5.  **Enable `pf`:**

    Bash

    ```
    sudo pfctl -e
    ```

**Allowing connections through your router's firewall**

You may need to manually forward ports `8889, 8554, 1935, 8888, 80, 443` to the IP address of your local PC. You will need to refer to your router's documentation on how to do this, as this process will vary based on make and model.

### Integrating MediaMTX with VDO.Ninja

Now that your MediaMTX server is up and running, it's time to integrate it with VDO.Ninja.

#### Understanding the Logic

VDO.Ninja uses the `&mediamtx` parameter to connect to your MediaMTX server. Here's how it works:

1. **`&mediamtx` Parameter:** When a guest joins a VDO.Ninja room with the `&mediamtx` parameter in their URL, VDO.Ninja interprets it as the address of your MediaMTX server.
2. **WHIP Output:** VDO.Ninja automatically constructs the WHIP (WebRTC-HTTP ingestion Protocol) endpoint based on the `&mediamtx` value and the stream ID. The guest's browser will publish their stream to this WHIP endpoint on your MediaMTX server.&#x20;
3. **WHEP URL Sharing:** The guest's browser shares the WHEP (WebRTC-HTTP Egress Protocol) URL of their stream (also hosted on your MediaMTX server) with other participants in the VDO.Ninja room via the data channel.
4. **WHEP Playback:** Viewers in the VDO.Ninja room receive the WHEP URL and use it to play the stream from the MediaMTX server instead of directly from the guest via a peer-to-peer connection.\

### Using the `&mediamtx` Parameter in VDO.Ninja: A Simple Guide

The `&mediamtx` parameter is your key to connecting VDO.Ninja with your MediaMTX server, allowing you to create a scalable and efficient streaming setup. Here's how you use it and what you need to know:

#### What it Does

The `&mediamtx` parameter tells VDO.Ninja where your MediaMTX server is located. When a guest joins your VDO.Ninja room with this parameter, their browser will send their video and audio stream directly to your MediaMTX server instead of relying solely on peer-to-peer connections. Your MediaMTX server then handles distributing the stream to viewers.

#### How to Use It

You add the `&mediamtx` parameter to the end of the VDO.Ninja guest invite link, followed by the address of your MediaMTX server.

#### Formatting Options

Here's the breakdown of how to format the `&mediamtx` value:

1. **Basic Domain Name:**
   * **Format:** `&mediamtx=yourdomain.com`
   * **What it does:** If you provide just a domain name (without `http://` or `https://` and without a port number), VDO.Ninja makes the following assumptions:
     * It assumes you want to use **HTTPS** (secure connection).
     * It assumes your MediaMTX server is running on the standard HTTPS port for WHIP/WHEP, which is **8889**.
     * It assumes the top level domain is .com if you do not specify it. `&mediamtx=mymediatxserver` will be treated as `&mediamtx=mymediatxserver.com`.
   * **Example:** `&mediamtx=mymediaserver.com` will connect to `https://mymediaserver.com:8889/`.
   * **Recommendation:** This is the simplest and recommended way if you've set up your domain with HTTPS and are using the default WHIP/WHEP port (8889).
2. **Domain Name with Different Top-Level Domain:**
   * **Format:** `&mediamtx=yourdomain.xyz` (or any other valid TLD)
   * **What it does:** Similar to the basic format, but allows you to specify a different top-level domain.
     * Assumes **HTTPS**.
     * Assumes the standard WHIP/WHEP port **8889**.
   * **Example:** `&mediamtx=stream.live` will connect to `https://stream.live:8889/`.
3. **Specifying a Port:**
   * **Format:** `&mediamtx=yourdomain.com:port`
   * **What it does:** If your MediaMTX server is running on a port other than 8889 for WHIP/WHEP, you need to specify it.
     * Assumes **HTTPS** if not specified.
   * **Example:** `&mediamtx=yourdomain.com:8890` will connect to `https://yourdomain.com:8890/`.
4. **Specifying HTTP or HTTPS:**
   * **Format:** `&mediamtx=http://yourdomain.com` or `&mediamtx=https://yourdomain.com`
   * **What it does:** You can explicitly specify whether to use HTTP or HTTPS.
   * **Example:** `&mediamtx=http://yourdomain.com:8889` will connect to `http://yourdomain.com:8889/`.
   * **Recommendation:** Always prefer HTTPS for security.
5. **Using an IP Address:**
   * **Format:** `&mediamtx=123.45.67.89` or `&mediamtx=123.45.67.89:port`
   * **What it does:** You can use your server's IP address instead of a domain name.
     * Assumes **HTTPS** and port **8889** if not specified.
   * **Example:** `&mediamtx=192.168.1.100:8890` will connect to `https://192.168.1.100:8890/`.
   * **Note:** Using IP addresses directly is generally not recommended for production because you cannot get a typically trusted SSL certificate without a domain name. If you do use an IP address, consider specifying the port, and configuring HTTPS via Mediamtx's automatic SSL generation.
6. **Using `localhost` (for local testing):**
   * **Format:** `&mediamtx=localhost` or `&mediamtx=localhost:port`
   * **What it does:** If you're testing MediaMTX locally on your own computer, you can use `localhost`.
     * Assumes **HTTP** and port **8889** if not specified.
   * **Example:** `&mediamtx=localhost:8890` will connect to `http://localhost:8890/`.

#### Important Notes

* **HTTPS is Highly Recommended:** Always strive to use HTTPS for secure communication. WebRTC often requires HTTPS in many browsers.
* **Default Port:** If you don't specify a port, VDO.Ninja assumes the default WHIP/WHEP port for MediaMTX, which is 8889.
* **Stream ID:** VDO.Ninja automatically generates a unique stream ID for each guest. You don't need to specify this in the `&mediamtx` parameter.
* **Room Name:** VDO.Ninja uses the room name as part of the path for WHIP/WHEP on the MediaMTX server.

#### Summary Table

| Format                   | Assumed Protocol | Assumed Port | Notes                                                                                                                                   |
| ------------------------ | ---------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `yourdomain.com`         | HTTPS            | 8889         | Assumes .com TLD. Simplest and recommended if using HTTPS and default port.                                                             |
| `yourdomain.xyz`         | HTTPS            | 8889         | Allows for specifying a different TLD.                                                                                                  |
| `yourdomain.com:port`    | HTTPS            | Specified    | Use if your MediaMTX WHIP/WHEP server is on a non-default port.                                                                         |
| `http://yourdomain.com`  | HTTP             | 8889         | Explicitly uses HTTP. Not recommended for production.                                                                                   |
| `https://yourdomain.com` | HTTPS            | 8889         | Explicitly uses HTTPS. Recommended.                                                                                                     |
| `123.45.67.89`           | HTTPS            | 8889         | Uses IP address. Assumes HTTPS and default port. Less ideal for production due to SSL limitations.                                      |
| `123.45.67.89:port`      | HTTPS            | Specified    | Uses IP address with a specific port. Consider specifying HTTPS if needed, and configuring SSL via Mediamtx's automatic SSL generation. |
| `localhost`              | HTTP             | 8889         | For local testing only. Assumes HTTP and default port.                                                                                  |
| `localhost:port`         | HTTP             | Specified    | For local testing with a specific port.                                                                                                 |

By following these guidelines, you can correctly format the `&mediamtx` parameter and ensure that your VDO.Ninja guests connect seamlessly to your MediaMTX server. Remember that using a domain name with HTTPS is the most secure and user-friendly approach for most scenarios.

#### Usage Example

Here's a step-by-step example of how to use MediaMTX with VDO.Ninja:

1.  **Guest URL:** A guest joining a VDO.Ninja room would use a URL like this:

    ```
    https://vdo.ninja/?room=YourRoomName&mediamtx=yourdomain.com
    ```

    or

    ```
    https://vdo.ninja/?room=YourRoomName&mediamtx=your_server_ip:8889
    ```

    Replace `YourRoomName` with your actual room name, `yourdomain.com` with your domain name, or `your_server_ip` with your server's IP address. If you haven't set up a domain, just use the IP.
2. **Director's View:** The director (or other viewers) can view the stream as usual in the VDO.Ninja room. They don't need to add any special parameters to their URL. VDO.Ninja will automatically handle the playback from the MediaMTX server.
3.  **Direct WHEP Playback (Optional):** If you want to play the stream directly from the MediaMTX server (outside of VDO.Ninja), you can use the WHEP URL. It will look like this:

    ```
    https://yourdomain.com:8889/YourRoomName/YourStreamID/whep
    ```

    or

    ```
    https://your_server_ip:8889/YourRoomName/YourStreamID/whep
    ```

    You can obtain `YourStreamID` from the VDO.Ninja interface or the URL of the guest's browser window.

    You may need to provide this URL manually if you want to play the stream in a separate player that supports WHEP.

#### Configuration Tips

* **Audio:** If you want to ensure stereo audio, even when using MediaMTX, you might need to use the `&stereo` parameter in the guest's URL. The code you provided suggests that setting `session.stereo=3` might force stereo, but you'll need to confirm this behavior.
* **Stream ID:** The `streamID` in the WHIP/WHEP URLs is automatically generated by VDO.Ninja. It's usually a random string. You can find the stream ID in the guest's VDO.Ninja URL or in the VDO.Ninja interface.
* **Security:**
  * **HTTPS:** Always use HTTPS (SSL) for your MediaMTX server to protect the stream and user data.
  * **Authentication:** Consider configuring authentication for your MediaMTX server if you need to restrict access to your streams. Refer to the MediaMTX documentation for details on how to set up authentication.
* **Performance:**
  * **Server Resources:** Monitor your server's CPU, memory, and bandwidth usage to ensure it can handle the load. Upgrade your server if necessary.
  * **Network Latency:** Choose a server location that's geographically close to your audience to minimize latency.
  * **Bitrate:** Adjust the bitrate of your stream in VDO.Ninja based on your available bandwidth and the desired quality.
* **Troubleshooting:**
  * **Firewall:** Double-check that your firewall (both on the server and your local machine if testing locally) is configured to allow the necessary ports.
  * **Domain Propagation:** If you're using a domain name, make sure the DNS records have fully propagated.
  * **MediaMTX Logs:** Check the MediaMTX logs for any errors or warnings.
  * **Browser Console:** Use your browser's developer console (usually by pressing F12) to look for any errors related to WebRTC or network requests.

### Conclusion

Deploying MediaMTX and integrating it with VDO.Ninja provides a powerful and scalable solution for broadcasting to larger audiences. By offloading the stream distribution to a dedicated server, you can significantly improve the performance and stability of your VDO.Ninja streams.

This guide has covered the essential steps for setting up MediaMTX on Linux, Windows, and macOS, including VPS deployment, domain name configuration, HTTPS setup, and firewall configuration. It has also explained how to use the `&mediamtx` parameter in VDO.Ninja to connect to your MediaMTX server and leverage its capabilities.

Remember to tailor the configuration to your specific needs and environment. Monitor your server's performance and adjust settings as necessary to ensure a smooth and high-quality streaming experience for your viewers. With a little bit of setup, you can take your VDO.Ninja broadcasts to the next level with the power of MediaMTX!




---
description: >-
  There are numerous free URL management tools to make using VDO.Ninja even more
  flexible
---

# How to edit an invite after sending it

You can use services like [https://short.io](https://short.io) to create aliases of your invite links, leveraging those service platforms to also keep track of invites you have sent out, how many times they have been opened, and also change the VDO.Ninja settings contained in the invite after sending it.

[VDO.Ninja](https://vdo.ninja) lets you move guests between room and change the URL of a guest after they have connected, but it doesn't offer services itself that let you change the URL before the user has connected.

 (1) (1) (1).png>)

{% hint style="info" %}
I have no relation to Short.io; it's just what service I happen to use. There are plenty of other options out there.
{% endhint %}




---
description: Publishing from OBS Studio to VDO.Ninja using WHIP
---

# From OBS to VDO.Ninja using WHIP

OBS Studio v30 now has WHIP output support, which means that you can stream directly to VDO.Ninja without a browser or other software.\
\
While there are a few serious limitations with OBS's current WHIP implementation, when used with VDO.Ninja it still offers a great way to stream from one computer to another, on the same LAN, while minimizing CPU overhead and latency.

Prerequisites

* OBS Studio (version 30 or later)
  * For WHIP over the Internet, you'll need to use this patched version of OBS for now: \
    [https://backup.vdo.ninja/OBS\_VDO\_Ninja.zip](https://backup.vdo.ninja/OBS_VDO_Ninja.zip) \[[source](https://github.com/steveseguin/obs-studio/)]
* A stable internet connection
* Access to VDO.Ninja

### Steps

1. **Prepare VDO.Ninja**
   * Make up a unique stream token (e.g., `STREAMTOKEN123`)
   * Create your VDO.Ninja link: `https://vdo.ninja/?whip=STREAMTOKEN123`
   * Open this link in a web browser on the receiving end
2. **Configure OBS Studio**
   * Open OBS Studio
   * Go to Settings > Stream
   * Select "WHIP" as the service
   * For the server, enter: `https://whip.vdo.ninja`
   * For the Stream Key, enter your unique stream token (STREAMTOKEN123)
3. **Choose Encoding Settings**
   * In OBS, go to Settings > Output
   * Select your preferred encoder:
     * Software (x264) for H.264
     * NVIDIA NVENC for H.264 (if you have an NVIDIA GPU)
     * AMD AMF for H.264 (if you have an AMD GPU)
     * AV1 (if supported by your hardware and OBS version)
   * Set your desired bitrate (e.g., 2500-6000 Kbps for 1080p)
4. **Go Live**
   * In OBS, click "Start Streaming"
   * The stream should appear automatically in the opened VDO.Ninja window

{% hint style="info" %}
The stream token you give to OBS is the stream ID you specified in VDO.Ninja.
{% endhint %}

<figure><figcaption><p>Example setup for OBS to VDO</p></figcaption></figure>

### Encoder options that can offer smooth playback

Some H264 settings that have reported offered good results are the following:

* Rate Control: CRF
* CRF: 23
* Keyframe Interval: 1s
* Preset: Veryfast
* Profile: High
* Tune: Fastdecode (required for WebRTC playback)
* x264 Options: bframes=0 (required for WebRTC playback)

In some cases, adding [`&buffer=2500`](https://docs.vdo.ninja/advanced-settings/video-parameters/buffer) to the VDO.Ninja view link can further help reduce any lost of skipped frames, but at the cost of increased latency.

### Additional Notes

* **Codec Choice**:
  * H.264 is widely supported and offers good quality/compression balance
  * AV1 provides better compression but requires more processing power and may not be supported on all devices
* **Network Considerations**:
  * OBS Studio's WHIP implementation doesn't support STUN (NAT traversal)
  * The receiving computer must be on the same LAN or accessible via a public IP without firewall restrictions
  * You can use the patched version of OBS to work around this issue for now, until the official OBS is updated with full support.
* **Troubleshooting**:
  * If the stream doesn't appear, check your firewall settings
  * Ensure both OBS and VDO.Ninja are using the same stream token
  * Verify that your internet connection is stable and has sufficient upload bandwidth
* **Quality vs. Performance**:
  * Lower resolutions and bitrates will reduce latency and improve stability
  * Higher resolutions and bitrates will increase quality but may introduce more delay

Remember to test your setup before any important broadcasts to ensure everything works smoothly.

### Streaming WHIP over the Internet or to more than one viewer

I offer [https://Meshcast.io](https://meshcast.io), for free, which supports WHIP input and can broadcast to dozens of viewers online.\
\
There's also MediaMTX, which is a self-hosted broadcasting server option that VDO.Ninja supports. Deeper integration with MediaMTX is being added to VDO.Ninja all the time.

In the future, OBS should be able to support 1 to 1 over the Internet, despite firewalls, with VDO.Ninja, in a peer to peer fashion.  Until they officially support it, you can try my patched version of OBS that has added this support: [https://backup.vdo.ninja/OBS\_VDO\_Ninja.zip](https://backup.vdo.ninja/OBS_VDO_Ninja.zip) \[[source](https://github.com/steveseguin/obs-studio/)]

### Alternative browser-free option

If looking for alternatives to publishing into VDO.Ninja, consider checking out [Raspberry.Ninja](https://docs.vdo.ninja/updates/updates-raspberry.ninja) also, which supports a broad range of encoders, including AV1-AOM, Intel QuickSync, Raspberry Pis, Nvidia Jetson, and many other hardware and software options. Playback is smooth, with support for multiple viewers. Runs on most systems, including Linux and _Windows for Linux Subsystem_ (WSL).

{% embed url="https://www.youtube.com/watch?v=ynSOE2d4Z9Y" %}
Demoing OBS to VDO.Ninja via WHIP
{% endembed %}

Related WHIP videos:

{% embed url="https://www.youtube.com/watch?v=_RHBsAJmfGs" %}





---
description: Some keyboard hotkeys
---

# Basic hotkeys

<table><thead><tr><th width="211">Hotkeys</th><th>Description</th></tr></thead><tbody><tr><td><code>CTRL + M</code></td><td>Mute your mic (audio output)</td></tr><tr><td><code>CTRL + B</code></td><td>Mute your video output</td></tr><tr><td><code>SHIFT + ALT + C</code></td><td>Toggle the control bar that's normally at the bottom of the screen</td></tr><tr><td><code>CTRL + ALT + F</code></td><td>Open the file-sharing window</td></tr><tr><td><code>CTRL + ALT + C</code></td><td>Cycle the camera to the next camera available</td></tr><tr><td><code>CTRL + ALT + S</code></td><td>Open the screen-sharing window</td></tr><tr><td><code>CTRL + ALT + D</code></td><td>Enable Draw-on-Screen</td></tr><tr><td><code>CTRL + ALT + P</code></td><td>Will toggle the picture in picture</td></tr><tr><td><code>ALT + A</code></td><td>Will toggle the speaker-output audio mute on/off (only usable when the browser tab is in focus)</td></tr></tbody></table>

{% hint style="info" %}
On MacOS use `CMD` instead of `CTRL`
{% endhint %}

When using the above keyboard short-cuts, the tab/window must be actively in focus.

When using the [Electron Capture App](../../steves-helper-apps/electron-capture.md) in elevated privilege mode, the keyboard shortcuts are global.

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="../../advanced-settings/settings-parameters/and-disablehotkeys.md" %}
[and-disablehotkeys.md](../../advanced-settings/settings-parameters/and-disablehotkeys.md)
{% endcontent-ref %}




---
description: Controlling VDO.Ninja with Touch Portal using API commands
---

# How to control VDO.Ninja with Touch Portal

## How to

1\. Create a new room as a director, with a custom API key, so that it looks like this: [`https://vdo.ninja/?api=APIKEY&director=TouchPortalExample`](https://vdo.ninja/?api=APIKEY\&director=TouchPortalExample) \
Replacing the APIKEY with a string of your choosing.&#x20;

2\. Then, in Touch Portal, add a new button with the `HTTP GET` action. In the `HTTP GET` Action `GET URL` field, input your desired action. This particular GET action will send Guest 1 to Scene 1 with a push of the button:\
`https://api.vdo.ninja/APIKEY/addScene/1/1`

<div align="left">

</div>

Thanks to <mark style="color:red;">djlefave</mark> on [Discord](https://discord.vdo.ninja/) for this guide.

## Switching the layout of a scene in OBS

`https://api.vdo.ninja/APIKEY/layout/[{"x":0,"y":0,"w":50,"h":100,"c":true,"slot":0},{"x":50,"y":0,"w":50,"h":100,"c":false,"slot":1}]`

 (2).png>)

You can also use Touch Portal to switch the layout of [`&scene=0`](../../advanced-settings/view-parameters/scene.md) without using the [Mixer App](../../steves-helper-apps/mixer-app.md).

[https://docs.google.com/spreadsheets/d/1cHBTfni-Os3SAITsXrrNJ3qVCMVjunuW3xugvw1dykw/edit#gid=151839312](https://docs.google.com/spreadsheets/d/1cHBTfni-Os3SAITsXrrNJ3qVCMVjunuW3xugvw1dykw/edit#gid=151839312)

You can download this google sheet and use it to create your own layouts.

## Examples and resources

For more API examples, check out these resources:\
[https://github.com/steveseguin/Companion-Ninja](https://github.com/steveseguin/Companion-Ninja)\
[https://companion.vdo.ninja/?api=k8eYrfvJUC](https://companion.vdo.ninja/?api=k8eYrfvJUC)

## Related

{% content-ref url="../../general-settings/api.md" %}
[api.md](../../general-settings/api.md)
{% endcontent-ref %}




# How to control bitrate/quality

## Video Bitrate

The bitrate controls are accessible via a URL parameter that can be added to the VIEW link.

Something like [https://vdo.ninja/?view=yyyyy\&bitrate=10000 ](https://vdo.ninja/?view=yyyyy\&bitrate=10000)will let the viewer request set a 10-mbps bitrate; up to around 20000-kbps is reasonable, but higher is possible in situations. The value is in kilobits per second and the default bitrate is 2500-kbps.

The viewer sets the bitrate generally, although you can set maximum allowed bitrates as the publisher of a stream. See the advanced settings in the wiki for more help here; there are many options available.

When in a group room, the guests will generally get a very low-quality preview of the stream. This can be changed with the [`&totalroombitrate`](../advanced-settings/video-bitrate-parameters/totalroombitrate.md) parameter or via the room's director settings menu. The higher the room bitrate however, the more CPU and Network load will be placed on those in the room.

When dealing with a group scene link, you can use [`&bitrate`](../advanced-settings/video-bitrate-parameters/bitrate.md) as normal, or `&totalbitrate`. There are many [other ways to control bitrates](how-do-i-control-bitrate-quality.md#more-details), in both rooms and push links, with these being the standard options.

## Resolution

Camera resolution by default is captured at 1280x720. You can increase this by changing the quality setting when selecting your camera, or by adding `&quality=0` to the URL. The [`&quality`](../advanced-settings/video-parameters/and-quality.md) parameter acts as a preset, where \&quality=0 is preset for 1920x1080 @ 60-fps, `&quality=1` is 720p60, and `&quality=2` is a gentle 360p30.

You can manually set the video resolution via the URL, using `&width=1920&height=1080`, and this might be helpful when dealing with non-standard aspect-ratios.

{% hint style="info" %}
If using the OBS Virtual Camera as a source, be sure to activate it in OBS before trying to access it with VDO.Ninja with non-standard resolutions set.
{% endhint %}

The resolution can also be set on the viewer-side via the `&scale=100` parameter. This scales down the resolution, as a percentage, based on the original camera capture resolution.&#x20;

By default, VDO.Ninja will try to optimize and scale down the incoming resolution to fit the viewer's window size, but sometimes you might want to disable this. Adding `&scale=100` to the view link can achieve that, as it forces 100% scale, or no scaling in other words.

VDO.Ninja may still scale the video down however, although only if the connection between the two peers is having network issues, if the sender's encoder is having issues, or if the set bitrate is too low to sustain the higher resolution.

## Audio

You can improve audio quality in the same way, by increasing the [`&audiobitrate`](../advanced-settings/view-parameters/audiobitrate.md), but you can get better results by just disabling noise and echo cancellation instead.

[`&proaudio`](../general-settings/stereo.md) is flag that presets many audio options, which can be added to both the sender's and viewer's link to enable stereo audio with no audio processing and a very high audio bitrate set. You may need to be using headphones, especially if in a group room, if using [`&proaudio`](../general-settings/stereo.md) or if disabling the echo cancellation features.

## More Details

{% content-ref url="video-bitrate-for-push-view-links.md" %}
[video-bitrate-for-push-view-links.md](video-bitrate-for-push-view-links.md)
{% endcontent-ref %}

{% content-ref url="video-bitrate-in-rooms.md" %}
[video-bitrate-in-rooms.md](video-bitrate-in-rooms.md)
{% endcontent-ref %}

{% content-ref url="audio-filters.md" %}
[audio-filters.md](audio-filters.md)
{% endcontent-ref %}




# How to control PowerPoint remotely with VDO.Ninja

### Overview

Support for remote PowerPoint slide control. (previous/next slide):

* Documented things quite a bit here: [https://github.com/steveseguin/powerpoint\_remote](https://github.com/steveseguin/powerpoint\_remote)
* I've only tested with Windows + PowerPoint so far, but it can be tweaked to work with more than PPT without much trouble
* Uses AutoHotKey + VDO.Ninja + MIDI to achieve the result; quite a few different ways implement it, with samples provided
* Built-in basic controller added, via [`&powerpoint`](../advanced-settings/settings-parameters/and-powerpoint.md) (aliases: `&slides`, `&ppt`, `&pptcontrols`)
* IFrame sample app provided with larger buttons and sample code to add more custom buttons/actions if needed. (start/stop/etc): [https://vdo.ninja/examples/powerpoint](https://vdo.ninja/examples/powerpoint)
* HTTP / WSS remote control also added; `https://api.vdo.ninja/YOURAPIKEY/nextSlide` and `prevSlide`
* Local Streamdeck support also working, via MIDI

### YouTube Tutorial

{% embed url="https://youtu.be/ORH8betTt8Y" %}
Remote control PowerPoint with VDO.Ninja
{% endembed %}

### Images

<div align="left">

<figure><figcaption><p><a href="../advanced-settings/settings-parameters/and-powerpoint.md"><code>&#x26;powerpoint</code></a> as a URL parameter</p></figcaption></figure>

</div>

<div align="left">

<figure><figcaption><p>Remote PowerPoint Web control via VDO.Ninja (IFrame API)</p></figcaption></figure>

</div>




---
description: Newer iOS devices can support 1080p60 output in some cases
---

# How to get iPhones to output 1080p Videos

iPhones 12 and newer, running higher than iOS 16.0, and with the **rear** camera selected, can access 1080p60 video output in VDO.Ninja. This was tested last with Safari on an iPhone 12 Pro, running iOS 16.2 on [VDO.Ninja v23](../releases/v23.md). (May 5th 2023)

The actual frame rate of the video that the viewer receives may be lower than the 60 or 30-fps capture rate. It may end up ranging from 20-fps to 45-fps. As a result, limiting the capture frame rate of the device to 30-fps, such as with [`&maxframerate=30`](../source-settings/and-maxframerate.md), may help offer more stable frame rates, even if limited to 30-fps. So, 1080p30 may be preferable to 1080p60 in some cases.

Keep in mind, high motion and highly detailed scenes may also require higher bitrates; the default VDO.Ninja encoding bitrate is just barely suitable for stationary talking heads at 1080p60, but increasing the video bitrate to 4000-kbps, up to as high as 20000-kbps, may help.

1080p60 seems to work with H264 video encoding (default) and even VP9 video encoding, if enabled. On a side note, H265 (HEVC) may work Safari to Safari, but it is untested at present and may only work in highly controlled situations. The state of AV1 support though is quickly changing, and may be supported by iPhones in the near future. Both these newer codec options may be quite useful for when 4K streaming becomes more common.

As for older devices, iPhone 11 and older, they may only be able to achieve 1080p30 or 720p60 capture, assuming they are running iOS 16 and up. The front and rear cameras may achieve different frame rates or resolutions, depending on the device. You may need to experiment to find what works best for you specific iOS device, though such as if using an iPhone SE or iPad.

If selecting 1080p60, but getting 720p60, that may be the result of the device defaulting to 720p60 rather than 1080p30. Using `&maxframerate=30&quality=0`, you might be able to to achieve 1080p30 instead.

For example, front facing cameras on an iPhone 6S might be able to achieve 720p60, but the rear camera may achieve 1080p30 max. Trying to force 1080p60 on the iPhone 6S may result in a lower resolution being actually selected, or an error message may appear.

Older versions of VDO.Ninja ([v22](../releases/v22.md) and older), and some specific iOS device models, may need some custom URL tweaking to get the maximum available resolution / frame rate.

### For devices running older iOS versions, see below:

You can force 1080p on many iPhones, but you then need to use [`&codec=vp8`](../advanced-settings/view-parameters/codec.md) also then on older iOS versions.

for example:

[`https://vdo.ninja/?push=streamid&width=1920&height=1080`](https://vdo.ninja/?push=streamid\&width=1920\&height=1080)

and:

[`https://vdo.ninja/?view=streamid&codec=vp8&videobitrate=6000`](https://vdo.ninja/?view=streamid\&codec=vp8\&videobitrate=6000)

Older iOS versions do not support h264 at resolutions higher than 720p30.

If you use VP8 though, you will be using the software-based encoder, which will make the iPhone pretty warm/hot. It also only works only on newer iOS versions (iOS 14, for example).

In newer versions of iOS , it's possible to do 1080p60 with H264 encoding, but only under specific circumstances.




---
description: >-
  Guest invites can be configured to ensure guests join with the same stream ID
  every time they join, allowing for reusable view- and solo-links.
---

# How to get permanent links

If you connect with the [`&push=xxxx`](../source-settings/push.md) URL parameter set, you essentially are telling the system what you want the 'view=' ID to be. In this case, it would be `xxxx`. This value is referred to as the "stream ID".

As long as the stream ID is not already in use, you can use it to identify the stream you or a guest is publishing with. In so doing, you can ensure you always connect with the same stream ID, making subsequent view- and solo- links reusable.

### Refreshing vs Rejoining

If a guest joins a room without the `&push` value set in advanced, their URL will update to include a randomly generated `&push` value once they start streaming. So, if a guest refreshes their page once they start streaming, they will rejoin with the same stream ID, as the stream ID will be embedded in the URL at that point.

However, if a guest re-joins the room using the original invite link, which didn't have a `&push` value included in it, they will be assigned a new `&push` value once they rejoin.

It's important to note as well that you should not copy and share your VDO.Ninja URL after you've already started streaming, as your URL will contain your unique stream ID at that point. Share the original invite link instead, or modify the URL so it includes a different and unique stream ID to avoid conflicts.

### How to set a custom stream ID

A [`&push`](../source-settings/push.md) ID can be up to around 40-characters in length, using alphanumeric characters, and it can be pretty much anything you want to make up. You don't need to register anything; it just needs to be unique, and preferably, random enough so that it is secure from others also picking the same value.

While you can use a name as a stream ID, it's not very secure to do so. Instead, you can label your streams with [`&label`](../general-settings/label.md) to make it easier to identify. [`&showlabels`](../advanced-settings/design-parameters/showlabels.md) will then show those labels via a video overlay if you want as well.

### Auto-remember the last user stream ID

You can also use [`&permaid`](../advanced-settings/setup-parameters/and-permaid.md) on a guest invite link, which will save the randomly generated stream ID to the guest's local browser storage. Every time they rejoin, their stream ID kept in local storage will be reused. With this approach, you do not need to set a stream ID ahead of time, and as long as the guest doesn't clear their cache, change computers, or use a different browser, the stream ID won't change.

### Using several scenes, one per guest

Another option is to not use stream IDs at all to specify a video to load into OBS, etc. Instead, you can use custom [scenes](../advanced-settings/view-parameters/scene.md). Scene 1, S2, S3, etc. When a guest joins a room, you can simply assign the guest to a specific scene, and that scene link in OBS would be unchanging. Guests would not automatically be assigned to a scene, so you'd need to manually do that, but you don't need to update any URL in OBS with this approach.

### Using the Mixer app and slots

Like the above, you can also use the VDO.Ninja [Mixer App](../steves-helper-apps/mixer-app.md) ([https://vdo.ninja/mixer](https://vdo.ninja/mixer)) to have custom layouts, with "slots", and you can assign guests as they join to certain slots. You can have the system auto-assign guests to the first available slot also, or manually do so.\
\
Also in this auto-assign mode, you can assign a guest a slot via their URL, and if that slot is available when they join, you can have them join it automatically rather than the first available slot.

### View specific slots without custom layouts

For those wanting to avoid creating custom layouts or having to use the mixer app, [\&viewslot](../advanced-settings/mixer-scene-parameters/and-viewslot.md) can be used on a scene link to show only the guest who is assigned that specific slot. You can use \&slotsmode on the director's URL to show the slot options, or you can just use the mixer app.

### Other options

There are perhaps other ways of doing this as all as well, but for most users, specifying a custom stream ID for each guest is recommended. The use of a spreadsheet to keep track of invites for guests is a great way to manage this, and with the use of URL forwarding services, like [short.io](https://short.io/), you can also change a guest's VDO.Ninja invite link retroactively, via the shortening service.




# How to mirror a video while Full-Screen - For iPads and Teleprompters

To  get a video to mirror while full-screened, you have a few options.

One is to just full screen the browser itself; F11 on most desktops. The video itself may not be fullscreen, but the browser will be and should be pretty close to perfect. Adding [`&hideheader`](../advanced-settings/design-parameters/and-hideheader.md) can hide any menu bars, if there are any.

Another option that is undergoing experimental testing as of Sept 23rd 2020 is to use the [`&effects`](../source-settings/effects.md) option, with `&effects=2` applying a mirrored effect to the video before publishing the video.

**Push Link**\
[https://vdo.ninja/?push=SOMESTREAMID\&effects=2](https://vdo.ninja/?push=SOMESTREAMID\&effects=2)

**View Link**\
[https://vdo.ninja/?view=SOMESTREAMID](https://vdo.ninja/?view=SOMESTREAMID)

So by adding `&effects=2`, the video will be mirrored in a way that can be full screened.  There are some limitations with this approach still, but I'm curious to get your feedback.




---
description: Restarting Winsock on Windows
---

# How to restart your winsock

When troubleshooting network issues on Windows, one common step is to **reset Winsock** (Windows Sockets API).\
\
This can fix problems caused by corrupted network configuration, malware, or software conflicts. It can also be caused by ISPs that enforce content filtering or DPI (Deep Packet Inspection) that interacts badly with VPN/proxy drivers.&#x20;

***

### ⚠️ Before You Begin

* You need **Administrator privileges**.
* Resetting Winsock will remove all custom Layered Service Providers (LSPs).\
  If you use VPN software, firewalls, or proxy clients, you may need to reinstall or reconfigure them afterward.
* Always consider restarting your computer after making changes.

***

### Step 1: Open Command Prompt as Administrator

1. Press <kbd>Win</kbd> + <kbd>S</kbd>, type `cmd`.
2. Right-click **Command Prompt** and select **Run as administrator**.

***

### Step 2: Reset Winsock

Run the following command:

```sh
netsh winsock reset
```

You should see output similar to:

```
Successfully reset the Winsock Catalog.
You must restart the computer in order to complete the reset.
```

***

### Step 3: Restart Your Computer

To apply the reset, restart your computer:

```sh
shutdown /r /t 0
```

***

### Step 4: (Optional) Reset TCP/IP Stack

If you continue having issues, also reset the TCP/IP stack:

```sh
netsh int ip reset
```

***

### Step 5: Verify

After reboot:

* Test connectivity with `ping google.com`.
* Use `ipconfig /all` to confirm network adapter settings.
* Confirm that applications relying on network sockets (e.g., browsers, chat tools) are working properly.

***

### Quick Reference

| Action                       | Command               |
| ---------------------------- | --------------------- |
| Reset Winsock                | `netsh winsock reset` |
| Reset TCP/IP stack           | `netsh int ip reset`  |
| Restart immediately          | `shutdown /r /t 0`    |
| Verify adapter configuration | `ipconfig /all`       |
| Test network connection      | `ping google.com`     |

***

### When to Use

* After malware removal
* If network apps fail to connect
* If DNS or socket errors persist
* When VPN/proxy software breaks connectivity

***

✅ That’s it! Winsock should now be reset and your network connection refreshed.




---
description: >-
  There's a few ways currently to limit or control access to a VDO.Ninja link or
  room. More ways will be added in the future.
---

# How to selectively allow access

* One way to limit who can view your stream is with the [`&prompt`](../advanced-settings/settings-parameters/and-prompt.md) option. Essentially, it will ask the publisher of a stream if they wish to allow a certain viewer to connect.\
  \
  Details here:

{% content-ref url="../advanced-settings/settings-parameters/and-prompt.md" %}
[and-prompt.md](../advanced-settings/settings-parameters/and-prompt.md)
{% endcontent-ref %}

* Another option is to use the [`transfer` ](../getting-started/rooms/transfer-rooms.md)room function, as a director. So, invited guests join a public lobby room, and then you can transfer them from that public room to a private secret room with the director's transfer button. Since only the director knows which room the guest is transferred to, the guest can't invite others to the secret room, nor can they rejoin once they disconnect or get kicked.\
  A further benefit of the transfer room method is that the director can pre-screen guests by observing their webcam and audio stream, rather than relying on just a label name.
* Another option is to use [`&maxconnections`](../source-settings/and-maxconnections.md), limiting the number of connections to something low, like 1, can be sometimes useful in ensuring there is only one viewer for a simple push stream.
* Obviously VDO.Ninja also has [`&password`](../advanced-settings/setup-parameters/and-password.md) support, and that can be useful to have back to back guests in a room, where you simply need to change the password to switch to another guest with matching password. Room names can be all the same, since it's the password AND the room name that create a room's uniqueness.
* Another option is to use [Cloudflare's Zero Trust service](https://www.cloudflare.com/en-ca/zero-trust/), which can be used with a self-hosted version of VDO.Ninja. When a user tries to join with an invite link in this setup, Cloudflare's service will prompt them to sign in first, blocking access to the site. Only users signing in with an approved location, IP address, domain, or email can continue.
* There are additional link-shortner services with password and user-access controls, which can be used to mask an invite-link for VDO.Ninja, and limit who can acess the real link that way. These services can be dynamically updated, allowing you to change the VDO.Ninja invite link after sending out the shortened alias link, and even changing the user-access allowances.
* There are also services designed for queue or user lobby management, which can be used to on-the-fly redirect a selected user to a VDO.Ninja link. [https://app.invite.cam](https://app.invite.cam) is such a service being developed by the developers of VDO.Ninja for such a purpose, although it is still in a young state of development.

More options for user control will be added to VDO.Ninja in the future. Feedback can be provided via the Discord server ([https://discord.vdo.ninja](https://discord.vdo.ninja)) in the #feature-request channel.\




# How to send the audio/video output of one OBS to another OBS using VDO.Ninja

In this walk-through we demonstrate how to use VDO.Ninja to stream a low-latency video/audio stream from one OBS Studio to another remote OBS Studio.

{% embed url="https://youtu.be/Ze1q6Qof2r0" %}

#### Requirements

* OBS Studio
  * For some Linux or older systems, you may need a virtual camera plugin as well
* A virtual audio cable
  * For Windows, use VB-CABLE Virtual Audio
    * This is recommended software as it enables proper audio support
    * The software is Donationware
    * [https://www.vb-audio.com/Cable/](https://www.google.com/url?q=https://www.vb-audio.com/Cable/\&sa=D\&source=editors\&ust=1658835550127888\&usg=AOvVaw1mgCACykvK7pkvmteZz-Mj)
  * For macOS, you have a few choices:
    * [https://github.com/steveseguin/obsninja/wiki/FAQ#how-to-capture-audio-on-mac](https://www.google.com/url?q=https://github.com/steveseguin/obsninja/wiki/FAQ%23how-to-capture-audio-on-mac\&sa=D\&source=editors\&ust=1658835550128112\&usg=AOvVaw07GMfUuAZJy6FI8EYhOdd1)

#### Basic Workflow Diagram

Please find below a diagram explaining the basic premise of what we are intending to do in this guide. We will go through it all, one step at a time.

#### Step 0.

This guide assumes you have OBS installed, along with the other required software, though we shall briefly cover these initial installation steps now.

1. Install OBS Studio (or StreamLabs, etc)\
   [https://github.com/obsproject/obs-studio/releases/](https://github.com/obsproject/obs-studio/releases/)
2. Install the VB-Cable Virtual Audio device.\
   [https://vb-audio.com/Cable/](https://vb-audio.com/Cable/)

If you are on Mac, you can consider Loopback as a premium alternative option, if having problems.

#### Step 1

We now need to create a virtual webcam so we can connect OBS to VDO.Ninja. If we followed the initial software setup of Step 0 correctly, this should be all smooth sailing.

Just press START VIRTUAL CAM in OBS v26 or newer.

#### Step 2

We will now configure OBS to output audio from the Browser Source to the Virtual Audio Cable. In the OBS settings, under Advanced, we select the Monitoring Device to be our Virtual Audio device. (CABLE Input).

We also want to disable Windows audio ducking.

#### Step 3

In our last configuration step, we want to go into the Advanced Audio Properties in OBS. When there, we want to set up the Audio Monitoring setting to have any audio we want pushed to the Virtual Audio Cable to be set to MONITOR AND OUTPUT.

#### Step 4

We’re ready to now create our VDO.Ninja stream.

There are many ways to do this, but the EASIEST way is to go to VDO.Ninja, click Add your Camera to OBS, and select from the options OBS Virtualcam. This option will set you up with the default settings, such as with audio echo-cancellation on, although you can use URL parameters when visiting VDO.Ninja to customize the settings more.

{% hint style="info" %}
A popular advanced URL option at this point might be with the stereo flag, so visit [https://vdo.ninja/?stereo](https://vdo.ninja/?stereo) instead of just [https://vdo.ninja](https://vdo.ninja). You can also set your own custom stream ID values, so [https://vdo.ninja/?push=myCustomStreamId123](https://vdo.ninja/?push=myCustomStreamId123), and then give your remote OBS user the link [https://vdo.ninja/?view=myCustomStreamId123](https://vdo.ninja/?view=myCustomStreamId123)
{% endhint %}

#### Step 5

You can select the Virtual Audio Cable from the audio choices, or instead, you can select your local microphone or multiple audio input sources.

VDO.Ninja will auto-mix if more than one option is selected. Hold `CTRL` (or `command`) to select more than one option.

#### Step 6

Press the green button when ready.

You’ll see a preview of your video stream and a link. This link is what we want to send to our remote OBS studio as an input source.

We can modify this link if we wish to have higher bitrates, for example, [https://vdo.ninja/?view=streamID\&videobitrate=20000](https://vdo.ninja/?view=streamID\&videobitrate=20000) to set a target video bitrate of 20-mbps.

#### Step 7

We send this VDO.Ninja view URL to our remote OBS Studio computer and now we use it to ingest the feed into the OBS there.

To do this, we create a scene and then a Browser Source in OBS. Give it a name and we will fill out the details in the next step.

\

#### Step 8

In the properties for the Browser Source, we need to fill out a few fields and then hit OK.

* The URL needs to be set to the address we created earlier, i.e.: [https://vdo.ninja/?view=q3QCScW](https://vdo.ninja/?view=q3QCScW)
* Width needs to match the input video resolution, so likely 1280
* The height also needs to match, so likely 720
* _**Control audio via OBS**_ should be checked, for audio capture to function

SECRET TIP: Some links on VDO.Ninja can be dragged and dropped directly into OBS, avoiding the tedious parts of this step.

#### Step 9

Once you hit OK, the video should appear and auto-play within seconds. There should be no audio feedback if you selected the Control audio via OBS option.

Now we just need to stretch the video to fill the full scene. It should snap into place when full.

All done! And that should be it! Problems?

You can also ask for help on [Discord](https://discord.vdo.ninja/); usually help can be provided within minutes, if not usually within half a day.

### WHIP Output

Newer versions of OBS may also support WHIP output, which VDO.Ninja also supports. While the Virtual Camera might be the better option for many, details on [WHIP are here](../advanced-settings/whip-parameters/and-whip.md).




# How to set up a simple chat room

### Link

With this link you can set up a simple room to chat with friends:\
[https://vdo.ninja/?room=SOMEROOMNAME\&audiodevice=0\&videodevice=0\&chatbutton\&cleanoutput\&label](https://vdo.ninja/?room=SOMEROOMNAME\&audiodevice=0\&videodevice=0\&chatbutton\&cleanoutput\&label)

Alias:\
[https://vdo.ninja/?r=SOMEROOMNAME\&ad=0\&vd=0\&cb\&clean\&l](https://vdo.ninja/?r=SOMEROOMNAME\&ad=0\&vd=0\&cb\&clean\&l)\
\
Copy one of the two links above and change SOMEROOMNAME into a different name.

### Explanation

| Parameter                                                               | Explanation                                          |
| ----------------------------------------------------------------------- | ---------------------------------------------------- |
| [`&room=SOMEROOMNAME`](../general-settings/room.md)                     | Creates a room with a specified room name            |
| [`&audiodevice=0`](../source-settings/audiodevice.md)                   | Join with no audio input                             |
| [`&videodevice=0`](../source-settings/videodevice.md)                   | Join with no camera                                  |
| [`&chatbutton`](../general-settings/chatbutton.md)                      | Shows the chat button                                |
| [`&cleanoutput`](../advanced-settings/design-parameters/cleanoutput.md) | Keeps the room as clean as possible from UI elements |
| [`&label`](../general-settings/label.md)                                | Asks for a name when joining the room                |

 (2).png>)




---
description: Window sharing into Zoom with the Electron Capture app
---

# How to stream into Zoom without OBS

This guide will let you stream video from VDO.Ninja into Zoom as a window share (screen share).

Window sharing into Zoom allows for higher quality video into Zoom, but it may also result in lower frame rates. In this guide, we will assume you are using a VDO.Ninja group room with the desire to share a group scene with Zoom.  Sharing a group scene is not required though.

We will be using some software to make window sharing into Zoom more effective and clean. It is technically optionally.

#### Alternative approach for sharing video into Zoom

There is another guide for publishing from VDO.Ninja into Zoom using OBS Studio, which will have the video appear as a webcam in Zoom.  As a webcam source, the video will be smooth, but the resolution will be relatively low.\
\
Check out that guide below:

{% content-ref url="use-vdo.ninja-as-a-webcam-for-google-hangouts-zoom-and-more.md" %}
[use-vdo.ninja-as-a-webcam-for-google-hangouts-zoom-and-more.md](use-vdo.ninja-as-a-webcam-for-google-hangouts-zoom-and-more.md)
{% endcontent-ref %}

## Let's get started

### Step 1.

Go to [https://vdo.ninja/](https://vdo.ninja/)

### Step 2.

Click the Add Group Chat to OBS button.

If we were looking to just share our camera, and not a group scene, we could instead just use "Add your Camera to OBS". This guide will assume you are using a group scene though.

<figure><figcaption></figcaption></figure>

### Step 3.

Enter a room name.

Also, check "The director will be performing as well..", so that we can add our local camera and microphone to Zoom as well, if desired.

Then click the Enter the Room’s control Center.  We should then enter the “director’s control center”.

<figure><figcaption></figcaption></figure>

### Step 4.

In the director's control center, click the **COPY LINK** button for the **GUEST INVITE** box.

We want to send this link to our guests. The can use this link to **JOIN** the room with their camera.

If we want to join the room ourselves, we can also join as a guest, or we can do so as the director. Since our camera might be in use by Zoom currently, we can add ourselves a bit later on instead

<figure><figcaption></figcaption></figure>

### Step 5.

As guests join the room, they will see each other and be able to talk to each other.

The director of the room will also see each guest in the control center as they join.

<figure><figcaption></figcaption></figure>

### Step 6.

If we copy the **CAPTURE A SCENE LINK** in the director's room, and we open it in a new Chrome tab, we should be able to see all the guests in the room on that page.

<div align="left">

<figure><figcaption></figcaption></figure>

</div>

We can technically screen share this browser tab into Zoom, especially if we joined Zoom via Chrome also. We will continue this guide assuming you want to share into Zoom via the Electron Capture app however, which offers some performance advantages.

Since we will be using the Electron Capture app instead, we can close the scene link page in our browser after we validated that it works.  We will however still use the link we copied in an upcoming step.

### Step 7.

Next, we **download the** [**Electron Capture app**](../steves-helper-apps/electron-capture.md) – [https://github.com/steveseguin/electroncapture/releases](https://github.com/steveseguin/electroncapture/releases) (free)

The Electron Capture will let us share our video into Zoom without any borders and allow us to capture the audio. It also is optimized in resolution for maximum quality transfer from VDO.Ninja to Zoom.

### Step 8.

While it might be possible to capture audio another way, in this guide we will also use a Virtual Audio Cable application to bring the audio into Zoom.

Download and install VB Cable for Windows or macOS - [https://vb-audio.com/cable](https://vb-audio.com/Cable) (Donationware).

{% hint style="info" %}
**Tip**: When installing VB Cable, on PC, you will want to extract the files, and run the installer in administrator mode.
{% endhint %}

### Step 9.

Open the Electron Capture app.

We now can put our GROUP SCENE link in Electron Capture's top input field.&#x20;

The AUDIO OUTPUT DESTINATION needs to point to the Virtual Audio Cable.&#x20;

Once ready, press GO to load our VDO.Ninja video.

<figure><figcaption></figcaption></figure>

### Step 10.

All the audio should be sent to VB Cable, so you won't hear anything if setup correctly.

While you can resize the Electron Capture app, it's best to run it at 1280x720, which is the default resolution. You can change resolutions by right-clicking the app, along enabling other options, such as pinning the app on top of all others.

The top \~ 5% of the app is draggable, so you click on its top and move it around. The app is frameless, so when window-sharing it into Zoom, the output is clean and exactly 720p resolution.

### Step 11.

To share the video with Zoom, we screen share within Zoom, selecting the the Electron Capture app as the window we want to share.

### Step 12.

To share our Audio with Zoom, we change our MICROPHONE source in Zoom to be the VB Audio Cable.&#x20;

### Step 13.

Lastly, in Zoom, we ensure the ORIGINAL AUDIO SOURCE option (no echo cancellation), so we can capture the best audio quality possible.

### Step 14.

We can close the director's room if want to at this point, however keeping it open gives you control over the room, allowing you to kick and mute guests as needed.

If we want to include our own microphone and video to the stream, we can also do so via the Director's control center, clicking "enable director's microphone or video" button. We can select our microphone/video that way.

If we do close the director's control center though, we can still add our audio and video to the stream by joining the room as a guest, using the guest invite link we looked at previously.

<figure><figcaption></figcaption></figure>

### Need help?

If stuck, join our Discord support server at [https://discord.vdo.ninja](https://discord.vdo.ninja).

### More information

More on the **ROOM** here:

[Getting started: The Room (VDO Ninja Podcast ep02)](https://youtu.be/m1cIT1kdlEo)

More on **Advanced settings** here:

[Getting started: Power Parameters (VDO Ninja Podcast ep06)](https://youtu.be/l9BNTTNY08s)




---
description: >-
  Sending video with a transparent background, or with an alpha-channel (RGBA),
  is possible, but rather limited at the moment
---

# How to stream transparent video

If you wanted to stream yourself with a transparent background, or use a WebM file as a transparent effects overlay, it's possible with VDO.Ninja, however a bit limited still.

There's not many ways to bring transparent sources into the browser, nor are there many ways current to stream transparent video.

Lets list some of the methods that do work however:

## Webp-mode supports transparency

[`&webp`](../advanced-settings/view-parameters/webp.md) mode send webp images, which supports transparencies, instead of streaming video, which current does not support transparencies. It does however require quite a bit of CPU and network bandwidth, so its recommend to use low frame rates and low resolutions to avoid problems.

### Sending a video file via webp-mode

With this option, you can select a video file locally that contains a transparent background. WebM file formats support transparent backgrounds and can be opened by the browser.

[`&webp`](../advanced-settings/view-parameters/webp.md) mode supports transparency as noted, so we need to include that on the sender link. We also need to include `&alpha`, to tell the system that we want to include alpha channels (transparency), if possible.

[https://vdo.ninja/alpha/?webp\&push=rPJ5bEb\&fileshare\&alpha](https://vdo.ninja/alpha/?webp\&push=rPJ5bEb\&fileshare\&alpha)

On the viewer side, we can add [`&codec=webp`](../advanced-settings/view-parameters/codec.md#webp) to tell the system we want to pull the video stream as a webp series of images, rather than normal video. Images will transparencies will automatically include them in the display.

[https://vdo.ninja/alpha/?view=rPJ5bEb\&codec=webp](https://vdo.ninja/alpha/?view=rPJ5bEb\&codec=webp)

### Transparent webcam background via webp-mode

As with the above example, you can also send a webcam feed of a person, with their background removed.

Like above, we need to include `&alpha` and [`&webp`](../advanced-settings/view-parameters/webp.md), but we also need need to include [`&effects=5`](../source-settings/effects.md).

The goal here is to remove the background using the VDO.Ninja background removal tool, and then use a transparent image as the background, instead of a normal virtual background image. In the link below, we include a transparent pixel in the URL, so no external file is needed.

[https://vdo.ninja/alpha/?webp\&push=rPJ5bEb\&effects=5\&alpha\&webcam\&imagelist=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII%3D](https://vdo.ninja/alpha/?webp\&push=rPJ5bEb\&effects=5\&alpha\&webcam\&imagelist=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII%3D)

And like before, to view this stream with transparencies, we need to include [`&codec=webp`](../advanced-settings/view-parameters/codec.md#webp) on the view link.

[https://vdo.ninja/alpha/?view=rPJ5bEb\&codec=webp](https://vdo.ninja/alpha/?view=rPJ5bEb\&codec=webp)

This option is highly CPU intensive though; I'd recommend at least a fast 8-core system for this option, as you are doing both AI and heavy image processing workloads.

## Green screening

As with the above option, you can use the digital background effect ([`&effects=4`](../source-settings/effects.md), in this case) to replace your background in VDO.Ninja with a green solid color.

If using an application like OBS or vMix, during playback of the stream you can use a Chroma filter to remove the green background.

This option is pretty standard, and since it streams actual video instead of motion images, you can reduce CPU load, network bandwidth usage, maintain high frame rates, and achieve higher resolutions. There might be some green fringing on the final result, but there are ways to reduce that effect.\
\
 (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)

Another benefit of green screening is you can use an actual physical green screen as well. And this would work without needing AI effects and it would work on anything; not just a person.

When green screening, since color is so important, try using [`&codec=av1`](../advanced-settings/view-parameters/codec.md#av1) as well on the playback view link, as the AV1 codec tends to preserve colors better than [`&codec=h264`](../advanced-settings/view-parameters/codec.md#h264) or [`&codec=vp8`](../advanced-settings/view-parameters/codec.md#vp8), which are normally the defaults. With better colors, it should be easier to chroma-key out the green.

## Chunked mode - partially working

VDO.Ninja has a mode called Chunked, which can be activated on Chromium browsers by adding [`&chunked`](../newly-added-parameters/and-chunked.md) to the push URL.

When also used with `&alpha`, i.e.:

&#x20;[`https://vdo.ninja/alpha/?chunked&alpha`](https://vdo.ninja/alpha/?chunked\&alpha)

it will tell the browser to only select video codecs that can encode alpha channels. Normal WebRTC video streaming doesn't support alpha channels, but the chunked mode does. However, if no codec is available in your browser with alpha-channel support, then the chunked mode will fail or default back to a codec that doesn't support alpha channels.

At present, no codecs in Chrome seem to support alpha channels, but when that changes the feature will be automatically available for us.

### Not many transparent sources

At present, virtual cameras and screen shares are likely to not include alpha channels, so while you might try to screen share the [Electron Capture app](../steves-helper-apps/electron-capture.md), which has a transparent background, you'll still have the captured video having a black background.

I'm hoping this isn't the case in the future with Chrome and other Chromium browsers, but I'm not entirely sure.

### Raspberry.Ninja and OBS WHIP output - future possiblities

I've not really sure about this, but you can force video into [Raspberry.Ninja](../steves-helper-apps/raspberry.ninja/), with transparent backgrounds, and VDO.Ninja will play them back. In my previous testing, Chrome refused to play back transparent video streams from Raspberry.Ninja with transparencies, dropping them for black backgrounds instead, but this might change in the future.

If this does change, you might then be able to use OBS as well for streaming transparent video to VDO.Ninja. Or perhaps you'll be able to go from Raspberry.Ninja into OBS via WHEP at some point, but these are all not yet available and are likely years away from being materialized.




---
description: How to embed VDO.Ninja into your own website with the IFRAME API
---

# How to embed VDO.Ninja into a site with iFrames

[VDO.Ninja](https://vdo.ninja/) offers here a simple and free solution to quickly enable real-time video streaming in their websites. VDON wishes to make live video streaming development accessible to any developer, even novices, yet still remain flexible and powerful.

While VDO.Ninja does offer source-code to customize the application and UI at a low level, this isn't for beginners and it is rather hard to maintain. As well, due to the complexity of video streaming in the web, typical approaches for offering API access isn't quite feasible either.

The solution decided on isn't an SDK framework, but rather the use of embeddable _IFrames_ and a corresponding bi-directional IFrame API. An [IFrame](https://www.w3schools.com/tags/tag_iframe.ASP) allows us to embed a webpage inside a webpage, including VDO.Ninja into your own website.

Modern web browsers allow the parent website to communicate with the child webpage, giving a high-level of control to a developer, while also abstracting the complex code and hosting requirements. Functionality, we can make an VDON video stream act much like an HTML video element tag, where you can issue commands like play, pause, or change video sources with ease.

Creating an VDON iframe can be done in HTML or programmatically with JavaScript like so:

```
const iframe = document.createElement("iframe");
iframe.allow = "document-domain;encrypted-media;sync-xhr;usb;web-share;cross-origin-isolated;midi *;geolocation;camera *;microphone *;fullscreen;picture-in-picture;display-capture;accelerometer;autoplay;gyroscope;screen-wake-lock;";
iframe.src = "https://vdo.ninja/?push=vhX5PYg&cleanoutput&transparent";
```

You can also make an VDO.Ninja without Javascript, using just HTML, like:

`<iframe allow="document-domain;encrypted-media;sync-xhr;usb;web-share;cross-origin-isolated;midi *;geolocation;camera *;microphone *;fullscreen;picture-in-picture;display-capture;accelerometer;autoplay;gyroscope;screen-wake-lock;" src="https://vdo.ninja/?push=vhX5PYg&cleanoutput&transparent"></iframe>`\
\
Adding that IFrame to the DOM will reveal a simple page for accessing for a user to select and share their webcam. For a developer wishing to access a remote guest's stream, this makes the ingestion of that stream into production software like OBS Studios very easy. The level of customization and control opens up opportunities, such as a pay-to-join audience option for a streaming interactive broadcast experience.

An example of how this API is used by VDO.Ninja is with its Internet Speedtest, which has two VDO.Ninja IFrames on a single page. One IFrame feeds video to the other IFrame, and the speed at which it does this is a measure of the system's performance. Detailed stats of the connection are made available to the parent window, which displays the results. [https://vdo.ninja/speedtest](https://vdo.ninja/speedtest)

More community-contributed IFrame examples can be found here:\
[https://github.com/steveseguin/vdoninja/tree/master/examples](https://github.com/steveseguin/vdoninja/tree/master/examples)

A sandbox of options is available at this page, too: [https://vdo.ninja/iframe](https://vdo.ninja/iframe) You can enter an VDO.Ninja URL in the input box to start using it. For developers, viewing the source of that page will reveal examples of how all the available functions work, along with a way to test and play with each of them. You can also see here for the source-code on GitHub:\
[https://github.com/steveseguin/vdoninja/blob/master/iframe.html](https://github.com/steveseguin/vdoninja/blob/master/iframe.html)

I also have an example of how you can transfer virtually any data (JSON, text, small images) via the IFrame API with just a few lines of code here:\
[https://gist.github.com/steveseguin/15bba03d1993c88d0bd849f7749ea625](https://gist.github.com/steveseguin/15bba03d1993c88d0bd849f7749ea625) It's a pretty awesome example of how you can securely communicate peer to peer online with virtually zero effort and with no cost.

There's dozens of other examples of how the IFrame API can be used to communicate via p2p, easily with any website, such as controlling PowerPoint remotely, but here's an example of how to use it to control OBS Studio remotely. [https://github.com/steveseguin/sample-p2p-tunnel](https://github.com/steveseguin/sample-p2p-tunnel)

Please note that since VDO.Ninja requires SSL to be strictly enabled site wide, any website you embed a VDO.Ninja IFrame into also will require SSL enabled site wide. Using a service like Cloudflare can provide SSL-enabled caching for websites to make this fairly easy to do.

Please also note that there we are allowing numerous permissions when setting up our IFRAME. You may need to adjust these for your use case; `allow="camera *;microphone *;"` for example.

Something else to note about this IFrame API is that it can not only be controlled via URL parameters given to the IFrame _src_ URL, but also using `postMessage` and `addEventListener` methods of the browser. The later is used to dynamically control VDO.Ninja, while the former is used to initiate the instance to a desired state.

Some of the more interesting ones primarily for IFrame users might include:

* [`&webcam`](../source-settings/and-webcam.md)
* [`&screenshare`](../source-settings/screenshare.md)
* [`&videodevice`](../source-settings/videodevice.md)`=`1 or 0
* [`&audiodevice`](../source-settings/audiodevice.md)`=`1 or 0
* [`&autostart`](../source-settings/and-autostart.md)
* [`&chroma`](../advanced-settings/design-parameters/chroma.md)
* [`&transparent`](../advanced-settings/design-parameters/and-transparent.md)
* As for API, allow for dynamic messaging, below are examples of the options available:
* Mute Speaker
* Mute Mic
* Disconnect
* Change Video Bitrate
* Reload the page
* Change the volume
* Request detailed connection stats
* Access the loudness level of the audio
* Send/Recieve a chat message to other connected guests
* Get notified when there is a video connection

As for the actually details for methods and options available to dynamically control child VDON IFrame, they are primarily kept up to via the iframe.html file that is mentioned previously. see: _iframe.html_. Below is a snippet from that file:

```javascript
let button = document.createElement("button");
button.innerHTML = "Mute Speaker";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "mute": true
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Un-Mute Speaker";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "mute": false
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Toggle Speaker";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "mute": "toggle"
    }, '*');
}
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Mute Mic";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "mic": false
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Un-Mute Mic";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "mic": true
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Toggle Mic";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "mic": "toggle"
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Disconnect";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "close": true
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Low Bitrate";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "bitrate": 30
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "High Bitrate";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "bitrate": 5000
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Default Bitrate";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "bitrate": -1
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Reload";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "reload": true
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "50% Volume";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "volume": 0.5
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "100% Volume";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "volume": 1.0
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Request Stats";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "getStats": true
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Request Loudness Levels";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "getLoudness": true
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Stop Sending Loudness Levels";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "getLoudness": false
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "Say Hello";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "sendChat": "Hello!"
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "previewWebcam()";
button.onclick = () => {
    iframe.contentWindow.postMessage({
        "function": "previewWebcam"
    }, '*');
};
iframeContainer.appendChild(button);

button = document.createElement("button");
button.innerHTML = "CLOSE IFRAME";
button.onclick = () => {
    iframeContainer.parentNode.removeChild(iframeContainer);
};
iframeContainer.appendChild(button);

// As for listening events, where the parent listens for responses or events from the VDON child frame:

// //////////  LISTEN FOR EVENTS

const eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
const eventer = window[eventMethod];
const messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";

eventer(messageEvent, function (e) {
    if (e.source !== iframe.contentWindow) {
        return
    } // reject messages send from other iframes

    if ("stats" in e.data) {
        const outputWindow = document.createElement("div");

        let out = `<br />total_inbound_connections:${
            e.data.stats.total_inbound_connections
        }`;
        out += `<br />total_outbound_connections:${
            e.data.stats.total_outbound_connections
        }`;

        for (const streamID in e.data.stats.inbound_stats) {
            out += `<br /><br /><b>streamID:</b> ${streamID}<br />`;
            out += printValues(e.data.stats.inbound_stats[streamID]);
        }

        outputWindow.innerHTML = out;
        iframeContainer.appendChild(outputWindow);
    }

    if ("gotChat" in e.data) {
        const outputWindow = document.createElement("div");
        outputWindow.innerHTML = e.data.gotChat.msg;
        outputWindow.style.border = "1px dotted black";
        iframeContainer.appendChild(outputWindow);
    }

    if ("action" in e.data) {
        const outputWindow = document.createElement("div");
        outputWindow.innerHTML = `child-page-action: ${
            e.data.action
        }<br />`;
        outputWindow.style.border = "1px dotted black";
        iframeContainer.appendChild(outputWindow);
    }

    if ("loudness" in e.data) {
        console.log(e.data);
        if (document.getElementById("loudness")) {
            outputWindow = document.getElementById("loudness");
        } else {
            const outputWindow = document.createElement("div");
            outputWindow.style.border = "1px dotted black";
            iframeContainer.appendChild(outputWindow);
            outputWindow.id = "loudness";
        }
        outputWindow.innerHTML = "child-page-action: loudness<br />";
        for (const key in e.data.loudness) {
            outputWindow.innerHTML += `${key} Loudness: ${
                e.data.loudness[key]
            }\n`;
        }
        outputWindow.style.border = "1px black";

    }
});
```

This VDO.Ninja API is developed and expanded based on user feedback and requests. It is by no means complete, but it is getting better every week.

### Transparency

Setting the `allowtransparency` attribute on the IFrame to `true` will allow for the contents to be transparent. You can then make VDO.Ninja transparent by adding `&transparent` to the URL, which sets the page's background to `rgba(0,0,0,0)`.&#x20;

https://vdo.ninja/iframe can demonstrate this by opening https://vdo.ninja/?transparent with it.

### Advanced IFrame functionality

There's some users who wish to have an SDK instead of an IFrame API. While an SDK may happen eventually, currently the IFram API is surprisingly capable.

If you wish to use your own video mixer logic for example, you can disable the existing auto-mixer logic that currently exists using the [`&manual`](../advanced-settings/view-parameters/manual.md) flag. You can then access the `srcObject` of each of the video elements in VDO.Ninja and pull those streams into the parent frame to manipulate or to connect to the parent DOM.&#x20;

If you aren't self-hosting the code, you may run into cross origin permission issues or limitations on cross-origin permissions with certain features. You can get around these issues usually by hosting VDO.Ninja as a subdomains though, in certain cases at least, along with the correct web hosting settings set.

[https://javascript.info/cross-window-communication#windows-on-subdomains-document-domain](https://javascript.info/cross-window-communication#windows-on-subdomains-document-domain)

See the video below for an advanced demo of the IFRAME API and how videos hosted within VDO.Ninja can be accessed and manipulated by the parent window. Video works well in this fashion; pulling audio from the IFRAME is a bit trickier however. \
\
\[update:  document.domain or such is a bit depreciated now, and while it is possible to use a sub-domain still, you'll need to specify certain headers and permissions with your webserver to allow for it.  https://versus.cam for example uses vdo.ninja as a subdomain to access frames across the IFRAME API]

{% embed url="https://www.youtube.com/watch?v=SqbufszHKi4&feature=youtu.be" %}

### Basic full window IFRAME control

Below is a simple code example of a website that can use VDO.Ninja as normal, full-window, while having a wrapper around it that controls it using the IFrame API.

It also will query the IFRAME every second for detailed state of the current setup, such as who is connected and visible.

This approach can allow you to do very advanced and dynamic configurations for VDO.Ninja, which might not be possible with the normal HTTPS/WSS API or URL parameters. Code injection is also supported, so there's no limit really to what you can do. If you would like to use VDO.Ninja with a custom API or inside an application as a webview, this is also a simple example of the concept.

```
<style>body,iframe{width:100%;height:100%;margin:0;padding:0;border:0;background-color:#0000;}</style><body></body><script>

var IFRAMEWINDOW = document.createElement("iframe"); // create VDO.Ninja in an IFRAME
IFRAMEWINDOW.src = "https://vdo.ninja/alpha/?scene&transparent&room=sssss123";

IFRAMEWINDOW.onload = function(){ // start polling shortly after we connect
    setInterval(function(){
            IFRAMEWINDOW.contentWindow.postMessage({"getDetailedState":true}, "*");  // get details every second
        },1000);
}
document.body.appendChild(IFRAMEWINDOW); // add the vdo.ninja element to the page, so its active/visible

window.addEventListener("message", (e) => {
  if (e.source != IFRAMEWINDOW.contentWindow){return} // only listen for vdo.ninja events
  console.log(e.data);// print the messages inbound to the console log
});
</script>
```

### WebViews

The IFrame API is is also a WebView API, using the same concept of listening for events and post-messaging into the VDO.Ninja window.

WebViews are available within iOS and Android native apps, Electron.js apps, and other applications, like Unity or Unreal.

This is a great way to configure, edit, listen to, and control VDO.Ninja, without a web or MIDI API.

### Raw video and audio transport

It's possible to transmit uncompressed video frames and audio data from VDO.Ninja to the parent window using the post-mesasging API. This allows video playback to happen outside the IFrame itself, using your own custom mixing logic. See[ https://versus.cam](https://versus.cam) for a code example; the website is on Steve's GitHub for reference.  Please note, this may require a custom deployment of VDO.Ninja's website code (SameOriginPolicy), and likely will also require a recent Chromium-based browser to use.

### Securing your stream ID

Using the \&audience option, you can have a consistent stream ID on your website that only you can publish to. Great for using VDO.Ninja as a small scale broadcast player on a personal website.

{% content-ref url="../advanced-settings/setup-parameters/and-audience.md" %}
[and-audience.md](../advanced-settings/setup-parameters/and-audience.md)
{% endcontent-ref %}

### All to happy to support the IFRAME API

Please feel free to follow me in the VDO.Ninja Discord channel ([discord.vdo.ninja](https://discord.com/invite/T4xpQVv)) where I post news about updates and listen to requests. The upcoming version of VDO.Ninja is also often hosted at [https://vdo.ninja/beta](https://vdo.ninja/beta), where you can explore new features and help crush any unexpected bugs.

I am keen to continue to support the IFrame API, so please reach out if you have questions or requests.

-steve




---
description: Transmitting Drawing Data Between Clients with VDO.Ninja IFRAMES
---

# Create custom drawing app

## VDO.Ninja IFRAME API: Transmitting Drawing Data Between Clients

This guide explains how to use the VDO.Ninja IFRAME API to send drawing data (or any custom data) between clients using peer-to-peer (P2P) data channels.

### Understanding the Data Channel

VDO.Ninja allows you to send arbitrary data between connected clients using its P2P data channels. This feature enables applications like:

* Custom drawing/annotation tools
* Chat systems
* Control signals
* Sensor data exchange
* Any other custom data payloads

The creators of VDO.Ninja use VDO.Ninja's data-channel functionality in many of their other applications and services, including Social Stream Ninja that processes hundreds of messages per minute per peer connection.

### Basic Setup

First, set up your VDO.Ninja iframe as described in the basic documentation:

```javascript
// Create the iframe element
var iframe = document.createElement("iframe");

// Set necessary permissions
iframe.allow = "camera;microphone;fullscreen;display-capture;autoplay;";

// Set the source URL (your VDO.Ninja room)
iframe.src = "https://vdo.ninja/?room=your-room-name&cleanoutput";

// Add the iframe to your page
document.getElementById("container").appendChild(iframe);
```

### Setting Up Event Listeners

To receive data from other clients, set up an event listener for messages from the iframe:

```javascript
// Set up event listener (cross-browser compatible)
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";

// Connected peers storage
var connectedPeers = {};

// Add the event listener
eventer(messageEvent, function(e) {
    // Make sure the message is from our VDO.Ninja iframe
    if (e.source != iframe.contentWindow) return;
    
    // Process connection events to track connected peers
    if ("action" in e.data) {
        if (e.data.action === "guest-connected" && e.data.streamID) {
            // Store connected peer information
            connectedPeers[e.data.streamID] = e.data.value?.label || "Guest";
            console.log("Guest connected:", e.data.streamID, "Label:", connectedPeers[e.data.streamID]);
        } 
        else if (e.data.action === "push-connection" && e.data.value === false && e.data.streamID) {
            // Remove disconnected peers
            console.log("Guest disconnected:", e.data.streamID);
            delete connectedPeers[e.data.streamID];
        }
    }
    
    // Handle received data
    if ("dataReceived" in e.data) {
        // Process any custom data received from peers
        console.log("Data received:", e.data.dataReceived);
        
        // If our custom data format is detected
        if ("overlayNinja" in e.data.dataReceived) {
            processReceivedData(e.data.dataReceived.overlayNinja, e.data.UUID);
        }
    }
}, false);

function processReceivedData(data, senderUUID) {
    // Process the data based on your application's needs
    console.log("Processing data from UUID:", senderUUID, "Data:", data);
    
    // Example: Handle drawing data
    if (data.drawingData) {
        updateDrawingCanvas(data.drawingData);
    }
}
```

### Sending Data to Peers

#### Sending to All Connected Peers

Use this approach to broadcast data to all connected peers:

```javascript
function sendDataToAllPeers(data) {
    // Create the data structure
    var payload = {
        drawingData: data  // Your custom drawing data
    };
    
    // Send to all peers
    iframe.contentWindow.postMessage({
        sendData: { overlayNinja: payload },
        type: "pcs"  // Use peer connection for reliability
    }, "*");
}
```

#### Sending to a Specific Peer by UUID

Use this approach to send data to a specific peer identified by UUID:

```javascript
function sendDataToPeer(data, targetUUID) {
    // Create the data structure
    var payload = {
        drawingData: data  // Your custom drawing data
    };
    
    // Send to specific UUID
    iframe.contentWindow.postMessage({
        sendData: { overlayNinja: payload },
        type: "pcs",
        UUID: targetUUID
    }, "*");
}
```

#### Sending to Peers with Specific Labels

Use this approach to send data to all peers with a specific label:

```javascript
function sendDataByLabel(data, targetLabel) {
    // Create the data structure
    var payload = {
        drawingData: data  // Your custom drawing data
    };
    
    // Iterate through connected peers to find those with matching label
    var keys = Object.keys(connectedPeers);
    for (var i = 0; i < keys.length; i++) {
        try {
            var UUID = keys[i];
            var label = connectedPeers[UUID];
            if (label === targetLabel) {
                // Send to this specific peer
                iframe.contentWindow.postMessage({
                    sendData: { overlayNinja: payload },
                    type: "pcs",
                    UUID: UUID
                }, "*");
            }
        } catch (e) {
            console.error("Error sending to peer:", e);
        }
    }
}
```

#### Sending to a Peer by StreamID

Use this approach when you know the streamID but not the UUID:

```javascript
function sendDataByStreamID(data, streamID) {
    // Create the data structure
    var payload = {
        drawingData: data  // Your custom drawing data
    };
    
    // Send to specific streamID
    iframe.contentWindow.postMessage({
        sendData: { overlayNinja: payload },
        type: "pcs",
        streamID: streamID
    }, "*");
}
```

### Drawing-Specific Implementation

For transmitting drawing data specifically, you'll need to:

1. Create a drawing canvas on your page
2. Capture drawing events
3. Format the data appropriately
4. Send the data to peers
5. Process and render received drawing data

Here's a simplified example:

```javascript
// 1. Set up a drawing canvas
const canvas = document.createElement('canvas');
canvas.width = 640;
canvas.height = 480;
document.getElementById('drawing-container').appendChild(canvas);
const ctx = canvas.getContext('2d');

// Drawing state
let isDrawing = false;
let lastX = 0;
let lastY = 0;
let currentPath = [];

// 2. Capture drawing events
canvas.addEventListener('mousedown', (e) => {
    isDrawing = true;
    [lastX, lastY] = [e.offsetX, e.offsetY];
    
    // Start a new path
    currentPath = [];
    // Normalize coordinates (0-1 range)
    const point = {
        x: lastX / canvas.width,
        y: lastY / canvas.height
    };
    currentPath.push(point);
});

canvas.addEventListener('mousemove', (e) => {
    if (!isDrawing) return;
    
    // Draw locally
    ctx.beginPath();
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(e.offsetX, e.offsetY);
    ctx.stroke();
    
    // Store normalized point
    const point = {
        x: e.offsetX / canvas.width,
        y: e.offsetY / canvas.height
    };
    currentPath.push(point);
    
    [lastX, lastY] = [e.offsetX, e.offsetY];
});

canvas.addEventListener('mouseup', () => {
    if (isDrawing) {
        isDrawing = false;
        
        // 3 & 4. Format and send the path data
        if (currentPath.length > 1) {
            // Send the complete path
            sendDrawingData(currentPath);
        }
        
        // Reset current path
        currentPath = [];
    }
});

// Send drawing data to all peers
function sendDrawingData(pathPoints) {
    // Format the data as a path
    const drawingData = {
        t: 'path',  // type: path
        p: pathPoints
    };
    
    // Send to all peers
    iframe.contentWindow.postMessage({
        sendData: { overlayNinja: { drawingData: drawingData } },
        type: "pcs"
    }, "*");
}

// 5. Process received drawing data
function processReceivedData(data, senderUUID) {
    if (data.drawingData && data.drawingData.t === 'path') {
        const pathPoints = data.drawingData.p;
        
        // Render the received path
        if (pathPoints && pathPoints.length > 1) {
            ctx.beginPath();
            
            // Convert normalized coordinates back to canvas coordinates
            const startX = pathPoints[0].x * canvas.width;
            const startY = pathPoints[0].y * canvas.height;
            ctx.moveTo(startX, startY);
            
            for (let i = 1; i < pathPoints.length; i++) {
                const x = pathPoints[i].x * canvas.width;
                const y = pathPoints[i].y * canvas.height;
                ctx.lineTo(x, y);
            }
            
            ctx.stroke();
        }
    }
}
```

### Advanced Drawing Commands

You can implement special drawing commands like clear, undo, etc.:

```javascript
// Clear the drawing canvas
function clearDrawing() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // Send clear command to all peers
    iframe.contentWindow.postMessage({
        sendData: { overlayNinja: { drawingData: "clear" } },
        type: "pcs"
    }, "*");
}

// Undo last drawing action
function undoLastDrawing() {
    // Local undo logic...
    
    // Send undo command to all peers
    iframe.contentWindow.postMessage({
        sendData: { overlayNinja: { drawingData: "undo" } },
        type: "pcs"
    }, "*");
}
```

### Using VDO.Ninja's Built-in Drawing System

VDO.Ninja has a built-in drawing system you can leverage if you prefer not to implement your own:

```javascript
// Send drawing data using VDO.Ninja's built-in format
function sendVDONinjaDrawing(drawingData) {
    iframe.contentWindow.postMessage({
        draw: drawingData,  // Can be an object with drawing data or commands like "clear", "undo"
        type: "pcs",
        UUID: targetUUID  // Optional: specific target
    }, "*");
}

// Clear VDO.Ninja's drawing
function clearVDONinjaDrawing() {
    iframe.contentWindow.postMessage({
        draw: "clear",
        type: "pcs"
    }, "*");
}

// Undo last drawing action in VDO.Ninja
function undoVDONinjaDrawing() {
    iframe.contentWindow.postMessage({
        draw: "undo",
        type: "pcs"
    }, "*");
}
```

### Complete Example: Drawing Application

Here's a more complete example of a drawing application using the data channel:

```javascript
// Create interface elements
const container = document.createElement('div');
container.id = 'app-container';
document.body.appendChild(container);

// Create VDO.Ninja iframe
const iframe = document.createElement('iframe');
iframe.allow = "camera;microphone;fullscreen;display-capture;autoplay;";
iframe.src = "https://vdo.ninja/?room=drawing-demo&cleanoutput";
iframe.style.width = "640px";
iframe.style.height = "360px";
container.appendChild(iframe);

// Create drawing canvas
const canvasContainer = document.createElement('div');
canvasContainer.style.position = 'relative';
container.appendChild(canvasContainer);

const canvas = document.createElement('canvas');
canvas.width = 640;
canvas.height = 360;
canvas.style.border = '1px solid black';
canvasContainer.appendChild(canvas);
const ctx = canvas.getContext('2d');
ctx.strokeStyle = 'red';
ctx.lineWidth = 3;
ctx.lineCap = 'round';

// Create controls
const controlsDiv = document.createElement('div');
controlsDiv.style.margin = '10px 0';
container.appendChild(controlsDiv);

const clearBtn = document.createElement('button');
clearBtn.textContent = 'Clear';
clearBtn.onclick = clearDrawing;
controlsDiv.appendChild(clearBtn);

const undoBtn = document.createElement('button');
undoBtn.textContent = 'Undo';
undoBtn.onclick = undoLastDrawing;
controlsDiv.appendChild(undoBtn);

// Track connected peers
const connectedPeers = {};
const drawingHistory = [];
let currentPath = [];
let isDrawing = false;

// Set up event handlers for the canvas
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', endDrawing);
canvas.addEventListener('mouseout', endDrawing);

function startDrawing(e) {
    isDrawing = true;
    const x = e.offsetX / canvas.width;
    const y = e.offsetY / canvas.height;
    currentPath = [{ x, y }];
    
    ctx.beginPath();
    ctx.moveTo(e.offsetX, e.offsetY);
}

function draw(e) {
    if (!isDrawing) return;
    
    const x = e.offsetX / canvas.width;
    const y = e.offsetY / canvas.height;
    currentPath.push({ x, y });
    
    ctx.lineTo(e.offsetX, e.offsetY);
    ctx.stroke();
}

function endDrawing() {
    if (!isDrawing) return;
    isDrawing = false;
    
    if (currentPath.length > 1) {
        // Save path to history
        drawingHistory.push(currentPath);
        
        // Send path to peers
        sendDrawingData(currentPath);
    }
    
    currentPath = [];
}

function clearDrawing() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawingHistory.length = 0;
    
    // Send clear command
    iframe.contentWindow.postMessage({
        sendData: { overlayNinja: { drawingData: "clear" } },
        type: "pcs"
    }, "*");
}

function undoLastDrawing() {
    if (drawingHistory.length === 0) return;
    
    // Remove the last path
    drawingHistory.pop();
    
    // Redraw everything
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawingHistory.forEach(path => {
        if (path.length > 1) {
            ctx.beginPath();
            ctx.moveTo(path[0].x * canvas.width, path[0].y * canvas.height);
            
            for (let i = 1; i < path.length; i++) {
                ctx.lineTo(path[i].x * canvas.width, path[i].y * canvas.height);
            }
            
            ctx.stroke();
        }
    });
    
    // Send undo command
    iframe.contentWindow.postMessage({
        sendData: { overlayNinja: { drawingData: "undo" } },
        type: "pcs"
    }, "*");
}

function sendDrawingData(pathPoints) {
    const drawingData = {
        t: 'path',
        p: pathPoints,
        c: 'red',  // Color
        w: 3       // Width
    };
    
    iframe.contentWindow.postMessage({
        sendData: { overlayNinja: { drawingData: drawingData } },
        type: "pcs"
    }, "*");
}

// Set up the event listener
const eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
const eventer = window[eventMethod];
const messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";

eventer(messageEvent, function(e) {
    // Make sure the message is from our VDO.Ninja iframe
    if (e.source != iframe.contentWindow) return;
    
    // Process connection events
    if ("action" in e.data) {
        if (e.data.action === "guest-connected" && e.data.streamID) {
            connectedPeers[e.data.streamID] = e.data.value?.label || "Guest";
            console.log("Guest connected:", e.data.streamID, "Label:", connectedPeers[e.data.streamID]);
            
            // Send current drawing state to new peer
            if (drawingHistory.length > 0) {
                iframe.contentWindow.postMessage({
                    sendData: { overlayNinja: { drawingHistory: drawingHistory } },
                    type: "pcs",
                    UUID: e.data.streamID
                }, "*");
            }
        } 
        else if (e.data.action === "push-connection" && e.data.value === false && e.data.streamID) {
            console.log("Guest disconnected:", e.data.streamID);
            delete connectedPeers[e.data.streamID];
        }
    }
    
    // Handle received data
    if ("dataReceived" in e.data) {
        if ("overlayNinja" in e.data.dataReceived) {
            const data = e.data.dataReceived.overlayNinja;
            
            // Process drawing data
            if (data.drawingData) {
                if (data.drawingData === "clear") {
                    // Clear command
                    ctx.clearRect(0, 0, canvas.width, canvas.height);
                    drawingHistory.length = 0;
                }
                else if (data.drawingData === "undo") {
                    // Undo command
                    if (drawingHistory.length > 0) {
                        drawingHistory.pop();
                        
                        // Redraw everything
                        ctx.clearRect(0, 0, canvas.width, canvas.height);
                        drawingHistory.forEach(path => {
                            if (path.length > 1) {
                                ctx.beginPath();
                                ctx.moveTo(path[0].x * canvas.width, path[0].y * canvas.height);
                                
                                for (let i = 1; i < path.length; i++) {
                                    ctx.lineTo(path[i].x * canvas.width, path[i].y * canvas.height);
                                }
                                
                                ctx.stroke();
                            }
                        });
                    }
                }
                else if (data.drawingData.t === 'path') {
                    // New path
                    const pathPoints = data.drawingData.p;
                    
                    // Add to history
                    drawingHistory.push(pathPoints);
                    
                    // Draw it
                    if (pathPoints && pathPoints.length > 1) {
                        ctx.beginPath();
                        ctx.moveTo(pathPoints[0].x * canvas.width, pathPoints[0].y * canvas.height);
                        
                        for (let i = 1; i < pathPoints.length; i++) {
                            ctx.lineTo(pathPoints[i].x * canvas.width, pathPoints[i].y * canvas.height);
                        }
                        
                        ctx.stroke();
                    }
                }
            }
            
            // Handle initial state sync
            if (data.drawingHistory) {
                // Clear current state
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                
                // Apply all paths from history
                data.drawingHistory.forEach(path => {
                    if (path.length > 1) {
                        ctx.beginPath();
                        ctx.moveTo(path[0].x * canvas.width, path[0].y * canvas.height);
                        
                        for (let i = 1; i < path.length; i++) {
                            ctx.lineTo(path[i].x * canvas.width, path[i].y * canvas.height);
                        }
                        
                        ctx.stroke();
                    }
                });
                
                // Update local history
                drawingHistory.length = 0;
                drawingHistory.push(...data.drawingHistory);
            }
        }
    }
}, false);
```

### Best Practices

1. **Data Structure**: Use a clear, consistent data structure for your payloads
2. **Normalization**: Normalize canvas coordinates (0-1 range) to ensure consistent display across different screen sizes
3. **Throttling**: Consider throttling frequent events like mouse movements to reduce data transmission
4. **Error Handling**: Always include try/catch blocks when sending or processing data
5. **State Synchronization**: When new peers join, send them the current state
6. **UUID vs StreamID**: Use UUID for reliable targeting; StreamIDs change when connections restart
7. **Connection Status**: Monitor connection and disconnection events to maintain a list of active peers

### Common Types of Data to Send

* **Drawing Paths**: Arrays of points representing drawing strokes
* **Commands**: Clear, undo, change color, change brush size
* **Annotations**: Text or shapes to overlay on videos
* **Control Signals**: Camera directions, audio levels, recording commands
* **Chat Messages**: Text messages between users
* **Sensor Data**: Device orientation, location, acceleration

### Troubleshooting

* **Data Not Arriving**: Check that you're using the correct UUID or streamID
* **Timing Issues**: Ensure your iframe is fully loaded before sending messages
* **Cross-Origin Issues**: Make sure your security settings allow communication
* **Format Errors**: Verify your data structure matches what receivers expect
* **Performance Problems**: Large data payloads can cause lag; consider optimizing

By following this guide, you should be able to implement custom drawing tools or any other data-sharing features using VDO.Ninja's P2P data channels.




# Detecting User Joins / Disconnects

## Understanding the VDO.Ninja IFRAME API: Detecting User Joins and Disconnects

The VDO.Ninja IFRAME API allows websites to embed and interact with VDO.Ninja streams. One of the most useful features is the ability to detect when users join or disconnect from your stream through event messaging. This guide will explain how to implement this functionality in your own projects.

### How the IFRAME API Works

VDO.Ninja's IFRAME API uses the browser's `postMessage` API to communicate between your parent website and the embedded VDO.Ninja iframe. This allows you to:

1. Send commands to control the VDO.Ninja instance
2. Receive events and data from the VDO.Ninja instance

### Setting Up the Basic Structure

First, you need to create an iframe that loads VDO.Ninja:

```javascript
// Create the iframe element
var iframe = document.createElement("iframe");

// Set necessary permissions
iframe.allow = "camera;microphone;fullscreen;display-capture;autoplay;";

// Set the source URL (your VDO.Ninja room)
iframe.src = "https://vdo.ninja/?room=your-room-name&cleanoutput";

// Add the iframe to your page
document.getElementById("container").appendChild(iframe);
```

### Setting Up the Event Listener

To detect joins and disconnects, you need to set up an event listener for messages from the iframe:

```javascript
// Set up event listener (cross-browser compatible)
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";

// Add the event listener
eventer(messageEvent, function (e) {
    // Make sure the message is from our VDO.Ninja iframe
    if (e.source != iframe.contentWindow) return;
    
    // Log the data for debugging
    console.log(e.data);
    
    // Process specific events
    if ("action" in e.data) {
        // Handle different actions
        handleAction(e.data);
    }
}, false);
```

### Detecting User Joins and Disconnects

The key events to watch for are:

#### Guest Connections

```javascript
function handleAction(data) {
    if (data.action === "guest-connected") {
        // A new guest has connected
        console.log("Guest connected:", data.streamID);
        
        // You can access additional info if available
        if (data.value && data.value.label) {
            console.log("Guest label:", data.value.label);
        }
    }
    else if (data.action === "view-connection") {
        // Someone viewing the stream has connected
        console.log("Viewer connected:", data.streamID);
        
        // The value property will be true for connections
        if (data.value) {
            console.log("New viewer connected");
        } else {
            console.log("Viewer disconnected");
        }
    }
    else if (data.action === "director-connected") {
        // The director has connected
        console.log("Director connected");
    }
    else if (data.action === "scene-connected") {
        // A scene has connected
        console.log("Scene connected:", data.value); // Scene ID
    }
    else if (data.action === "slot-updated") {
        // A stream has been assigned to a slot
        console.log("Stream", data.streamID, "assigned to slot", data.value);
    }
}
```

#### Disconnections

```javascript
function handleAction(data) {
    // Handling disconnections
    if (data.action === "view-connection" && data.value === false) {
        // A viewer has disconnected
        console.log("Viewer disconnected:", data.streamID);
    }
    else if (data.action === "director-share" && data.value === false) {
        // A director has stopped sharing
        console.log("Director stopped sharing:", data.streamID);
    }
    else if (data.action === "push-connection" && data.value === false) {
        // A guest has disconnected
        console.log("Guest disconnected:", data.streamID);
    }
}
```

### Complete Working Example

Here's a complete example that demonstrates detecting joins and disconnects:

```javascript
// Create the container for the iframe
var container = document.createElement("div");
container.id = "vdo-container";
document.body.appendChild(container);

// Create the iframe element
var iframe = document.createElement("iframe");
iframe.allow = "camera;microphone;fullscreen;display-capture;autoplay;";
iframe.src = "https://vdo.ninja/?room=your-room-name&cleanoutput";
iframe.style.width = "100%";
iframe.style.height = "100%";
container.appendChild(iframe);

// Create a status display element
var statusDiv = document.createElement("div");
statusDiv.id = "connection-status";
document.body.appendChild(statusDiv);

// Set up event listener
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";

// Keep track of connected users
var connectedUsers = {};

// Add the event listener
eventer(messageEvent, function (e) {
    // Make sure the message is from our VDO.Ninja iframe
    if (e.source != iframe.contentWindow) return;
    
    // Log all messages for debugging
    console.log(e.data);
    
    // Process specific actions
    if ("action" in e.data) {
        handleAction(e.data);
    }
}, false);

function handleAction(data) {
    // Handle connections
    if (data.action === "guest-connected" && data.streamID) {
        connectedUsers[data.streamID] = data.value?.label || "Guest";
        updateStatusDisplay("Guest connected: " + (data.value?.label || data.streamID));
    }
    else if (data.action === "view-connection") {
        if (data.value && data.streamID) {
            connectedUsers[data.streamID] = "Viewer";
            updateStatusDisplay("Viewer connected: " + data.streamID);
        } else if (data.streamID) {
            delete connectedUsers[data.streamID];
            updateStatusDisplay("Viewer disconnected: " + data.streamID);
        }
    }
    else if (data.action === "director-connected") {
        updateStatusDisplay("Director connected");
    }
    else if (data.action === "push-connection" && data.value === false && data.streamID) {
        delete connectedUsers[data.streamID];
        updateStatusDisplay("User disconnected: " + data.streamID);
    }
}

function updateStatusDisplay(message) {
    var timestamp = new Date().toLocaleTimeString();
    statusDiv.innerHTML += `<p>${timestamp}: ${message}</p>`;
    
    // Update connected users count
    var count = Object.keys(connectedUsers).length;
    document.getElementById("user-count").textContent = count;
}

// Add a user count display
var countDiv = document.createElement("div");
countDiv.innerHTML = "Connected users: <span id='user-count'>0</span>";
document.body.insertBefore(countDiv, statusDiv);
```

### Waiting Room Example

You can implement a waiting room like the one in the `waitingroom.html` file from your code samples:

```javascript
// Setup event listener
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
var waiting = null;

eventer(messageEvent, function (e) {
    if (e.source != iframe.contentWindow) return;
    
    if ("action" in e.data) {
        if (e.data.action == "joining-room") {
            // Show initial joining message
            outputWindow.innerHTML = "JOINING ROOM";
            
            // After 1 second, show waiting message if director hasn't joined
            waiting = setTimeout(function() {
                outputWindow.innerHTML = "Waiting for the director to join";
                outputWindow.classList.remove("hidden");
            }, 1000);
        } 
        else if (e.data.action == "director-connected") {
            // Director has joined, clear waiting message
            clearTimeout(waiting);
            outputWindow.innerHTML = "";
            outputWindow.classList.add("hidden");
        }
    }
});
```

### Getting Additional Information About Connections

For more detailed information about connections, you can use the `getStreamIDs` or `getDetailedState` commands:

```javascript
// Request info about all connected streams
iframe.contentWindow.postMessage({ "getStreamIDs": true }, "*");

// Request detailed state information
iframe.contentWindow.postMessage({ "getDetailedState": true }, "*");
```

### Best Practices

1. **Always check the source**: Make sure messages are coming from your VDO.Ninja iframe.
2. **Handle disconnections gracefully**: Sometimes connections drop unexpectedly.
3. **Consider implementing reconnection logic**: If important users disconnect, you might want to notify them or attempt to reconnect.
4. **Debug with console.log**: Log all events during development to understand the full message flow.
5. **Test with multiple users**: The behavior can be different depending on who connects first.

By implementing these techniques, you can build sophisticated applications that respond to users joining and leaving your VDO.Ninja sessions, creating more interactive and responsive experiences.




---
description: Generic P2P Data Transmission Guide
---

# Generic P2P Data Transmission Guide

This guide focuses specifically on how to send and receive generic data between clients using VDO.Ninja's peer-to-peer (P2P) data channels over the IFRAME API.

### Understanding the P2P Data Channels

VDO.Ninja provides a powerful API that allows websites to send arbitrary data between connected clients through its peer-to-peer infrastructure. This enables you to:

* Create custom communication channels between clients
* Implement application-specific data exchange
* Build interactive multi-user experiences
* Exchange any type of serializable data

### Why VDO.Ninja's P2P Data Channels Are Powerful

VDO.Ninja's data channels offer several compelling advantages that make them ideal for modern web applications:

* **Production-Proven Reliability**: Used in production applications like Social Stream Ninja, which processes hundreds of messages per minute per peer connection
* **Automatic LAN Optimization**: Detects when connections are on the same local network and routes data directly, reducing latency
* **Firewall Traversal**: Enables communication between devices behind different firewalls without port forwarding
* **Cost-Effective**: No server costs or bandwidth charges for data transmission, as everything happens peer-to-peer
* **Low Latency**: Direct connections between peers minimize delay, ideal for real-time applications
* **Scalability**: Each peer connects directly to others, allowing for programmed distribution of loads
* **AI Integration Ready**: Perfect for distributing AI processing tasks or sharing AI-generated content between users, or accessing private AI services that are behind firewalls.
* **Remote Control Applications**: Enables secure remote control of devices through firewalls without complex networking setups
* **Works Across Platforms**: Functions on mobile, desktop, and various browsers without additional plugins

The creators of VDO.Ninja use these data channels in numerous applications beyond video, demonstrating their versatility and reliability in real-world scenarios.

### Basic Setup

First, set up your VDO.Ninja iframe:

```javascript
// Create the iframe element
var iframe = document.createElement("iframe");

// Set necessary permissions
iframe.allow = "camera;microphone;fullscreen;display-capture;autoplay;";

// Set the source URL (your VDO.Ninja room)
iframe.src = "https://vdo.ninja/?room=your-room-name&cleanish&dataonly";

// Add the iframe to your page
document.getElementById("container").appendChild(iframe);
```

{% hint style="info" %}
`&dataonly` is offered as a simple way to configure VDO.Ninja for data-only applications with no camera/microphone controls. `&cleanish` lets you hide GUI and menus, while still having access to stats and right-click content menus; helpful for debugging and development.
{% endhint %}

### Setting Up Event Listeners

To receive data from other clients, set up an event listener:

```javascript
// Set up event listener (cross-browser compatible)
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";

// Connected peers storage
var connectedPeers = {};

// Add the event listener
eventer(messageEvent, function(e) {
    // Make sure the message is from our VDO.Ninja iframe
    if (e.source != iframe.contentWindow) return;
    
    // Process connection events to track connected peers
    if ("action" in e.data) {
        handleConnectionEvents(e.data);
    }
    
    // Handle received data
    if ("dataReceived" in e.data) {
        handleDataReceived(e.data.dataReceived, e.data.UUID);
    }
}, false);

function handleConnectionEvents(data) {
    if (data.action === "guest-connected" && data.streamID) {
        // Store connected peer information
        connectedPeers[data.streamID] = data.value?.label || "Guest";
        console.log("Guest connected:", data.streamID, "Label:", connectedPeers[data.streamID]);
    } 
    else if (data.action === "push-connection" && data.value === false && data.streamID) {
        // Remove disconnected peers
        console.log("Guest disconnected:", data.streamID);
        delete connectedPeers[data.streamID];
    }
}

function handleDataReceived(data, senderUUID) {
    console.log("Data received from:", senderUUID, "Data:", data);
    
    // Example: Check for your custom data namespace
    if (data.overlayNinja) {
        processCustomData(data.overlayNinja, senderUUID);
    }
}

function processCustomData(data, senderUUID) {
    // Process based on your application's needs
    console.log("Processing custom data:", data);
    
    // Example: Handle different data types
    if (data.message) {
        displayMessage(data.message);
    } else if (data.command) {
        executeCommand(data.command);
    }
}
```

### Sending Data

#### Send Data Structure

When sending data via the VDO.Ninja IFRAME API, you use this general format:

```javascript
iframe.contentWindow.postMessage({
    sendData: yourDataPayload,
    type: "pcs",  // Connection type (see below)
    UUID: targetUUID  // Optional: specific target
}, "*");
```

The components are:

* `sendData`: Your data payload (object)
* `type`: Connection type (string)
  * `"pcs"`: Use peer connections (most reliable)
  * `"rpcs"`: Use request-based connections
* `UUID` or `streamID`: Optional target identifier

#### Sending to All Connected Peers

```javascript
function sendDataToAllPeers(data) {
    // Create the data structure with your custom namespace
    var payload = {
        overlayNinja: data  // Your custom data under a namespace
    };
    
    // Send to all peers
    iframe.contentWindow.postMessage({
        sendData: payload,
        type: "pcs"  // Use peer connection for reliability
    }, "*");
}

// Example usage
sendDataToAllPeers({
    message: "Hello everyone!",
    timestamp: Date.now()
});
```

#### Sending to a Specific Peer by UUID

```javascript
function sendDataToPeer(data, targetUUID) {
    // Create the data structure
    var payload = {
        overlayNinja: data  // Your custom data
    };
    
    // Send to specific UUID
    iframe.contentWindow.postMessage({
        sendData: payload,
        type: "pcs",
        UUID: targetUUID
    }, "*");
}

// Example usage
sendDataToPeer({
    message: "Hello specific peer!",
    timestamp: Date.now()
}, "peer-uuid-123");
```

#### Sending to Peers with Specific Labels

```javascript
function sendDataByLabel(data, targetLabel) {
    // Create the data structure
    var payload = {
        overlayNinja: data  // Your custom data
    };
    
    // Iterate through connected peers to find those with matching label
    var keys = Object.keys(connectedPeers);
    for (var i = 0; i < keys.length; i++) {
        try {
            var UUID = keys[i];
            var label = connectedPeers[UUID];
            if (label === targetLabel) {
                // Send to this specific peer
                iframe.contentWindow.postMessage({
                    sendData: payload,
                    type: "pcs",
                    UUID: UUID
                }, "*");
            }
        } catch (e) {
            console.error("Error sending to peer:", e);
        }
    }
}

// Example usage
sendDataByLabel({
    message: "Hello all viewers!",
    timestamp: Date.now()
}, "viewer");
```

#### Sending to a Peer by StreamID

```javascript
function sendDataByStreamID(data, streamID) {
    // Create the data structure
    var payload = {
        overlayNinja: data  // Your custom data
    };
    
    // Send to specific streamID
    iframe.contentWindow.postMessage({
        sendData: payload,
        type: "pcs",
        streamID: streamID
    }, "*");
}

// Example usage
sendDataByStreamID({
    message: "Hello by stream ID!",
    timestamp: Date.now()
}, "stream-123");
```

### Tracking Connected Peers

To reliably communicate with peers, keep track of connections and disconnections:

```javascript
// Store connected peers
var connectedPeers = {};

function handleConnectionEvents(data) {
    // Guest connections
    if (data.action === "guest-connected" && data.streamID) {
        connectedPeers[data.streamID] = data.value?.label || "Guest";
        console.log("Guest connected:", data.streamID, "Label:", connectedPeers[data.streamID]);
    }
    // View connections
    else if (data.action === "view-connection") {
        if (data.value && data.streamID) {
            connectedPeers[data.streamID] = "Viewer";
            console.log("Viewer connected:", data.streamID);
        } else if (data.streamID) {
            console.log("Viewer disconnected:", data.streamID);
            delete connectedPeers[data.streamID];
        }
    }
    // Director connections
    else if (data.action === "director-connected") {
        console.log("Director connected");
    }
    // Handle disconnections
    else if (data.action === "push-connection" && data.value === false && data.streamID) {
        console.log("User disconnected:", data.streamID);
        delete connectedPeers[data.streamID];
    }
}
```

### Getting All Connected StreamIDs

You can request a list of all connected streams:

```javascript
function getConnectedPeers() {
    iframe.contentWindow.postMessage({ getStreamIDs: true }, "*");
}

// In your event listener, handle the response:
if ("streamIDs" in e.data) {
    console.log("Connected streams:");
    for (var key in e.data.streamIDs) {
        console.log("StreamID:", key, "Label:", e.data.streamIDs[key]);
    }
}
```

### Detailed State Information

For more comprehensive information about the current state:

```javascript
function getDetailedState() {
    iframe.contentWindow.postMessage({ getDetailedState: true }, "*");
}

// Handle the response in your event listener
```

### Data Structure Best Practices

1.  **Use a Namespace**: Put your data under a custom namespace to avoid conflicts

    ```javascript
    {
      sendData: {
        yourAppName: {
          // Your data here
        }
      }
    }
    ```
2.  **Include Type Information**: Include type identifiers to differentiate messages

    ```javascript
    {
      sendData: {
        yourAppName: {
          type: "command",
          data: { /* command data */ }
        }
      }
    }
    ```
3.  **Include Timestamp**: Add timestamps to help with ordering

    ```javascript
    {
      sendData: {
        yourAppName: {
          type: "update",
          data: { /* update data */ },
          timestamp: Date.now()
        }
      }
    }
    ```

### Complete Example: Simple Chat System

Here's a complete example implementing a simple chat system using the P2P data channels:

```javascript
// Create the interface
const container = document.createElement('div');
container.style.width = '100%';
container.style.maxWidth = '800px';
container.style.margin = '0 auto';
document.body.appendChild(container);

// Create VDO.Ninja iframe
const iframe = document.createElement('iframe');
iframe.allow = "camera;microphone;fullscreen;display-capture;autoplay;";
iframe.src = "https://vdo.ninja/?room=chat-demo&cleanoutput";
iframe.style.width = "100%";
iframe.style.height = "360px";
container.appendChild(iframe);

// Create chat interface
const chatContainer = document.createElement('div');
chatContainer.style.marginTop = '20px';
container.appendChild(chatContainer);

const chatMessages = document.createElement('div');
chatMessages.style.height = '300px';
chatMessages.style.border = '1px solid #ccc';
chatMessages.style.padding = '10px';
chatMessages.style.overflowY = 'scroll';
chatContainer.appendChild(chatMessages);

const inputContainer = document.createElement('div');
inputContainer.style.marginTop = '10px';
inputContainer.style.display = 'flex';
chatContainer.appendChild(inputContainer);

const messageInput = document.createElement('input');
messageInput.type = 'text';
messageInput.placeholder = 'Type your message...';
messageInput.style.flexGrow = '1';
messageInput.style.padding = '8px';
inputContainer.appendChild(messageInput);

const sendButton = document.createElement('button');
sendButton.textContent = 'Send';
sendButton.style.marginLeft = '10px';
sendButton.style.padding = '8px 16px';
inputContainer.appendChild(sendButton);

// Store connected peers
const connectedPeers = {};

// Add event listeners
sendButton.addEventListener('click', sendChatMessage);
messageInput.addEventListener('keypress', function(e) {
    if (e.key === 'Enter') {
        sendChatMessage();
    }
});

function sendChatMessage() {
    const message = messageInput.value.trim();
    if (message) {
        // Create message object
        const chatData = {
            type: 'chat',
            text: message,
            sender: 'Me',
            timestamp: Date.now()
        };
        
        // Add to local chat
        addMessageToChat(chatData.sender, chatData.text);
        
        // Send to all peers
        sendDataToAllPeers(chatData);
        
        // Clear input
        messageInput.value = '';
    }
}

function addMessageToChat(sender, text) {
    const messageElement = document.createElement('div');
    messageElement.style.marginBottom = '8px';
    
    const senderSpan = document.createElement('strong');
    senderSpan.textContent = sender + ': ';
    messageElement.appendChild(senderSpan);
    
    const textNode = document.createTextNode(text);
    messageElement.appendChild(textNode);
    
    chatMessages.appendChild(messageElement);
    
    // Scroll to bottom
    chatMessages.scrollTop = chatMessages.scrollHeight;
}

function sendDataToAllPeers(data) {
    // Create the data structure
    const payload = {
        chatApp: data  // Using a custom namespace
    };
    
    // Send to all peers
    iframe.contentWindow.postMessage({
        sendData: payload,
        type: "pcs"
    }, "*");
}

// Set up event listener for messages from iframe
const eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
const eventer = window[eventMethod];
const messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";

eventer(messageEvent, function(e) {
    // Make sure the message is from our VDO.Ninja iframe
    if (e.source != iframe.contentWindow) return;
    
    // Process connection events
    if ("action" in e.data) {
        handleConnectionEvents(e.data);
    }
    
    // Handle received data
    if ("dataReceived" in e.data) {
        handleDataReceived(e.data.dataReceived, e.data.UUID);
    }
}, false);

function handleConnectionEvents(data) {
    if (data.action === "guest-connected" && data.streamID) {
        // Store connected peer information
        connectedPeers[data.streamID] = data.value?.label || "Guest";
        console.log("Guest connected:", data.streamID, "Label:", connectedPeers[data.streamID]);
        
        // Announce new connection in chat
        addMessageToChat("System", `${connectedPeers[data.streamID]} joined the chat`);
    } 
    else if (data.action === "push-connection" && data.value === false && data.streamID) {
        // Announce disconnection
        if (connectedPeers[data.streamID]) {
            addMessageToChat("System", `${connectedPeers[data.streamID]} left the chat`);
        }
        
        // Remove from tracking
        console.log("Guest disconnected:", data.streamID);
        delete connectedPeers[data.streamID];
    }
}

function handleDataReceived(data, senderUUID) {
    // Check for chat messages
    if (data.chatApp && data.chatApp.type === 'chat') {
        const chatData = data.chatApp;
        
        // Get sender name from our peer tracking if available
        const senderName = connectedPeers[senderUUID] || chatData.sender || "Unknown";
        
        // Add to chat
        addMessageToChat(senderName, chatData.text);
    }
}
```

### Best Practices

1. **Track Connections**: Always maintain a list of connected peers
2. **Use Namespaces**: Organize your data under custom namespaces
3. **Add Type Information**: Include message types for easier processing
4. **Include Timestamps**: Help with ordering and synchronization
5. **Error Handling**: Use try/catch blocks when sending messages
6. **Data Size**: Keep payloads reasonably small to avoid performance issues
7. **UUID vs StreamID**: Prefer UUID for targeting as it's more stable

### Troubleshooting

* **No Data Received**: Verify the UUID or streamID is correct
* **Connection Issues**: Check if peers are properly connected before sending
* **Timing Problems**: Ensure the iframe is fully loaded before sending messages
* **Data Format**: Make sure your data is properly serializable
* **Security Settings**: Check that your iframe permissions are set correctly

By following this guide, you can implement robust P2P data exchange between VDO.Ninja clients for any custom application.




---
description: 'Understanding the VDO.Ninja IFRAME API: Detecting User Joins and Disconnects'
---

# IFRAME API Basics

The VDO.Ninja IFRAME API allows websites to embed and interact with VDO.Ninja streams. One of the most useful features is the ability to detect when users join or disconnect from your stream through event messaging. This guide will explain how to implement this functionality in your own projects.

### How the IFRAME API Works

VDO.Ninja's IFRAME API uses the browser's `postMessage` API to communicate between your parent website and the embedded VDO.Ninja iframe. This allows you to:

1. Send commands to control the VDO.Ninja instance
2. Receive events and data from the VDO.Ninja instance

### Setting Up the Basic Structure

irst, you need to create an iframe that loads VDO.Ninja:

```
// Create the iframe element
var iframe = document.createElement("iframe");

// Set necessary permissions
iframe.allow = "camera;microphone;fullscreen;display-capture;autoplay;";

// Set the source URL (your VDO.Ninja room)
iframe.src = "https://vdo.ninja/?room=your-room-name&cleanoutput";

// Add the iframe to your page
document.getElementById("container").appendChild(iframe);
```

### Setting Up the Event Listener

To detect joins and disconnects, you need to set up an event listener for messages from the iframe:

```
// Set up event listener (cross-browser compatible)
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";

// Add the event listener
eventer(messageEvent, function (e) {
    // Make sure the message is from our VDO.Ninja iframe
    if (e.source != iframe.contentWindow) return;
    
    // Log the data for debugging
    console.log(e.data);
    
    // Process specific events
    if ("action" in e.data) {
        // Handle different actions
        handleAction(e.data);
    }
}, false);
```

### Detecting User Joins and Disconnects

The key events to watch for are:

#### Guest Connections

```
function handleAction(data) {
    if (data.action === "guest-connected") {
        // A new guest has connected
        console.log("Guest connected:", data.streamID);
        
        // You can access additional info if available
        if (data.value && data.value.label) {
            console.log("Guest label:", data.value.label);
        }
    }
    else if (data.action === "view-connection") {
        // Someone viewing the stream has connected
        console.log("Viewer connected:", data.streamID);
        
        // The value property will be true for connections
        if (data.value) {
            console.log("New viewer connected");
        } else {
            console.log("Viewer disconnected");
        }
    }
    else if (data.action === "director-connected") {
        // The director has connected
        console.log("Director connected");
    }
    else if (data.action === "scene-connected") {
        // A scene has connected
        console.log("Scene connected:", data.value); // Scene ID
    }
    else if (data.action === "slot-updated") {
        // A stream has been assigned to a slot
        console.log("Stream", data.streamID, "assigned to slot", data.value);
    }
}
```

#### Disconnections

```
function handleAction(data) {
    // Handling disconnections
    if (data.action === "view-connection" && data.value === false) {
        // A viewer has disconnected
        console.log("Viewer disconnected:", data.streamID);
    }
    else if (data.action === "director-share" && data.value === false) {
        // A director has stopped sharing
        console.log("Director stopped sharing:", data.streamID);
    }
    else if (data.action === "push-connection" && data.value === false) {
        // A guest has disconnected
        console.log("Guest disconnected:", data.streamID);
    }
}
```

### Complete Working Example

Here's a complete example that demonstrates detecting joins and disconnects:

```
// Create the container for the iframe
var container = document.createElement("div");
container.id = "vdo-container";
document.body.appendChild(container);

// Create the iframe element
var iframe = document.createElement("iframe");
iframe.allow = "camera;microphone;fullscreen;display-capture;autoplay;";
iframe.src = "https://vdo.ninja/?room=your-room-name&cleanoutput";
iframe.style.width = "100%";
iframe.style.height = "100%";
container.appendChild(iframe);

// Create a status display element
var statusDiv = document.createElement("div");
statusDiv.id = "connection-status";
document.body.appendChild(statusDiv);

// Set up event listener
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";

// Keep track of connected users
var connectedUsers = {};

// Add the event listener
eventer(messageEvent, function (e) {
    // Make sure the message is from our VDO.Ninja iframe
    if (e.source != iframe.contentWindow) return;
    
    // Log all messages for debugging
    console.log(e.data);
    
    // Process specific actions
    if ("action" in e.data) {
        handleAction(e.data);
    }
}, false);

function handleAction(data) {
    // Handle connections
    if (data.action === "guest-connected" && data.streamID) {
        connectedUsers[data.streamID] = data.value?.label || "Guest";
        updateStatusDisplay("Guest connected: " + (data.value?.label || data.streamID));
    }
    else if (data.action === "view-connection") {
        if (data.value && data.streamID) {
            connectedUsers[data.streamID] = "Viewer";
            updateStatusDisplay("Viewer connected: " + data.streamID);
        } else if (data.streamID) {
            delete connectedUsers[data.streamID];
            updateStatusDisplay("Viewer disconnected: " + data.streamID);
        }
    }
    else if (data.action === "director-connected") {
        updateStatusDisplay("Director connected");
    }
    else if (data.action === "push-connection" && data.value === false && data.streamID) {
        delete connectedUsers[data.streamID];
        updateStatusDisplay("User disconnected: " + data.streamID);
    }
}

function updateStatusDisplay(message) {
    var timestamp = new Date().toLocaleTimeString();
    statusDiv.innerHTML += `<p>${timestamp}: ${message}</p>`;
    
    // Update connected users count
    var count = Object.keys(connectedUsers).length;
    document.getElementById("user-count").textContent = count;
}

// Add a user count display
var countDiv = document.createElement("div");
countDiv.innerHTML = "Connected users: <span id='user-count'>0</span>";
document.body.insertBefore(countDiv, statusDiv);
```

### Waiting Room Example

You can implement a waiting room like the one in the `waitingroom.html` file from your code samples:

```
// Setup event listener
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
var waiting = null;

eventer(messageEvent, function (e) {
    if (e.source != iframe.contentWindow) return;
    
    if ("action" in e.data) {
        if (e.data.action == "joining-room") {
            // Show initial joining message
            outputWindow.innerHTML = "JOINING ROOM";
            
            // After 1 second, show waiting message if director hasn't joined
            waiting = setTimeout(function() {
                outputWindow.innerHTML = "Waiting for the director to join";
                outputWindow.classList.remove("hidden");
            }, 1000);
        } 
        else if (e.data.action == "director-connected") {
            // Director has joined, clear waiting message
            clearTimeout(waiting);
            outputWindow.innerHTML = "";
            outputWindow.classList.add("hidden");
        }
    }
});
```

### Getting Additional Information About Connections

For more detailed information about connections, you can use the `getStreamIDs` or `getDetailedState` commands:

```
// Request info about all connected streams
iframe.contentWindow.postMessage({ "getStreamIDs": true }, "*");

// Request detailed state information
iframe.contentWindow.postMessage({ "getDetailedState": true }, "*");
```

### Best Practices

1. **Always check the source**: Make sure messages are coming from your VDO.Ninja iframe.
2. **Handle disconnections gracefully**: Sometimes connections drop unexpectedly.
3. **Consider implementing reconnection logic**: If important users disconnect, you might want to notify them or attempt to reconnect.
4. **Debug with console.log**: Log all events during development to understand the full message flow.
5. **Test with multiple users**: The behavior can be different depending on who connects first.

By implementing these techniques, you can build sophisticated applications that respond to users joining and leaving your VDO.Ninja sessions, creating more interactive and responsive experiences.

##

##

## VDO.Ninja IFRAME API - Complete Inbound Control Reference

This document provides a comprehensive list of all inbound remote control calls available through the VDO.Ninja IFRAME API. These commands allow you to control a VDO.Ninja instance embedded in an iframe from your parent webpage.

### Table of Contents

* [Basic Usage](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#basic-usage)
* [Audio Controls](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#audio-controls)
* [Video Controls](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#video-controls)
* [Stream Management](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#stream-management)
* [Recording Controls](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#recording-controls)
* [Group Management](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#group-management)
* [Bitrate & Quality Controls](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#bitrate--quality-controls)
* [Device Management](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#device-management)
* [Layout & Display Controls](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#layout--display-controls)
* [Data & Messaging](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#data--messaging)
* [Statistics & Monitoring](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#statistics--monitoring)
* [Utility Functions](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#utility-functions)
* [Advanced Controls](https://github.com/steveseguin/Companion-Ninja/blob/main/iframeapi.md#advanced-controls)

### Basic Usage

To send commands to the VDO.Ninja iframe:

```
iframe.contentWindow.postMessage({
    command: value,
    // optional parameters
}, "*");
```

### Audio Controls

#### `mic` - Microphone Control

Controls the local microphone mute state.

```
// Unmute microphone
iframe.contentWindow.postMessage({ mic: true }, "*");

// Mute microphone
iframe.contentWindow.postMessage({ mic: false }, "*");

// Toggle microphone
iframe.contentWindow.postMessage({ mic: "toggle" }, "*");
```

#### `mute` / `speaker` - Speaker Control

Controls the speaker mute state (incoming audio).

```
// Mute speakers
iframe.contentWindow.postMessage({ mute: true }, "*");
// OR
iframe.contentWindow.postMessage({ speaker: false }, "*");

// Unmute speakers
iframe.contentWindow.postMessage({ mute: false }, "*");
// OR
iframe.contentWindow.postMessage({ speaker: true }, "*");

// Toggle speaker
iframe.contentWindow.postMessage({ mute: "toggle" }, "*");
```

#### `volume` - Volume Control

Sets the volume level for incoming audio (0.0 to 1.0).

```
// Set volume to 50%
iframe.contentWindow.postMessage({ volume: 0.5 }, "*");

// Set volume for specific stream
iframe.contentWindow.postMessage({ 
    volume: 0.8, 
    target: "streamID123" // or use "*" for all streams
}, "*");
```

#### `panning` - Audio Panning

Adjusts stereo panning for incoming audio.

```
// Pan left (-90 to 90, where -90 is full left, 90 is full right)
iframe.contentWindow.postMessage({ 
    panning: -45,
    UUID: "connection-uuid" // optional, applies to all if omitted
}, "*");
```

#### `targetAudioBitrate` - Audio Bitrate Target

Sets the target audio bitrate (in kbps).

```
iframe.contentWindow.postMessage({ 
    targetAudioBitrate: 128,
    target: "streamID123" // optional
}, "*");
```

#### `audiobitrate` - Audio Bitrate Control

Changes the audio bitrate with optional lock.

```
iframe.contentWindow.postMessage({ 
    audiobitrate: 64,
    lock: true, // optional, defaults to true
    target: "streamID123" // optional
}, "*");
```

#### `PPT` - Push-to-Talk

Controls push-to-talk functionality.

```
// Activate PPT (unmute)
iframe.contentWindow.postMessage({ PPT: true }, "*");

// Deactivate PPT (mute)
iframe.contentWindow.postMessage({ PPT: false }, "*");

// Toggle PPT
iframe.contentWindow.postMessage({ PPT: "toggle" }, "*");
```

### Video Controls

#### `camera` - Camera Control

Controls the local camera on/off state.

```
// Turn on camera
iframe.contentWindow.postMessage({ camera: true }, "*");

// Turn off camera
iframe.contentWindow.postMessage({ camera: false }, "*");

// Toggle camera
iframe.contentWindow.postMessage({ camera: "toggle" }, "*");
```

#### `pauseinvisible` - Pause Invisible Videos

Controls whether videos hidden in the mixer are paused.

```
// Enable pause invisible
iframe.contentWindow.postMessage({ pauseinvisible: true }, "*");

// Disable pause invisible
iframe.contentWindow.postMessage({ pauseinvisible: false }, "*");

// Toggle
iframe.contentWindow.postMessage({ pauseinvisible: "toggle" }, "*");
```

#### `keyframe` - Request Keyframe

Forces a keyframe to be sent to all scene connections.

```
iframe.contentWindow.postMessage({ keyframe: true }, "*");
```

### Stream Management

#### `requestStream` - Request Specific Stream

Loads a specific stream by ID.

```
iframe.contentWindow.postMessage({ 
    requestStream: "streamID123" 
}, "*");
```

#### `close` / `hangup` - Disconnect Streams

Disconnects and hangs up connections.

```
// Normal hangup
iframe.contentWindow.postMessage({ close: true }, "*");

// Emergency stop (immediate)
iframe.contentWindow.postMessage({ close: "estop" }, "*");

// Hangup and reload
iframe.contentWindow.postMessage({ close: "reload" }, "*");
```

### Recording Controls

#### `record` - Local Recording Control

Controls local video recording.

```
// Start recording
iframe.contentWindow.postMessage({ record: true }, "*");

// Stop recording
iframe.contentWindow.postMessage({ record: false }, "*");

// Record specific video element
iframe.contentWindow.postMessage({ 
    record: "videoElementId" 
}, "*");
```

### Group Management

#### `groups` - Set Groups

Sets the groups for the local stream.

```
// Set groups as array
iframe.contentWindow.postMessage({ 
    groups: ["group1", "group2"] 
}, "*");

// Set groups as comma-separated string
iframe.contentWindow.postMessage({ 
    groups: "group1,group2" 
}, "*");

// Clear groups
iframe.contentWindow.postMessage({ groups: [] }, "*");
```

#### `groupView` - Set View Groups

Sets which groups are visible.

```
// View specific groups
iframe.contentWindow.postMessage({ 
    groupView: ["group1", "group3"] 
}, "*");

// View all groups
iframe.contentWindow.postMessage({ groupView: [] }, "*");
```

### Bitrate & Quality Controls

#### `bitrate` - Video Bitrate Control

Sets video bitrate for streams (in kbps).

```
// Set bitrate for all streams
iframe.contentWindow.postMessage({ 
    bitrate: 2500,
    lock: true // optional, defaults to true
}, "*");

// Set bitrate for specific stream
iframe.contentWindow.postMessage({ 
    bitrate: 1000,
    target: "streamID123" // or UUID: "uuid-here"
}, "*");
```

#### `targetBitrate` - Target Video Bitrate

Sets the fundamental bitrate target.

```
iframe.contentWindow.postMessage({ 
    targetBitrate: 3000,
    target: "streamID123" // optional
}, "*");
```

#### `manualBitrate` - Manual Bandwidth Control

Sets manual bandwidth limits.

```
iframe.contentWindow.postMessage({ 
    manualBitrate: 5000,
    target: "streamID123" // optional
}, "*");
```

#### `scale` - Resolution Scaling

Controls resolution scaling.

```
// Set specific scale percentage
iframe.contentWindow.postMessage({ scale: 50 }, "*");

// Disable manual scaling (enable dynamic)
iframe.contentWindow.postMessage({ scale: false }, "*");

// Apply to specific stream
iframe.contentWindow.postMessage({ 
    scale: 75,
    UUID: "connection-uuid"
}, "*");
```

#### `targetWidth` / `targetHeight` - Resolution Request

Request specific resolution from remote connection.

```
iframe.contentWindow.postMessage({ 
    targetWidth: 1280,
    targetHeight: 720,
    UUID: "connection-uuid" // required
}, "*");
```

### Device Management

#### `changeVideoDevice` - Change Camera

Changes the active video input device.

```
iframe.contentWindow.postMessage({ 
    changeVideoDevice: "deviceId-here" 
}, "*");
```

#### `changeAudioDevice` - Change Microphone

Changes the active audio input device.

```
iframe.contentWindow.postMessage({ 
    changeAudioDevice: "deviceId-here" 
}, "*");
```

#### `changeAudioOutputDevice` - Change Speaker

Changes the audio output device.

```
iframe.contentWindow.postMessage({ 
    changeAudioOutputDevice: "deviceId-here" 
}, "*");
```

#### `getDeviceList` - List Available Devices

Requests a list of available media devices.

```
iframe.contentWindow.postMessage({ 
    getDeviceList: true,
    cib: "callback-id" // optional callback ID
}, "*");

// Response will be sent back via postMessage:
// { deviceList: [...], cib: "callback-id" }
```

### Layout & Display Controls

#### `layout` - Set Layout

Sets the display layout.

```
// Set single layout
iframe.contentWindow.postMessage({ layout: "grid" }, "*");

// Set multiple layouts (array)
iframe.contentWindow.postMessage({ 
    layout: ["grid", "presenter"] 
}, "*");

// With scene control (director only)
iframe.contentWindow.postMessage({ 
    layout: "grid",
    scene: 1,
    UUID: "target-uuid" // optional
}, "*");
```

#### `previewMode` - Switch Preview Mode

Switches between preview modes.

```
iframe.contentWindow.postMessage({ 
    previewMode: 1 // mode number
}, "*");
```

#### `slotmode` - Slot Mode Control

Controls slot mode behavior.

```
iframe.contentWindow.postMessage({ 
    slotmode: 1 // slot mode number, or false to disable
}, "*");
```

#### `advancedMode` - Toggle Advanced UI

Shows/hides advanced UI elements.

```
// Show advanced elements
iframe.contentWindow.postMessage({ advancedMode: true }, "*");

// Hide advanced elements
iframe.contentWindow.postMessage({ advancedMode: false }, "*");
```

#### `toggleSettings` - Toggle Settings Panel

Controls the settings panel visibility.

```
// Toggle settings
iframe.contentWindow.postMessage({ toggleSettings: "toggle" }, "*");

// Show settings
iframe.contentWindow.postMessage({ toggleSettings: true }, "*");
```

#### `target` - DOM Manipulation

Manipulates video elements in the DOM.

```
// Add video to grid
iframe.contentWindow.postMessage({ 
    target: "streamID123",
    add: true
}, "*");

// Remove video from grid
iframe.contentWindow.postMessage({ 
    target: "streamID123",
    remove: true
}, "*");

// Replace all videos with target
iframe.contentWindow.postMessage({ 
    target: "streamID123",
    replace: true
}, "*");

// Apply settings to video element
iframe.contentWindow.postMessage({ 
    target: "streamID123",
    settings: {
        style: "transform: scale(1.5);",
        muted: true
    }
}, "*");
```

### Data & Messaging

#### `sendData` - Send Generic Data

Sends data through peer connections.

```
iframe.contentWindow.postMessage({ 
    sendData: { custom: "data" },
    UUID: "target-uuid", // optional
    streamID: "streamID123", // optional
    type: "custom-type" // optional
}, "*");
```

#### `sendChat` - Send Chat Message

Sends a chat message to all peers.

```
iframe.contentWindow.postMessage({ 
    sendChat: "Hello everyone!" 
}, "*");
```

#### `sendMessage` - WebRTC Message to Viewers

Sends a message to viewer connections.

```
iframe.contentWindow.postMessage({ 
    sendMessage: { custom: "viewer-data" } 
}, "*");
```

#### `sendRequest` - WebRTC Request to Publishers

Sends a request to publisher connections.

```
iframe.contentWindow.postMessage({ 
    sendRequest: { action: "some-action" } 
}, "*");
```

#### `sendPeers` - Message All Peers

Sends a message to all connected peers.

```
iframe.contentWindow.postMessage({ 
    sendPeers: { broadcast: "data" } 
}, "*");
```

#### `sendRawMIDI` - Send MIDI Data

Sends raw MIDI messages.

```
iframe.contentWindow.postMessage({ 
    sendRawMIDI: {
        data: [144, 60, 127], // MIDI data array
        channel: 1,
        timestamp: Date.now()
    },
    UUID: "target-uuid" // optional
}, "*");
```

### Statistics & Monitoring

#### `getStats` - Get Quick Stats

Requests current statistics.

```
// Get all stats
iframe.contentWindow.postMessage({ 
    getStats: true,
    cib: "callback-id"
}, "*");

// Get stats for specific stream
iframe.contentWindow.postMessage({ 
    getStats: true,
    streamID: "streamID123",
    cib: "callback-id"
}, "*");
```

#### `getFreshStats` - Get Detailed Stats

Requests detailed statistics (takes \~1 second).

```
iframe.contentWindow.postMessage({ 
    getFreshStats: true,
    cib: "callback-id"
}, "*");
```

#### `getRemoteStats` - Request Remote Stats

Requests statistics from remote peers.

```
iframe.contentWindow.postMessage({ 
    getRemoteStats: true 
}, "*");
```

#### `requestStatsContinuous` - Continuous Stats

Enables/disables continuous statistics updates.

```
// Enable continuous stats
iframe.contentWindow.postMessage({ 
    requestStatsContinuous: true 
}, "*");

// Disable continuous stats
iframe.contentWindow.postMessage({ 
    requestStatsContinuous: false 
}, "*");
```

#### `getLoudness` - Audio Loudness Monitoring

Enables/disables loudness monitoring.

```
// Enable loudness monitoring
iframe.contentWindow.postMessage({ 
    getLoudness: true,
    cib: "callback-id"
}, "*");

// Disable loudness monitoring
iframe.contentWindow.postMessage({ 
    getLoudness: false 
}, "*");
```

#### `getStreamIDs` - List Stream IDs

Gets a list of all connected stream IDs.

```
iframe.contentWindow.postMessage({ 
    getStreamIDs: true,
    cib: "callback-id"
}, "*");
```

#### `getStreamInfo` - Detailed Stream Information

Gets detailed information about all streams.

```
iframe.contentWindow.postMessage({ 
    getStreamInfo: true,
    cib: "callback-id"
}, "*");
```

#### `getDetailedState` - Complete State Information

Gets comprehensive state information.

```
iframe.contentWindow.postMessage({ 
    getDetailedState: true,
    cib: "callback-id"
}, "*");
```

#### `getGuestList` - Get Guest List

Gets a list of all connected guests.

```
iframe.contentWindow.postMessage({ 
    getGuestList: true,
    cib: "callback-id"
}, "*");
```

### Utility Functions

#### `reload` - Reload Page

Forces a page reload.

```
iframe.contentWindow.postMessage({ reload: true }, "*");
```

#### `style` - Inject Custom CSS

Injects custom CSS into the iframe.

```
iframe.contentWindow.postMessage({ 
    style: `
        .videoContainer { border: 2px solid red; }
        #mutebutton { background: blue; }
    `
}, "*");
```

#### `function` - Execute Built-in Functions

Executes predefined functions.

```
// Preview webcam
iframe.contentWindow.postMessage({ 
    function: "previewWebcam" 
}, "*");

// Publish screen
iframe.contentWindow.postMessage({ 
    function: "publishScreen" 
}, "*");

// Change HTML content
iframe.contentWindow.postMessage({ 
    function: "changeHTML",
    target: "elementId",
    value: "<p>New content</p>"
}, "*");

// Route WebSocket message
iframe.contentWindow.postMessage({ 
    function: "routeMessage",
    value: { /* message data */ }
}, "*");

// Execute arbitrary code (use with caution)
iframe.contentWindow.postMessage({ 
    function: "eval",
    value: "console.log('Hello from eval');"
}, "*");
```

#### `saveVideoFrameToDisk` - Save Screenshot

Saves a video frame to disk.

```
// Save local video
iframe.contentWindow.postMessage({ 
    saveVideoFrameToDisk: true,
    filename: "screenshot.png" // optional
}, "*");

// Save specific stream
iframe.contentWindow.postMessage({ 
    saveVideoFrameToDisk: true,
    streamID: "streamID123",
    filename: "stream-capture.jpg"
}, "*");

// Save all streams
iframe.contentWindow.postMessage({ 
    saveVideoFrameToDisk: true,
    UUID: "*"
}, "*");
```

#### `getVideoFrame` - Get Video Frame Data

Gets video frame data as base64.

```
iframe.contentWindow.postMessage({ 
    getVideoFrame: true,
    streamID: "streamID123", // or UUID
    cib: "callback-id"
}, "*");
```

#### `copyVideoFrameToClipboard` - Copy Screenshot

Copies a video frame to clipboard.

```
iframe.contentWindow.postMessage({ 
    copyVideoFrameToClipboard: true,
    streamID: "streamID123" // or UUID
}, "*");
```

#### `getSnapshotBySlot` / `getSnapshotByStreamID` - Get Slot/Stream Snapshot

Gets a snapshot from a specific slot or stream using MediaStreamTrackProcessor.

```
// By slot number
iframe.contentWindow.postMessage({ 
    getSnapshotBySlot: 0, // slot index
    cib: "callback-id"
}, "*");

// By stream ID
iframe.contentWindow.postMessage({ 
    getSnapshotByStreamID: "streamID123",
    cib: "callback-id"
}, "*");

// Response includes base64 image data:
// {
//     type: 'frame',
//     frame: 'data:image/png;base64,...',
//     UUID: 'connection-uuid',
//     streamID: 'streamID123',
//     slot: 0,
//     format: 'png',
//     cib: 'callback-id'
// }
```

### Advanced Controls

#### `sceneState` - OBS Scene State

Sets the scene state for OBS integration.

```
// Scene is live
iframe.contentWindow.postMessage({ 
    sceneState: true 
}, "*");

// Scene is not live
iframe.contentWindow.postMessage({ 
    sceneState: false 
}, "*");
```

#### `layouts` - OBS Layout Sync

Syncs layouts with OBS.

```
iframe.contentWindow.postMessage({ 
    layouts: ["layout1", "layout2"],
    obsSceneTriggers: true // optional
}, "*");
```

#### `obsCommand` - OBS Commands

Sends commands to OBS.

```
iframe.contentWindow.postMessage({ 
    obsCommand: "some-command",
    remote: "remote-id", // optional
    UUID: "target-uuid", // optional
    streamID: "streamID123" // optional
}, "*");
```

#### `setBufferDelay` - Audio/Video Buffer Delay

Sets the buffer delay in milliseconds.

```
// Set default buffer delay
iframe.contentWindow.postMessage({ 
    setBufferDelay: 200 
}, "*");

// Set for specific stream
iframe.contentWindow.postMessage({ 
    setBufferDelay: 300,
    streamID: "streamID123" // or UUID or label
}, "*");

// Set for all streams
iframe.contentWindow.postMessage({ 
    setBufferDelay: 250,
    UUID: "*"
}, "*");
```

#### `automixer` - Automixer Control

Controls the automatic mixer behavior.

```
// Enable automixer
iframe.contentWindow.postMessage({ 
    automixer: true 
}, "*");

// Disable automixer (manual control)
iframe.contentWindow.postMessage({ 
    automixer: false 
}, "*");
```

#### `enableYouTube` - YouTube Chat Integration

Enables YouTube chat integration.

```
// Enable with API key
iframe.contentWindow.postMessage({ 
    enableYouTube: "your-youtube-api-key" 
}, "*");

// Enable with existing key
iframe.contentWindow.postMessage({ 
    enableYouTube: true 
}, "*");
```

#### `nextSlide` / `prevSlide` - Slide Navigation

Controls slide navigation.

```
// Next slide
iframe.contentWindow.postMessage({ nextSlide: true }, "*");

// Previous slide
iframe.contentWindow.postMessage({ prevSlide: true }, "*");
```

#### `getFaces` / `faceTrack` - Face Detection

Controls face detection/tracking.

```
// Enable face tracking
iframe.contentWindow.postMessage({ 
    getFaces: true,
    faceTrack: true
}, "*");

// Disable face tracking
iframe.contentWindow.postMessage({ 
    getFaces: true,
    faceTrack: false
}, "*");
```

#### `getEffectsData` - Effects Data

Gets data from visual effects (face tracking, etc.).

```
// Get specific effect data
iframe.contentWindow.postMessage({ 
    getEffectsData: "effect-name" 
}, "*");

// Disable effects data
iframe.contentWindow.postMessage({ 
    getEffectsData: false 
}, "*");
```

#### `action` - Companion API Actions

Executes Companion API actions.

```
iframe.contentWindow.postMessage({ 
    action: "action-name",
    value: "action-value",
    target: "optional-target"
}, "*");
```

### Response Handling

Many commands support a callback ID (`cib`) for tracking responses:

```
// Send request with callback ID
iframe.contentWindow.postMessage({ 
    getStats: true,
    cib: "unique-callback-123"
}, "*");

// Listen for response
window.addEventListener("message", function(e) {
    if (e.data.cib === "unique-callback-123") {
        console.log("Stats received:", e.data.stats);
    }
});
```

### Notes

* All commands are sent via `postMessage` to the iframe's `contentWindow`
* The second parameter `"*"` can be replaced with a specific origin for security
* Some commands require director privileges to function
* Commands that affect remote streams often accept `UUID`, `streamID`, or `target` parameters
* The `lock` parameter on bitrate controls prevents automatic adjustments
* Many "get" commands return data via postMessage back to the parent window




---
description: Enhanced IFRAME API Documentation - HTTP/WSS API Integration
---

# IFRAME API for Directors

#### Overview

The VDO.Ninja IFRAME API provides access to all HTTP/WSS API commands through the `action` parameter. This means you can use any command from the [HTTP/WSS API](https://github.com/steveseguin/Companion-Ninja) directly through the iframe's postMessage interface.

#### Using HTTP/WSS API Commands via IFRAME

All commands available in the HTTP/WSS API can be accessed through the IFRAME API using this format:

```
iframe.contentWindow.postMessage({
    action: "commandName",
    value: "value",
    value2: "optional",
    target: "optional", // for director commands
    cib: "callback-id" // optional callback identifier
}, "*");
```

#### Director Permissions

**Important:** To use director commands for remote control, you must have director permissions:

1. Use `&director=roomname` instead of `&room=roomname` in your iframe URL
2. Or combine with `&codirector=password` to enable multiple directors
3. Without proper permissions, director commands will fail silently

Example iframe URL with director permissions:

```
https://vdo.ninja/?director=myroom&cleanoutput&api=myapikey
```

### Complete Command Reference

**Self Commands (No Target Required)**

These commands affect the local VDO.Ninja instance:

```
// Microphone control
iframe.contentWindow.postMessage({ action: "mic", value: "toggle" }, "*");

// Camera control  
iframe.contentWindow.postMessage({ action: "camera", value: false }, "*");

// Speaker control
iframe.contentWindow.postMessage({ action: "speaker", value: true }, "*");

// Volume control (0-200)
iframe.contentWindow.postMessage({ action: "volume", value: 85 }, "*");

// Recording
iframe.contentWindow.postMessage({ action: "record", value: true }, "*");

// Bitrate control
iframe.contentWindow.postMessage({ action: "bitrate", value: 2500 }, "*");

// Layout control
iframe.contentWindow.postMessage({ action: "layout", value: 2 }, "*");

// Custom layout object
iframe.contentWindow.postMessage({ 
    action: "layout", 
    value: [
        {x: 0, y: 0, w: 50, h: 100, slot: 0},
        {x: 50, y: 0, w: 50, h: 100, slot: 1}
    ]
}, "*");

// Group management
iframe.contentWindow.postMessage({ action: "joinGroup", value: "1" }, "*");
iframe.contentWindow.postMessage({ action: "leaveGroup", value: "2" }, "*");

// Get information
iframe.contentWindow.postMessage({ action: "getDetails", cib: "details-123" }, "*");
iframe.contentWindow.postMessage({ action: "getGuestList", cib: "guests-456" }, "*");

// Camera PTZ controls
iframe.contentWindow.postMessage({ action: "zoom", value: 0.1 }, "*"); // Relative
iframe.contentWindow.postMessage({ action: "zoom", value: 1.5, value2: "abs" }, "*"); // Absolute
iframe.contentWindow.postMessage({ action: "pan", value: -0.5 }, "*");
iframe.contentWindow.postMessage({ action: "tilt", value: 0.1 }, "*");
iframe.contentWindow.postMessage({ action: "focus", value: 0.8, value2: "abs" }, "*");

// Other controls
iframe.contentWindow.postMessage({ action: "reload" }, "*");
iframe.contentWindow.postMessage({ action: "hangup" }, "*");
iframe.contentWindow.postMessage({ action: "togglehand" }, "*");
iframe.contentWindow.postMessage({ action: "togglescreenshare" }, "*");
iframe.contentWindow.postMessage({ action: "forceKeyframe" }, "*");
iframe.contentWindow.postMessage({ action: "sendChat", value: "Hello everyone!" }, "*");
```

**Director Commands (Target Required)**

These commands require director permissions and target specific guests:

```
// Target can be:
// - Slot number: "1", "2", "3", etc.
// - Stream ID: "abc123xyz"
// - "*" for all guests (where applicable)

// Guest microphone control
iframe.contentWindow.postMessage({ 
    action: "mic", 
    target: "1", 
    value: "toggle" 
}, "*");

// Guest camera control
iframe.contentWindow.postMessage({ 
    action: "camera", 
    target: "streamID123", 
    value: false 
}, "*");

// Add guest to scene
iframe.contentWindow.postMessage({ 
    action: "addScene", 
    target: "2", 
    value: 1  // Scene number
}, "*");

// Transfer guest to another room
iframe.contentWindow.postMessage({ 
    action: "forward", 
    target: "1", 
    value: "newroom" 
}, "*");

// Solo chat with guest
iframe.contentWindow.postMessage({ 
    action: "soloChat", 
    target: "3" 
}, "*");

// Two-way solo chat
iframe.contentWindow.postMessage({ 
    action: "soloChatBidirectional", 
    target: "2" 
}, "*");

// Send private message to guest
iframe.contentWindow.postMessage({ 
    action: "sendChat", 
    target: "1", 
    value: "Private message" 
}, "*");

// Overlay message on guest's screen
iframe.contentWindow.postMessage({ 
    action: "sendDirectorChat", 
    target: "2", 
    value: "You're live in 10 seconds!" 
}, "*");

// Guest volume control
iframe.contentWindow.postMessage({ 
    action: "volume", 
    target: "1", 
    value: 120  // 0-200
}, "*");

// Disconnect specific guest
iframe.contentWindow.postMessage({ 
    action: "hangup", 
    target: "3" 
}, "*");

// Guest camera PTZ control
iframe.contentWindow.postMessage({ 
    action: "zoom", 
    target: "1", 
    value: 0.1 
}, "*");

// Timer controls for guest
iframe.contentWindow.postMessage({ 
    action: "startRoomTimer", 
    target: "1", 
    value: 600  // 10 minutes in seconds
}, "*");

// Change guest position in mixer
iframe.contentWindow.postMessage({ 
    action: "mixorder", 
    target: "2", 
    value: -1  // Move up
}, "*");
```

#### Using targetGuest Function (Legacy)

The `targetGuest` function provides another way to control guests:

```
iframe.contentWindow.postMessage({
    function: "targetGuest",
    target: "1",      // Guest slot or stream ID
    action: "mic",    // Action to perform
    value: "toggle"   // Value (optional)
}, "*");
```

#### Using Commands Function

Access any command from the Commands object:

```
iframe.contentWindow.postMessage({
    function: "commands",
    action: "zoom",
    value: 0.5,
    value2: "abs"
}, "*");
```

#### Advanced DOM Manipulation

Target specific video elements by stream ID:

```
// Add video to grid
iframe.contentWindow.postMessage({
    target: "streamID123",
    add: true
}, "*");

// Remove video from grid
iframe.contentWindow.postMessage({
    target: "streamID123",
    remove: true
}, "*");

// Replace all videos with target
iframe.contentWindow.postMessage({
    target: "streamID123",
    replace: true
}, "*");

// Apply settings to video element
iframe.contentWindow.postMessage({
    target: "streamID123",
    settings: {
        style: "transform: scale(1.5);",
        muted: true,
        volume: 0.5
    }
}, "*");
```

#### Special Functions

```
// Preview local webcam
iframe.contentWindow.postMessage({
    function: "previewWebcam"
}, "*");

// Publish screen share
iframe.contentWindow.postMessage({
    function: "publishScreen"
}, "*");

// Change HTML content
iframe.contentWindow.postMessage({
    function: "changeHTML",
    target: "elementId",
    value: "<p>New content</p>"
}, "*");

// Route WebSocket message
iframe.contentWindow.postMessage({
    function: "routeMessage",
    value: { /* message data */ }
}, "*");

// Execute code (use with extreme caution)
iframe.contentWindow.postMessage({
    function: "eval",
    value: "console.log('Hello from eval');"
}, "*");
```

#### Handling Responses

Listen for responses with callback IDs:

```
window.addEventListener("message", function(e) {
    if (e.source !== iframe.contentWindow) return;
    
    if (e.data.cib === "my-callback-123") {
        console.log("Received response:", e.data);
        
        // Handle different response types
        if (e.data.guestList) {
            console.log("Guest list:", e.data.guestList);
        } else if (e.data.detailedState) {
            console.log("State info:", e.data.detailedState);
        } else if (e.data.callback) {
            console.log("Command result:", e.data.callback.result);
        }
    }
});
```

#### Complete Example: Director Control Panel

```
<!DOCTYPE html>
<html>
<head>
    <title>VDO.Ninja Director Control Panel</title>
</head>
<body>
    <h1>Director Control Panel</h1>
    
    <div id="container"></div>
    
    <div id="controls">
        <h2>Guest Controls</h2>
        <select id="guest-select">
            <option value="1">Guest 1</option>
            <option value="2">Guest 2</option>
            <option value="3">Guest 3</option>
        </select>
        
        <button onclick="controlGuest('mic', 'toggle')">Toggle Mic</button>
        <button onclick="controlGuest('camera', 'toggle')">Toggle Camera</button>
        <button onclick="controlGuest('addScene', 1)">Add to Scene 1</button>
        <button onclick="controlGuest('forward', 'lobby')">Send to Lobby</button>
        <button onclick="controlGuest('zoom', 0.1)">Zoom In</button>
        <button onclick="controlGuest('zoom', -0.1)">Zoom Out</button>
    </div>
    
    <div id="log"></div>

    <script>
    // Create iframe with director permissions
    const iframe = document.createElement("iframe");
    iframe.allow = "camera;microphone;fullscreen;display-capture;autoplay;";
    iframe.src = "https://vdo.ninja/?director=myroom&cleanoutput&api=mykey";
    iframe.style.width = "800px";
    iframe.style.height = "600px";
    document.getElementById("container").appendChild(iframe);
    
    // Control function
    function controlGuest(action, value) {
        const target = document.getElementById("guest-select").value;
        
        const message = {
            action: action,
            target: target
        };
        
        if (value !== undefined) {
            message.value = value;
        }
        
        // Generate callback ID
        const callbackId = `cb-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
        message.cib = callbackId;
        
        iframe.contentWindow.postMessage(message, "*");
        log(`Sent: ${JSON.stringify(message)}`);
    }
    
    // Listen for responses
    window.addEventListener("message", function(e) {
        if (e.source !== iframe.contentWindow) return;
        
        log(`Received: ${JSON.stringify(e.data)}`);
        
        // Handle specific events
        if (e.data.action === "guest-connected") {
            log(`Guest connected: ${e.data.streamID}`);
        } else if (e.data.guestList) {
            updateGuestList(e.data.guestList);
        }
    });
    
    // Logging
    function log(message) {
        const logDiv = document.getElementById("log");
        const entry = document.createElement("div");
        entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
        logDiv.appendChild(entry);
        logDiv.scrollTop = logDiv.scrollHeight;
    }
    
    // Update guest list
    function updateGuestList(guests) {
        const select = document.getElementById("guest-select");
        select.innerHTML = "";
        
        guests.forEach((guest, index) => {
            const option = document.createElement("option");
            option.value = guest.id || (index + 1);
            option.textContent = guest.label || `Guest ${index + 1}`;
            select.appendChild(option);
        });
    }
    
    // Get initial guest list
    setTimeout(() => {
        iframe.contentWindow.postMessage({
            action: "getGuestList",
            cib: "initial-guests"
        }, "*");
    }, 2000);
    </script>
</body>
</html>
```

#### Important Notes

1. **Director Permissions**: Always use `&director=roomname` or `&codirector=password` for director commands
2. **Target Format**: Use slot numbers (1, 2, 3) or stream IDs for targeting
3. **Callback IDs**: Use unique `cib` values to track responses
4. **Error Handling**: Commands may fail silently without proper permissions
5. **Timing**: Wait for iframe to load before sending commands

#### Troubleshooting

* **Commands not working**: Check director permissions in iframe URL
* **No response**: Verify callback ID handling and message source
* **Guest not found**: Confirm target value matches slot or stream ID
* **Permission errors**: Ensure using `&director=` not `&room=`

This integration allows you to build powerful control interfaces using the full capabilities of the VDO.Ninja API through simple iframe messaging.




---
description: Improve quality of video if using iOS or Android native app versions
---

# How to improve quality of the native app

The [native app version](../steves-helper-apps/native-mobile-app-versions.md) of VDO.Ninja isn't as feature rich as the web-app version, so control over exactly resolutions, frame rates, and more are a bit limited. Still, there are ways to encourage the quality to be as high as it can go.

## Increase the bitrate

Setting the bitrate on the viewer side, such as by adding one of the following to the view-link.

[`&videobitrate=12000`](../advanced-settings/video-bitrate-parameters/bitrate.md), or maybe `&videobitrate=12000`[`&codec=h264`](../advanced-settings/view-parameters/codec.md) or `&videobitrate=12000&codec=av1`

Different phones will have different CPU/encoding capabilities, so different codecs can result in varying qualities sometimes.

## Enable 1080p mode

In the app itself, you can enable the prefer 1080p mode also. This doesn't force 1080p mode, but it "suggests" to the phone that is what you want captured. In time, more advanced controls may be added in this respect.

## Improve the network connection

You can also try to connect your smartphone via Ethernet, rather than via WiFi, and ensure your network connection is top-notch. You can do this with a USB to Ethernet adapter, and then connecting the phone to your router.

You'll want the viewer also to be on a wired connection if possible, so preferably also ethernet.

If on cellular, considering using a bonded cellular connection, such as those provided by Speedify or other provider.

## Smartphone overheating

If your phone is getting warm, putting a metal heatsink on the backside of the phone directly can help keep it from thermal throttling. You can also try changing codecs, to see if perhaps there is a better option

## Update your smartphone

Some smartphones will have limited functionality if using an older version of the operating system. This is especially true of iOS devices, where iOS 16 has several core improvements over iOS 16, for example.

## Final notes

Those options will give you the best chance of obtaining the highest quality from the native app.

Otherwise, if you want more control over settings and quality, you'll need to use the web app, available at [https://vdo.ninja](https://vdo.ninja).




# How to install RaspNinja on Jetson

Download image for your device from:\
[https://developer.nvidia.com/embedded/downloads](https://developer.nvidia.com/embedded/downloads)

.png>)

Write the image to a high-quality micro SD card, as low-quality SD cards will be slow and have a very short lifespan.

.png>)

Boot the Jetson with the SD card install. You will need a display and keyboard, ideally also a mouse, to complete the initial setup. \
\
Connect the Jetson to the internet; Ethernet is ideal, but WiFi will work if your Jetson has a WiFi adapter.\
\
Open the Terminal app or SSH into the Jetson to continue the installation.

.png>)

Download Raspberry Ninja and run the installer. This will update your Jetson installation to Ubuntu 20 and install the required components. It may take some time and may require some prodding if it fails.

```
git clone https://github.com/steveseguin/raspberry_ninja
cd raspberry_ninja
cd nvidia_jetson
chmod +x advanced_installer.sh
./advanced_installer.sh
```

 (1).png>)




# MIDI, API and WebHID support

## MIDI hotkeys

There are numerous more hotkeys that can be used via MIDI; these are global hotkeys, used even if the window is not visible, but they require some additional setup. You can remotely control via MIDI also, using the [`&midiout`](../midi-settings/midiout.md) and [`&midiin`](../midi-settings/midiin.md) routing functionality.&#x20;

MIDI hotkeys are compatible with an Elgato Streamdeck by means of a free Streamdeck MIDI plugin.

{% content-ref url="../midi-settings/midi.md" %}
[midi.md](../midi-settings/midi.md)
{% endcontent-ref %}

## Bitfocus Companion

There is also Bitfocus Companion control compatibility, available here: [https://github.com/bitfocus/companion-module-vdo-ninja](https://github.com/bitfocus/companion-module-vdo-ninja)

## HTTP / Websocket API

The Bitfocus Companion plugin makes use of a HTTP and Websocket API, that allows for lots of remote control functionality.

There is a website that demos some of the commands available here: [https://companion.vdo.ninja/](https://companion.vdo.ninja/) Details on the API itself is here: [https://github.com/steveseguin/Companion-Ninja](https://github.com/steveseguin/Companion-Ninja)

You can use this to create your own hotkeys for pretty any device, application, or website.

{% content-ref url="../general-settings/api.md" %}
[api.md](../general-settings/api.md)
{% endcontent-ref %}

## IFRAME API

The HTTP and websocket make use of a server to route API calls. If you'd like to create your own API server or don't need remote hotkey support, you can used the provide IFRAME API and send commands instead to VDO.Ninja via an IFRAME wrapper.&#x20;

The IFRAME API is the most powerful option, but it requires some basic coding on your own part to have it provide hotkey functionality for your specific requirement.

{% content-ref url="iframe-api-documentation.md" %}
[iframe-api-documentation.md](iframe-api-documentation.md)
{% endcontent-ref %}

Below is an example of how to remotely control OBS anywhere online using the VDO.Ninja IFrame API; the code is just an example of how to use the IFrame API with OBS in this case, and it not intended to be used in production as is. The core concept lets you relay data messages from one website page to another, peer to peer, with just a few lines of code!

{% embed url="https://github.com/steveseguin/sample-p2p-tunnel" %}

## WebHID

There is also WebHID support, but it's not fully implemented at this time. User requests are welcomed though and there's a demo here: [https://vdo.ninja/webhid](https://vdo.ninja/webhid)\
It should be improved upon in the future, assuming the feature does not get depreciated by the browser first.

## Feature requests and feedback

It's easy enough to add new hotkeys or features; please make a request as needed. The hotkey and API commands are organically development, based on user needs and feedback. Most simple requests can be accommodated within minutes.




---
description: Encoder options that can offer smooth playback
---

# Recommended OBS WHIP settings

OBS Studio v30 now has WHIP output, which can stream into VDO.Ninja. While there are a few limitations of using OBS Studio with VDO.Ninja directly, some H264 settings that have reported offered good results are the following:

* Rate Control: CRF
* CRF: 23
* Keyframe Interval: 1s
* Preset: Veryfast
* Profile: High
* Tune: Fastdecode (required for WebRTC playback)
* x264 Options: bframes=0 (required for WebRTC playback)

In some cases when using VDO.Ninja to view the WHIP video, adding [`&buffer=2500`](../advanced-settings/view-parameters/buffer.md) to the VDO.Ninja view link can further help reduce any lost of skipped frames, but at the cost of increased latency.\
\
While these above settings may not offer the lowest latency or CPU usage, please try them out before seeking support about issues you may be having. It's very easy to break things with bad settings.

{% hint style="warning" %}
OBS Studio does not yet have fully compatible WHIP support with VDO.Ninja, as it lacks the ability to perform NAT traversal. You can resolve this issue with my patched version of OBS in the mean time-- download links can be found below:\
\
[\[Windows\]](https://backup.vdo.ninja/OBS_VDO_Ninja.zip) [\[macOS\]](https://drive.google.com/file/d/1bDln_cOuAb3wA0fzvXwsY8WX1vZKGEIJ/view?usp=sharing) \[[source](https://github.com/steveseguin/obs-studio/)]
{% endhint %}

## How to view WHIP streams using VDO.Ninja

There's a guide here for those looking to go live from OBS to VDO.Ninja via WHIP

{% embed url="https://docs.vdo.ninja/guides/from-obs-to-vdo.ninja-using-whip" %}

If looking for alternatives to publishing into VDO.Ninja, consider checking out [Raspberry.Ninja](../updates/updates-raspberry.ninja.md) also, which supports a broad range of encoders, including AV1-AOM, Intel QuickSync, Raspberry Pis, Nvidia Jetson, and many other hardware and software options. Playback is smooth, with support for multiple viewers. Runs on most systems, including Linux and _Windows for Linux Subsystem_ (WSL).




---
description: How to share audio and video from OBS Studio into VDO.Ninja
---

# Publish from OBS into VDO.Ninja

In this walk-through we demonstrate how to use VDO.Ninja with the OBS Virtual camera and Virtual Audio Cable.\
\
This combination is powerful and opens the world to numerous new live show formats. You could also push back audio and/or video from OBS into VDO.Ninja to share with a group there, or into a large Zoom call, all with super low latency.\
\
Combining this OBS to VDO.Ninja approach with \&broadcast mode or a server-assisted approach, you can enable larger room sizes, with around 10 to 30 people in a room being feasible.

#### Requirements

* OBS Studio v26 or newer
  * This ideally will run on OBS on the same system as VDO.Ninja
  * For Windows, OBS version 26 or newer is recommended: [https://obsproject.com/download](https://www.google.com/url?q=https://obsproject.com/download\&sa=D\&source=editors\&ust=1626144550329000\&usg=AOvVaw1SHwecfzt\_otZPz1YNkN3r)\

* Virtual Audio Cable Software
  * For Windows or Mac, you can use VB-CABLE Virtual Audio
    * This is recommended software as it enables proper audio support
    * The software is Donationware
    * [https://www.vb-audio.com/Cable/](https://www.google.com/url?q=https://www.vb-audio.com/Cable/\&sa=D\&source=editors\&ust=1626144550330000\&usg=AOvVaw3F2QQT0F6uzv1rHBdsARNF)\

    * There's also Voicemeter or VAC available as good options on PC.
    * For macOS, you have a few other good choices too:
      * [https://github.com/steveseguin/vdo.ninja/wiki/FAQ#how-to-capture-audio-on-mac](https://www.google.com/url?q=https://github.com/steveseguin/obsninja/wiki/FAQ%23how-to-capture-audio-on-mac\&sa=D\&source=editors\&ust=1626144550330000\&usg=AOvVaw1Rzm5d\_ud17CiLByYZ66lb)

### Step 0

This guide assumes you have OBS installed, along with the other required software, though we shall briefly cover these initial installation steps now.

\
We also will assume you are using Windows. You will need to adapt accordingly for macOS, which likely is going to be more complicated.

On the computer that will be using Zoom or Google Hangouts to broadcast, please do the following:

1. Uninstall and remove all old versions of OBS, including StreamLabs OBS if that is installed.
2. Install OBS Studio v26 or newer. [https://github.com/obsproject/obs-studio/releases/](https://github.com/obsproject/obs-studio/releases/)
3. Lastly, install the VB-Cable Virtual Audio device. [https://www.vb-audio.com/Cable/](https://www.google.com/url?q=https://www.vb-audio.com/Cable/\&sa=D\&source=editors\&ust=1626144550333000\&usg=AOvVaw1V70Tdr32UiXMUJZ0Uysnb)

### Step 1

Start the OBS Virtual camera; located under the Start Recording button.

### Step 2

We will now configure OBS to output audio from the Browser Source to the Virtual Audio Cable. In the OBS settings, under Advanced, we select the Monitoring Device to be our Virtual Audio device (CABLE Input).\
\
We also want to disable Windows audio ducking.

### Step 3

In our last configuration step, we want to go into the Advanced Audio Properties in OBS. When there, we want to set the audio sources we want to output have its Audio Monitoring setting be set to Monitor and Output.\
\
If you intend to feed audio from OBS back into an VDO.Ninja group call, you can use this step to also mix-minus the audio; selecting just the audio sources you want the remote guests to hear, excluding their own audio to prevent echo.\
\

### Step 4

We’re READY to go! Using this setup we can publish from OBS into VDO.Ninja with near zero latency; going forward it's just like selecting a second Webcam and microphone.

If you are already in VDO.Ninja, you can switch between your webcam and the virtual camera and normal camera in the settings. If you're a director of a room in VDO.Ninja, you can even share you audio and video from OBS into a room and not have it show up in any scene; just have it been seen by guests.\
\
It is important to remember that you need to select the VB-Audio Virtual Cable in the call as well, if you also want to share the audio from it that is. \
\
If publishing to VDO.Ninja, remember that you can select multiple audio sources in VDO.Ninja by holding down `CTRL` (or command) when selecting them. You could include the VB Audio Cable and your local microphone together, for example.\

.png>)

\
All done! You can switch between the webcam and the OBS live video as needed.\
\
If you need to listen to your VB-Audio cable at the same time still, you can refer to this help guide for a couple options: [https://docs.vdo.ninja/guides/audio#guide-routing-windows-applications-audio-to-vdo.ninja](https://docs.vdo.ninja/guides/audio#guide-routing-windows-applications-audio-to-vdo.ninja)

### Having issues with frame rates or aspect ratios?&#x20;

{% hint style="info" %}
If you aren't getting 60-fps from the OBS Virtual Camera into `&framerate=60` to the sender's URL.  The OBS Virtual Camera doesn't always report what framerates it can handle correctly to the browser, but if you manually specify it, it should work.
{% endhint %}

{% hint style="info" %}
It's sometimes important to activate the OBS Virtual Camera in OBS before selecting it with VDO.Ninja.  If you start the Virtual Camera \*after\* it has been selected, settings may not correctly work, such as the correct aspect ratio
{% endhint %}

{% hint style="info" %}
If looking to do custom aspect-ratios with the OBS Virtual Camera into VDO.Ninja, you can specify the exact width and height via the URL in VDO.Ninja; `&width=720&height=1280,` for example.\
\
It's important that the resolution be exactly the same as what is specified in OBS video settings; deviations will cause issues.\
\
It is also important that you activate the OBS Virtual Camera in OBS before select it in VDO.Ninja. If you do it after, the aspect ratio may not work correctly.
{% endhint %}

## Share webcam directly from OBS

If you wish not to use a third-party browser, but publish video directly from OBS itself, you can load OBS up in a special mode that allows for it.\
\
Please see this article for more on that: [https://docs.vdo.ninja/guides/share-webcam-from-inside-obs](https://docs.vdo.ninja/guides/share-webcam-from-inside-obs)





# How to publish to Facebook Live

There's a video guide on how to publish from VDO.Ninja to Facebook Live here: [https://www.youtube.com/watch?v=Zk345qg0U6U](https://www.youtube.com/watch?v=Zk345qg0U6U)

Some options that you can use to achieve this include:

RTMP is an option, typically done via OBS Studio. You can get a stream key for publishing from the Facebook Live production dashboard:\
[https://www.facebook.com/live/producer/](https://www.facebook.com/live/producer/)

You'd use the OBS Browser source to bring VDO.Ninja into OBS Studio.

You can also publish via OBS into Facebook via the Virtual camera, as Facebook supports webcam publishing. This will require the use of a virtual audio cable though, and since OBS does not yet include its own virtual audio cable, you'll have to download one.\
For example: [https://vb-audio.com/Cable/](https://vb-audio.com/Cable/)

You can also screen share VDO.Ninja into Facebook, bypassing the need for OBS altogether. Facebook doesn't support audio cable via screen share sadly, so you'll need to use a virtual audio cable still for audio routing.

You can use the Electron Capture app instead of Chrome as a screen sharing source, which provides exact resolution and always-on-top options. It also makes it easier to select the virtual audio cable output as the output destination.

With Chrome, you can select the virtual audio cable as the output source by adding [`&od=cable`](../advanced-settings/setup-parameters/and-audiooutput.md) to the scene/view link, or by visiting [https://vdo.ninja/electron](https://vdo.ninja/electron) and selecting it from the drop down menu.




---
description: How to Set Up Proper Lighting for Live Streaming
---

# Set Up Proper Lighting

Proper lighting is crucial for creating a professional-looking live stream. Good lighting can enhance your video quality, making you appear clearer and more engaging to your audience. This guide will walk you through the process of setting up effective lighting for your live stream.

### Understanding the Basics

Before we dive into the setup, it's important to understand the three-point lighting system, which is the foundation of good lighting in video production:

1. Key Light: The primary and brightest light source
2. Fill Light: Softens shadows created by the key light
3. Back Light: Separates you from the background, adding depth

### Equipment You'll Need

* 2-3 light sources (LED panels, ring lights, or softboxes)
* Light stands (if not using desk lamps)
* Diffusers (if your lights don't have built-in softening)
* Optional: Dimmers or brightness adjusters

### Step-by-Step Setup

#### 1. Position Your Key Light

* Place your brightest light at a 45-degree angle to your face, slightly above eye level.
* This light should be on the same side as your "good side" if you have a preference.
* Ensure it's not too close to avoid harsh shadows or washing out your features.

#### 2. Add Your Fill Light

* Position a softer light on the opposite side of your face from the key light.
* This light should be about half the intensity of your key light.
* Its purpose is to soften shadows and provide more even illumination.

#### 3. Set Up the Back Light

* Place this light behind you, pointing at your shoulders and hair.
* It should be out of frame and slightly higher than your head.
* This light separates you from the background, adding depth to the image.

#### 4. Adjust and Balance

* Turn on all your lights and make adjustments.
* Ensure the key light isn't too bright or causing harsh shadows.
* Adjust the fill light to reduce shadows without flattening the image.
* Fine-tune the back light so it creates a subtle glow without being distracting.

### Additional Tips

1. **Use Natural Light**: If possible, face a window for your key light and use artificial lights to supplement.
2. **Avoid Overhead Lighting**: This can create unflattering shadows. Turn off ceiling lights if necessary.
3. **Consider Your Background**: Ensure your lighting doesn't create distracting shadows on the wall behind you.
4. **Use Diffusion**: Soft, diffused light is generally more flattering than harsh, direct light.
5. **Match Color Temperatures**: If using multiple lights, ensure they have the same color temperature for consistency.
6. **Experiment with RGB Lights**: These can add creative color effects to your background or accent lighting.
7. **Invest in Adjustable Lights**: Lights with dimming capabilities and adjustable color temperature offer more flexibility.

### Troubleshooting Common Issues

* **Glare on Glasses**: Adjust the angle of your key light slightly to reduce reflections.
* **Harsh Shadows**: Move your key light further away or use diffusion to soften the light.
* **Washed Out Appearance**: Reduce the intensity of your lights or move them further away.
* **Uneven Lighting**: Ensure your fill light is properly positioned to balance the key light.

### Conclusion

Remember, good lighting takes practice and experimentation. Don't be afraid to make adjustments and find what works best for your specific setup and environment. With these guidelines, you'll be well on your way to creating a professional-looking live stream that engages your audience and enhances your content.




---
description: >-
  Share your webcam, virtual-camera, and audio source from using VDO.Ninja
  inside OBS
---

# How to share webcam from inside OBS

{% hint style="warning" %}
This guide works for OBS Studio v27.1.3, but some users have had issues with v27.2. &#x20;
{% endhint %}

By default, you can't select your webcam in an OBS dock or browser source. This can be changed by adding a command-line parameter to the OBS launch shortcut.

Within Windows, we can right-click the OBS launch icon or app icon, right click the "OBS Studio" option, and then click Properties. This will provide us the launch properties window.

 (1) (1) (1) (1) (1).png>)

We want to add `--enable-media-stream` to the Target field; we want to add this after the quotations, and not inside them. See below for an example.

.png>)

From there, we are good to go. We can add a dock to OBS or a browser source, and we should be able to now activate our webcam source, such as the built-in OBS virtual webcam.

If we use the following VDO.Ninja URL as a dock source, we can have VDO.Ninja auto-start every time, create a new link that you can share with others. This link is setup to auto-select the OBS virtual camera and the first VB virtual audio cable, if one is available.&#x20;

`https://vdo.ninja/?webcam&vd=obs&ad=virtual&autostart&cover`

 (1).png>)

.png>)




---
description: Best Practices for Stream Scheduling and Promotion
---

# Stream Scheduling and Promotion

Consistent scheduling and effective promotion are crucial for growing your audience and maintaining a successful streaming channel. This guide will cover key strategies to optimize your stream schedule and promote your content effectively.

### Stream Scheduling

#### 1. Consistency is Key

* Set a regular schedule and stick to it
* Stream at the same times each week to build viewer habits

#### 2. Find Your Optimal Time Slot

* Use your platform's analytics to identify when your audience is most active
* Consider your target audience's time zone and typical schedule

#### 3. Balance Frequency and Quality

* Stream often enough to maintain audience engagement
* Don't overcommit – prioritize quality over quantity

#### 4. Plan for Variety

* Mix up your content to keep things interesting
* Consider themed days (e.g., "Multiplayer Mondays", "Tutorial Tuesdays")

#### 5. Account for Special Events

* Plan around major events in your niche (e.g., game releases, tournaments)
* Occasionally schedule special, longer streams for big occasions

### Stream Promotion

#### 1. Leverage Social Media

* Maintain active profiles on relevant platforms (Twitter, Instagram, TikTok)
* Post regular updates, teasers, and highlights
* Use appropriate hashtags to increase visibility

#### 2. Optimize Your Stream Titles and Descriptions

* Use clear, catchy titles that describe your content
* Include relevant keywords in your descriptions for discoverability

#### 3. Create a Content Calendar

* Plan your streams and promotional content in advance
* Ensure a consistent flow of content across all platforms

#### 4. Collaborate with Other Streamers

* Participate in raids and host other channels
* Organize collaborative streams to cross-pollinate audiences

#### 5. Engage with Your Community

* Respond to comments and messages promptly
* Create a Discord server for your community

#### 6. Use Email Marketing

* Build an email list for your most dedicated fans
* Send regular newsletters with stream schedules and updates

#### 7. Create Highlight Reels and Clips

* Share your best moments on platforms like YouTube and TikTok
* Use these to attract new viewers to your live streams

### Platform-Specific Strategies

#### Twitch

* Use the Schedule feature to display upcoming streams
* Leverage Channel Points for viewer engagement
* Participate in Twitch Teams relevant to your content

#### YouTube

* Create and update playlists for your streams
* Use Community posts to engage with your audience between streams
* Optimize your video titles and thumbnails for search

#### Facebook Gaming

* Use the Streamer Dashboard to schedule upcoming streams
* Engage with viewers in Facebook Groups related to your content
* Utilize Facebook Events to promote big streaming events

### Advanced Promotion Techniques

#### 1. Create a Website or Blog

* Centralize your content and streaming information
* Improve your SEO for better discoverability

#### 2. Develop a Brand

* Create consistent visuals across all platforms
* Develop a unique streaming persona or style

#### 3. Offer Exclusive Content

* Provide Subscriber-only streams or content
* Create Patreon tiers with special perks

#### 4. Attend Gaming Events and Conventions

* Network with other content creators and industry professionals
* Promote your channel in person to potential new viewers

#### 5. Run Contests and Giveaways

* Encourage viewers to share your content for entries
* Ensure you comply with platform rules and local laws

### Measuring and Improving

#### 1. Track Your Metrics

* Monitor viewer counts, engagement rates, and follower growth
* Use this data to refine your scheduling and promotion strategies

#### 2. Seek Feedback

* Regularly ask your community for input on your schedule and content
* Conduct polls to gauge interest in potential new stream ideas

#### 3. Stay Adaptable

* Be willing to adjust your schedule based on performance and feedback
* Keep an eye on platform changes and new features to leverage

### Conclusion

Effective scheduling and promotion are ongoing processes that require consistent effort and adaptation. By maintaining a regular schedule, actively promoting your streams, and continuously engaging with your community, you can build a strong, loyal audience for your streaming channel. Remember to stay authentic and true to your content – your genuine passion will be your best promotional tool.




# How to use the green screen just locally

Since OBS is using a very old browser inside, the green screen effect inside [VDO.Ninja](https://vdo.ninja/) wouldn't really run well within OBS itself, and even if it did, accessing the camera from a browser-source is a hassle to setup.

&#x20;What you could do though is use the Electron Capture app, and then just window capture the local preview output. You can hide the interface UI and access any camera/microphone changes via the Electron Capture's right-click context menu of options instead.

Electron download link: [https://github.com/steveseguin/electroncapture/releases](https://github.com/steveseguin/electroncapture/releases)\
\
Getting this working is not complex; pretty easy once you do it once actually. Sample URL to enter into VDO.Ninja:

[`https://vdo.ninja/?cleanoutput&webcam&effects=4`](https://vdo.ninja/?cleanoutput\&webcam\&effects=4)

.png>)

Cheers.




# How to use VDO.Ninja as a webcam for Google Hangouts, Zoom, and more

In this walk-through we demonstrate how to use VDO.Ninja and the OBS Virtual Camera to bring remote cameras, smartphones, and other media sources into third-party video software as a virtual webcam.

We will also be including audio in this guide, however that may not be needed in all situations. You can skip the audio-related portions if not needed for your application.

{% hint style="info" %}
Some third-party applications support Browser Sources as an input, negating the need for a virtual camera, as VDO.Ninja can be used directly in such scenarios.
{% endhint %}

\
**Requirements for this guide**

* OBS Studio V26 or newer
* Virtual Audio Cable Software               &#x20;
  * For Windows, use VB-CABLE Virtual Audio
    * This is recommended software as it enables proper audio support
    * The software is Donationware
    * [https://www.vb-audio.com/Cable/](https://www.google.com/url?q=https://www.vb-audio.com/Cable/\&sa=D\&source=editors\&ust=1651965669921223\&usg=AOvVaw32Nu8pxk1d3BG6A39I2slb)\

  * For macOS, you have a few choices:
    * &#x20;[https://github.com/steveseguin/vdo.ninja/wiki/FAQ#how-to-capture-audio-on-mac](https://github.com/steveseguin/vdo.ninja/wiki/FAQ#how-to-capture-audio-on-mac)

**Basic Workflow Diagram**

Please find below a diagram explaining the basic premise of what we are intending to do in this guide. We will go through it all, one step at a time.

 (1).png>)

### **Step 0. - Installing dependencies**

This guide assumes you have OBS installed, along with the other required software, though we shall briefly cover these initial installation steps now.

We also will assume you are using Windows. You will need to adapt accordingly for macOS, which likely is going to be more complicated.&#x20;

On the computer that will be using Zoom or Google Hangouts to broadcast, please do the following:

1. Install OBS Studio  h[ttps://github.com/obsproject/obs-studio/releases/](https://www.google.com/url?q=https://github.com/obsproject/obs-studio/releases/\&sa=D\&source=editors\&ust=1651965669925129\&usg=AOvVaw2y3_HZy3Sm_0aAQ7QRRX8K)
2. Install the VB-Cable Virtual Audio device.\
   [https://www.vb-audio.com/Cable/](https://www.google.com/url?q=https://www.vb-audio.com/Cable/\&sa=D\&source=editors\&ust=1651965669925809\&usg=AOvVaw3k4NHvzmWNnuxOnB2nnoYZ)

### **Step 1.** &#x20;

Generate an VDO.Ninja invite. You will get an Invite link and a Browser Source link.

The <mark style="color:red;">Guest Invite Link</mark> is what you send to a person who you wish to join your live stream in OBS.  We will also be calling this a PUSH link, as it contains \&push in the URL.&#x20;

The <mark style="color:green;">OBS Browser Source link</mark> is what we will be putting into OBS to capture our guest’s video stream with.  We will also be calling this a VIEW link, as it contains \&view in the URL.

<figure><figcaption></figcaption></figure>

 (1) (1).png>)

### Step 2.

For ease of setup, the "Generate Invite Link" button found at [VDO.Ninja](https://vdo.ninja) can provide you with both a <mark style="color:red;">PUSH (</mark><mark style="color:red;">**Guest Invite**</mark><mark style="color:red;">) link</mark> and an <mark style="color:green;">VIEW (</mark><mark style="color:green;">**OBS Source**</mark><mark style="color:green;">) link.</mark> &#x20;

We will want to send the PUSH link to our guest, or if using a mobile phone, use the QR code to open the link. We can select our camera, microphone, and then click START.

 (1) (1).png>)

### Step 3.

Once we have our PUSH link setup to stream our camera, we can move on to pulling that video stream into OBS using the VIEW link.

To setup our OBS Studio, create a Scene and then add a Browser Source in OBS Studio. Give it a name and we will fill out the details in the next step.

### Step 4.

In the properties for the Browser Source, we need to fill out a few fields and then hit OK.

* The URL we add to OBS needs to be set to the VIEW address we created earlier,  \
  Just as example: `https://vdo.ninja/?view=q3QCScW`\
  You will of course need to use your own link, with its own unique view ID, which was given to you at the end of Step #1.  The view ID should exactly make the push ID; case-sensitive.
* Width can be set to 1280
* The height be set to 720
* "<mark style="color:green;">**Control audio via OBS**</mark>" should be checked. This is quite important, else the audio will not work correctly or you will get a terrible echo / feedback.

 (1).png>)

{% hint style="info" %}
_SECRET TIP_: Some links in VDO.Ninja can be dragged and dropped directly into OBS from the Chrome browser, avoiding the tedious parts of step 2 and 3. You will still need to select “Control audio via OBS” however, if you wish audio to function.
{% endhint %}

### Step 5.

The video should appear and auto-play. There should be no audio feedback if you selected the Control audio via OBS option.

Now we just need to stretch the video to fill the full scene. It should snap into place when full.

<figure><figcaption></figcaption></figure>

### Step 6.

Start the OBS Virtual camera ; located under the Start Recording button

<div align="left"><figure><figcaption></figcaption></figure></div>

### Step 7. (optional)

We will now configure OBS to output audio from the Browser Source to the Virtual Audio Cable.  In the OBS settings, under Advanced, we select the Monitoring Device to be our Virtual Audio device. (CABLE Input). &#x20;

We also want to disable Windows audio ducking.

### Step 8. (optional)

In our last configuration step, we want to go into the Advanced Audio Properties in OBS. When there, we want to set the audio sources we want to output have its Audio Monitoring setting be set to Monitor and Output.

If you intend to feed audio from OBS back into an VDO.Ninja group call, you can use this step to also mix-minus the audio; selecting just the audio sources you want the remote guests to hear, excluding their own audio to prevent echo.

<div align="left"><figure><figcaption></figcaption></figure></div>

<figure><figcaption></figcaption></figure>

### Step 9.

We’re READY to go!  Using this setup in VDO.Ninja or Zoom or Google Hangouts is just like selecting a second Webcam and microphone.

If you are already in the Zoom / Google Hangout call, you can switch between your webcam and the virtual camera and normal camera in the settings.

It is important to remember that you need to select the VB-Audio Virtual Cable in the call as well, if you also want to share the audio from it that is.

If publishing to VDO.Ninja, remember that you can select multiple audio sources in VDO.Ninja by holding down CTRL (or command) when selecting them. You could include the VB Audio Cable and your local microphone together, for example.

<div align="left"><figure><figcaption></figcaption></figure></div>

<div align="left"><figure><figcaption></figcaption></figure></div>

### All done!

And that should be it! You can switch between the webcam and the OBS live video as needed.

If you need to increase the video quality from the defaults, all that is possible in the next section, linked below:

{% content-ref url="how-do-i-control-bitrate-quality.md" %}
[how-do-i-control-bitrate-quality.md](how-do-i-control-bitrate-quality.md)
{% endcontent-ref %}




---
description: Streaming PlayStation or Xbox Output to VDO.Ninja
---

# PlayStation or Xbox to VDO.Ninja

This guide covers different methods for sharing your console gameplay through VDO.Ninja. VDO.Ninja allows you to easily share high-quality, low-latency video streams with others online.

### Method 1: Browser-Compatible Capture Card

Some HDMI capture cards work directly with browsers, allowing you to bypass OBS entirely:

1. Connect your PlayStation or Xbox to a browser-compatible capture card
2. Plug the capture card into your computer
3. In VDO.Ninja:
   * Select "Add your Camera"
   * Choose the capture card as your video source

This method offers a streamlined setup with low latency and high quality.

### Method 2: PS Remote Play with Screen Sharing

For a hardware-free solution:

#### PlayStation:

1. Install PS Remote Play on your computer
2. Connect your PlayStation to PS Remote Play
3. In VDO.Ninja:
   * Select "Share Your Screen"
   * Choose to share the PS Remote Play window
   * Optionally select system audio to share game sound

#### Xbox:

1. Install the Xbox app on your Windows 10 or 11 PC
2. Connect your Xbox to the Xbox app using Remote Play
3. In VDO.Ninja:
   * Select "Share Your Screen"
   * Choose to share the Xbox app window
   * Optionally select system audio to share game sound

This approach is simple but may have slightly higher latency.

### Method 4: Xbox-Specific Streaming (Windows 10/11 Only)

Xbox offers a built-in streaming feature for Windows 10 and 11 users:

1. Press the Windows key + G to open the Xbox Game Bar
2. Click on "Capture" and select "Start Recording"
3. In VDO.Ninja:
   * Select "Share Your Screen"
   * Choose to share the game window or entire screen
   * Ensure system audio is selected to share game sound

This method provides good quality and relatively low latency for Xbox users.

Remember to adjust your console's privacy and streaming settings to enable remote play and streaming features.

### Method 5: Capture Card with OBS Virtual Camera

For capture cards not directly compatible with browsers:

1. Connect your PlayStation to the capture card
2. In OBS Studio:
   * Add a "Video Capture Device" source for your capture card
   * Start the OBS Virtual Camera
3. In VDO.Ninja:
   * Select "Add your Camera"
   * Choose the OBS Virtual Camera as your video source

This method allows for more advanced stream customization but adds an extra step.

### Additional Considerations

* HDMI Splitters: If you want to play on a TV while streaming, use an HDMI splitter to send the signal to both your capture device and TV.
  * Some HDMI capture devices have an HDMI pass-through option, which can be used in place of an HDMI splitter.
* Audio Routing: Consider using a virtual audio cable to route game audio to VDO.Ninja if not captured by your chosen method
* Latency: Browser-compatible capture cards generally offer the lowest latency when used directly with VDO.Ninja.
  * Some HDMI to USB capture devices are only compatible with OBS Studio and not the browser; a browser-compatible device is suggested.
* Quality Settings: Experiment with VDO.Ninja's bitrate and resolution settings for optimal performance.

By leveraging VDO.Ninja's browser-based capabilities, you can often achieve a simpler setup with compatible capture cards, while still having the flexibility to use OBS when needed for more complex streaming scenarios.\

## HDMI Splitter / pass-thru considerations

When considering HDMI splitters with pass-through for 4K content, it's important to understand their compatibility with various resolutions and frame rates:

### 4K Resolution and Frame Rate Compatibility

HDMI splitters with pass-through for 4K content typically support the following:

* 4K resolution (3840 x 2160 pixels)
* Frame rates up to 60fps for 4K content

However, compatibility can vary depending on the specific splitter model and HDMI version.

### Key Considerations

### HDMI Version

* HDMI 2.0 supports 4K at 60fps
* HDMI 1.4 supports 4K at 30fps

Ensure your splitter uses the appropriate HDMI version for your desired resolution and frame rate.

### Bandwidth

4K content requires significant bandwidth, especially at higher frame rates. Look for splitters that support:

* 18 Gbps bandwidth for 4K60 HDR
* 10.2 Gbps bandwidth for 4K30

### HDR Support

If you want to pass through HDR content, make sure the splitter explicitly supports it.

### HDCP Compatibility

For copy-protected content, ensure the splitter is compatible with HDCP 2.2 or later.

### Trade-offs

When using a splitter with pass-through, be aware of potential trade-offs:

* Some splitters may introduce slight latency
* Lower-quality splitters might degrade signal quality

### Recommendations

1. Choose a splitter that matches or exceeds your highest required resolution and frame rate.
2. Opt for HDMI 2.0 or higher for the best 4K compatibility.
3. Ensure the splitter supports the necessary bandwidth for your content.
4. Verify HDR and HDCP compatibility if needed.

By carefully considering these factors, you can select an HDMI splitter with pass-through that maintains the quality of your 4K content while allowing you to share it across multiple displays or capture devices.




---
description: hotkey features via API and MIDI
---

# API & MIDI Parameters

<table><thead><tr><th width="213.75007715635093">Parameter</th><th width="446.4285714285714">Explanation</th></tr></thead><tbody><tr><td><a href="../../general-settings/api.md"><code>&#x26;api</code></a></td><td>Remote control API (HTTP-GET / WSS-based)</td></tr><tr><td><a href="../../general-settings/pie.md"><code>&#x26;pie</code></a></td><td>Support for piesocket.com</td></tr><tr><td><a href="../../midi-settings/midiin.md"><code>&#x26;midi</code></a></td><td>Global hotkey support via MIDI input and more</td></tr><tr><td><a href="../../midi-settings/midiin.md"><code>&#x26;midiin</code></a></td><td>Allows for receiving of remote MIDI</td></tr><tr><td><a href="../../midi-settings/midiout.md"><code>&#x26;midiout</code></a></td><td>Broadcast MIDI commands to a remote computer's virtual MIDI device</td></tr><tr><td><a href="../../director-settings/midiremote.md"><code>&#x26;midiremote</code></a></td><td>Remote MIDI control</td></tr><tr><td><a href="../../midi-settings/and-midichannel.md"><code>&#x26;midichannel</code></a></td><td>Allows for specifying which midi channel (1 to 16) to listen on</td></tr><tr><td><a href="../../midi-settings/and-mididevice.md"><code>&#x26;mididevice</code></a></td><td>Allows to specify which midi device (1 and up) selected</td></tr><tr><td><a href="../../midi-settings/and-midioffset.md"><code>&#x26;midioffset</code></a></td><td>Allows you to set a series of buttons on a MIDI controller to be mute controls for those guests</td></tr><tr><td><a href="and-mididelay.md"><code>&#x26;mididelay</code></a></td><td>Lets you precisely delay the MIDI play-out</td></tr><tr><td><a href="../../newly-added-parameters/and-datamode.md"><code>&#x26;datamode</code></a></td><td>Combines a bunch of flags together; no video, no audio, GUI, etc.</td></tr><tr><td><a href="and-postapi.md"><code>&#x26;postapi</code></a></td><td>Lets you specify a custom POST URL to send events within VDO.Ninja to</td></tr></tbody></table>




---
description: Lets you precisely delay the MIDI play-out
---

# \&mididelay

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Options

Example: `&mididelay=1000`

| Value           | Description |
| --------------- | ----------- |
| (numeric value) | delay in ms |

## Details

`&mididelay=1000` lets you precisely delay the MIDI play-out from VDO.Ninja to your MIDI device when using [`&midiin`](../../midi-settings/midiin.md), irrespective of network latency.

Use case: If you have a remote drum machine, you can have it play out the beat exactly 4-bars ahead, allowing for music jamming types with even high ping delays between locations.

## Related

{% content-ref url="../../midi-settings/midi.md" %}
[midi.md](../../midi-settings/midi.md)
{% endcontent-ref %}

{% content-ref url="../../midi-settings/midiin.md" %}
[midiin.md](../../midi-settings/midiin.md)
{% endcontent-ref %}




---
description: Lets you specify a custom POST URL to send events within VDO.Ninja to
---

# \&postapi

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&posturl`

## Options

Example: `&postapi=https%3A%2F%2Fwebhook.site%2Fb190f5bf-e4f8-454a-bd51-78b5807df9c1`

<table><thead><tr><th width="203">Value</th><th>Description</th></tr></thead><tbody><tr><td>(custom POST URL)</td><td>Data JSON encoded, post URL requires HTTPS+CORS, and the passed URL parameter value needs to be encodedURLComponent</td></tr></tbody></table>

## Details

`&postapi` lets you specify a custom POST URL to send events within VDO.Ninja to.

Data JSON encoded, post URL requires HTTPS+CORS, and the passed URL parameter value needs to be encodedURLComponent.\
ie: `&postapi=https%3A%2F%2Fwebhook.site%2Fb190f5bf-e4f8-454a-bd51-78b5807df9c1`

If you don't want to listen for events with the websocket server API I host, you can use this with your own API https server instead and get key events pushed to you that way.

<div align="left">

<figure><figcaption></figcaption></figure>

</div>




# API reference - alt version

## VDO.Ninja Remote Control API Documentation

### Overview

VDO.Ninja's Remote Control API allows programmatic control of VDO.Ninja sessions via HTTP or WebSocket connections. This powerful API enables integration with stream decks, custom applications, and automation tools for controlling cameras, microphones, layouts, and other features.

### Basic Setup

To enable the API on any VDO.Ninja instance, add the `&api` parameter with a unique API key:

```
https://vdo.ninja/?api=YOUR_UNIQUE_API_KEY&webcam
```

This key must be kept private and will be used to authenticate API requests. The same key must be used when making API calls to control this specific VDO.Ninja instance.

### Connection Methods

The API supports three connection methods:

1. **WebSocket API** (recommended for real-time control)
2. **HTTP GET API** (good for simple controllers and hotkeys)
3. **Server-Sent Events** (SSE) for one-way event monitoring

#### WebSocket API

Connect to `wss://api.vdo.ninja:443` and authenticate with your API key:

```javascript
const socket = new WebSocket("wss://api.vdo.ninja:443");

socket.onopen = function() {
    // Join with your API key
    socket.send(JSON.stringify({"join": "YOUR_UNIQUE_API_KEY"}));
    
    // After joining, you can send commands
    socket.send(JSON.stringify({
        "action": "mic", 
        "value": false // mute microphone
    }));
};

// Listen for responses and events
socket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    console.log("Received:", data);
};
```

#### HTTP GET API

Structure: `https://api.vdo.ninja/{apiKey}/{action}/{target}/{value}`

Examples:

```
https://api.vdo.ninja/YOUR_UNIQUE_API_KEY/mic/false       // Mute microphone
https://api.vdo.ninja/YOUR_UNIQUE_API_KEY/camera/toggle   // Toggle camera
```

#### Server-Sent Events (SSE)

For monitoring events without sending commands:

```javascript
const eventSource = new EventSource(`https://api.vdo.ninja/sse/YOUR_UNIQUE_API_KEY`);
eventSource.onmessage = function(event) {
    console.log(JSON.parse(event.data));
};
```

### API Commands Reference

#### Self-Targeted Commands

These commands affect the local VDO.Ninja instance that has the API key enabled.

| Action              | Value Options                 | Description                                |
| ------------------- | ----------------------------- | ------------------------------------------ |
| `mic`               | `true`, `false`, `toggle`     | Control microphone state                   |
| `camera`            | `true`, `false`, `toggle`     | Control camera state                       |
| `speaker`           | `true`, `false`, `toggle`     | Control speaker state                      |
| `volume`            | `0` to `200`                  | Set playback volume (percentage)           |
| `bitrate`           | Integer (kbps), `-1` for auto | Set video bitrate                          |
| `record`            | `true`, `false`               | Control local recording                    |
| `hangup`            | N/A                           | Disconnect current session                 |
| `reload`            | N/A                           | Reload the page                            |
| `sendChat`          | Text string                   | Send a chat message                        |
| `togglehand`        | N/A                           | Toggle raised hand status                  |
| `togglescreenshare` | N/A                           | Toggle screen sharing                      |
| `forceKeyframe`     | N/A                           | Force video keyframes ("rainbow puke fix") |
| `getDetails`        | N/A                           | Get detailed state information             |
| `getGuestList`      | N/A                           | Get list of connected guests with IDs      |

#### Layout Control Commands

| Action   | Value                    | Description                          |
| -------- | ------------------------ | ------------------------------------ |
| `layout` | `0` or `false`           | Switch to auto-mixer layout          |
| `layout` | Integer (`1`, `2`, etc.) | Switch to specific predefined layout |
| `layout` | Layout object/array      | Apply custom layout configuration    |

#### Camera Control (PTZ) Commands

| Action     | Value                              | Description                        |
| ---------- | ---------------------------------- | ---------------------------------- |
| `zoom`     | `-1.0` to `1.0`                    | Adjust zoom level (relative)       |
| `zoom`     | `0.0` to `1.0` with `value2="abs"` | Set absolute zoom level            |
| `focus`    | `-1.0` to `1.0`                    | Adjust focus (relative)            |
| `pan`      | `-1.0` to `1.0`                    | Adjust camera pan (negative=left)  |
| `tilt`     | `-1.0` to `1.0`                    | Adjust camera tilt (negative=down) |
| `exposure` | `0.0` to `1.0`                     | Adjust camera exposure             |

#### Group Communication Commands

| Action           | Value      | Description                             |
| ---------------- | ---------- | --------------------------------------- |
| `group`          | `1` to `8` | Toggle participation in specified group |
| `joinGroup`      | `1` to `8` | Join a specific group                   |
| `leaveGroup`     | `1` to `8` | Leave a specific group                  |
| `viewGroup`      | `1` to `8` | Toggle view of specified group          |
| `joinViewGroup`  | `1` to `8` | View a specific group                   |
| `leaveViewGroup` | `1` to `8` | Stop viewing a specific group           |

#### Timer Commands

| Action           | Value             | Description                    |
| ---------------- | ----------------- | ------------------------------ |
| `startRoomTimer` | Integer (seconds) | Start countdown timer for room |
| `pauseRoomTimer` | N/A               | Pause the room timer           |
| `stopRoomTimer`  | N/A               | Stop and reset the room timer  |

#### Presentation Control

| Action      | Value                     | Description                                        |
| ----------- | ------------------------- | -------------------------------------------------- |
| `nextSlide` | N/A                       | Advance to next slide (for PowerPoint integration) |
| `prevSlide` | N/A                       | Go to previous slide                               |
| `soloVideo` | `true`, `false`, `toggle` | Highlight video for all guests                     |

#### Director-Only Guest Commands

These commands target specific guests when you are the director.

| Action                  | Target        | Value                     | Description                      |
| ----------------------- | ------------- | ------------------------- | -------------------------------- |
| `forward`               | Guest ID/slot | Room name                 | Transfer guest to another room   |
| `addScene`              | Guest ID/slot | Scene ID (1-8)            | Toggle guest in/out of scene     |
| `muteScene`             | Guest ID/slot | Scene ID                  | Toggle guest's audio in scene    |
| `mic`                   | Guest ID/slot | `true`, `false`, `toggle` | Control guest's microphone       |
| `hangup`                | Guest ID/slot | N/A                       | Disconnect a specific guest      |
| `soloChat`              | Guest ID/slot | N/A                       | Private chat with guest          |
| `soloChatBidirectional` | Guest ID/slot | N/A                       | Two-way private chat             |
| `speaker`               | Guest ID/slot | N/A                       | Toggle guest's speaker           |
| `display`               | Guest ID/slot | N/A                       | Toggle guest's display           |
| `forceKeyframe`         | Guest ID/slot | N/A                       | Fix video artifacts for guest    |
| `soloVideo`             | Guest ID/slot | N/A                       | Highlight specific guest's video |
| `volume`                | Guest ID/slot | `0` to `100`              | Set guest's microphone volume    |
| `mixorder`              | Guest ID/slot | `-1` or `1`               | Change guest's position in mixer |

### Target Parameter Explanation

When using director commands, you can specify targets in two ways:

1. **Slot number**: Simple integers like `1`, `2`, `3` (corresponds to position in room)
2. **Stream ID**: The unique ID for a specific guest (more reliable as slots can change)

Examples:

```javascript
// Target guest in slot 1
{"action": "mic", "target": 1, "value": false}

// Target guest with specific stream ID
{"action": "mic", "target": "abc123xyz", "value": false}
```

### Callbacks and Responses

API commands receive callbacks with the current state after execution:

```javascript
// WebSocket example response when toggling mic
{
  "callback": {
    "action": "mic",
    "value": "toggle",
    "result": false  // Indicates mic is now muted
  }
}
```

### Custom Layout Format

The layout API supports complex scene configurations. Layouts can be arrays of objects with properties:

```javascript
// Simple layout with two videos
{
  "action": "layout",
  "value": [
    {"x": 0, "y": 0, "w": 50, "h": 100, "slot": 0},
    {"x": 50, "y": 0, "w": 50, "h": 100, "slot": 1}
  ]
}
```

Layout object properties:

* `x`, `y`: Position (percentage of canvas)
* `w`, `h`: Width and height (percentage)
* `slot`: Which video slot to display (0-indexed)
* `z`: Z-index for layering (optional)
* `c`: Cover mode (true/false, optional)

### Implementation Examples

#### Python Example

```python
import websockets
import asyncio
import json

async def control_camera():
    async with websockets.connect("wss://api.vdo.ninja:443") as websocket:
        # Join with API key
        await websocket.send(json.dumps({"join": "YOUR_API_KEY"}))
        
        # Zoom in camera
        await websocket.send(json.dumps({
            "action": "zoom",
            "value": 0.5,
            "value2": "abs"
        }))
        
        # Wait for response
        response = await websocket.recv()
        print(f"Response: {response}")

asyncio.run(control_camera())
```

#### JavaScript HTTP Example

```javascript
// Toggle microphone via HTTP
fetch("https://api.vdo.ninja/YOUR_API_KEY/mic/toggle")
    .then(response => response.text())
    .then(result => console.log("Mic toggled, new state:", result));
```

### Integration with Automation Tools

The API integrates well with:

1. **BitFocus Companion**: Official module available at [github.com/bitfocus/companion-module-vdo-ninja](https://github.com/bitfocus/companion-module-vdo-ninja)
2. **Stream Deck**: Can use HTTP requests for button actions
3. **Node-RED**: Great for complex automation workflows
4. **Home Assistant**: For smart home integration

### Security Considerations

* Keep your API key private
* Consider using unique keys for different productions
* The API has full control over the VDO.Ninja instance it's connected to
* All connections are encrypted over SSL/TLS

### Troubleshooting

* Ensure the API key matches exactly between VDO.Ninja and your requests
* For WebSocket connections, implement reconnection logic (connections timeout after \~1 minute of inactivity)
* When using HTTP API, a `timeout` response means the request couldn't reach the target

### Additional Resources

* Complete API documentation: [github.com/steveseguin/Companion-Ninja](https://github.com/steveseguin/Companion-Ninja)
* Interactive demo: [companion.vdo.ninja](https://companion.vdo.ninja)
* For Python implementations: See the Python sample in the repository

### Advanced Usage: Self-Hosting the API

For production environments, you can self-host the API server:

1. Clone the repository from GitHub
2. Install dependencies with `npm install`
3.  Modify the server URL in your VDO.Ninja instances:

    ```javascript
    session.apiserver = "wss://your-custom-domain:443";
    ```
4. Run the server with proper SSL certificates

Note: Self-hosting support is limited and should only be attempted by experienced developers.




---
description: This is a snapshot of the VDO.Ninja API documentation as of Aug 16th, 2023
---

# API reference

For the most up to date copy of this API endpoint documentation, please go to [https://github.com/steveseguin/Companion-Ninja/#readme](https://github.com/steveseguin/Companion-Ninja/#readme)

For a test sandbox, to easily try out a few of the basic API options via a web dashboard, please go to: [https://companion.vdo.ninja/](https://companion.vdo.ninja/)

You can use this API on its own directly, or can use it indirectly via the Bitfocus Companion app /w the VDO.Ninja module.  The Companion app can be found here: [https://bitfocus.io/companion](https://bitfocus.io/companion)

While not maintained or controlled by VDO.Ninja, you can find the third-party Bitfocus Companion module for VDO.Ninja here: [https://github.com/bitfocus/companion-module-vdo-ninja](https://github.com/bitfocus/companion-module-vdo-ninja)

## Companion Ninja _(aka, the VDO.Ninja remote HTTP/WSS API)_

Remote control VDO.Ninja using an HTTP or Websocket interface; now Companion compatible.

#### Direct integration into VDO.Ninja

Support for Companion.Ninja is now built into VDO.Ninja (v19), with a set of hard-coded commands. The available API commands and their related options are listed further down. The index.html file contains sample code with an interactive layer, where you can press buttons to send commands to VDO.Ninja. HTTP and Websocket methods of sending commands are provided as examples. Details of those two methods are also below.

To use the integrated command set and API, just add \&api=XXXXXX to the VDO.Ninja link you wish to remotely control, like you would any other parameter. ie: https://vdo.ninja?api=XXXXXX The API value needs to match the value used by Companion Ninja and should be kept private. Then just send commands however you may wish.

Note: This API should also work with the vdo.ninja/beta/mixer?api=XXXXX page.

#### Companion Plugin

A fantastic user in the community also has made a BitFocus-Companion module for this VDO.Ninja API. If you wish to avoid doing custom API calls, definitely give the module a go.

[https://github.com/bitfocus/companion-module-vdo-ninja](https://github.com/bitfocus/companion-module-vdo-ninja)

#### Customized IFRAME API Integration

You can also use the Companion Ninja service with your own custom set of commands if desired. You would wrap VDO.Ninja into an IFRAME, and use the parent-window to relay commands to VDO.Ninja and Companion Ninja. You can speak to VDO.Ninja via the IFRAME API in that case, to have access to the more exhaustive set of remote control options.

An example of this approach can be found here:

[https://github.com/steveseguin/Companion-Ninja/blob/main/iframe\_api\_customizable\_example.html](https://github.com/steveseguin/Companion-Ninja/blob/main/iframe_api_customizable_example.html)

Also note, the IFRAME API used by VDO.Ninja (v19.1) is also largely backwards compatible with the Companion Ninja API. You can find the IFRAME developer sandbox here: [https://vdo.ninja/beta/iframe](https://vdo.ninja/beta/iframe) to get a sense of what is available.

#### Technical Details of the API

The API is likely to change over time, as this is still early days and user feedback with direct how things evolve. More commands added on request.

**HTTP/GET API (/w SSL)**

The HTTP API uses GET-requests (not POST/PUT), and is structured in a way to be compatible with existing hotkey control software.

`https://api.vdo.ninja/{apiID}/{action}/{target}/{value}`

or

`https://api.vdo.ninja/{apiID}/{action}/{value}`

or

`https://api.vdo.ninja/{apiID}/{action}`

Any field can be replaced with "null", if no value is being passed to it. Double slashes will cause issues though, so avoid those.

**Websocket API**

If using the Websocket API, this accepts JSON-based commands

connect to: `wss://api.vdo.ninja:443`

On connection, send: `{"join": $apiID }`, where `$apiID` is your api ID.

* be sure to stringify objects as JSON before sending over the websocket connection. ie: `JSON.stringify(object)`

Once joined, you can then issue commands at will, such as this object

```
{
  "action":"reload",
  "value": "true",
  "target" "null"
}
```

Be sure to implement reconnection logic with the websocket connection, as it will timeout every minute or so by default otherwise. You will need to rejoin after a timeout.

**API Commands**

The API and its commands are currently in a DRAFT form, and as such, may/will undergo change.

| Action            | Target | Value                             | Details                                                                                                                                                       |
| ----------------- | ------ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| speaker           | null   | true                              | Unmute the Local Speaker                                                                                                                                      |
| speaker           | null   | false                             | Mute the Local Speaker                                                                                                                                        |
| speaker           | null   | toggle                            | Toggle the state of the local Speaker                                                                                                                         |
| mic               | null   | true                              | Unmute the local Microphone                                                                                                                                   |
| mic               | null   | false                             | Mute the local Microphone                                                                                                                                     |
| mic               | null   | toggle                            | Toggle the state of the local Microphone                                                                                                                      |
| camera            | null   | true                              | Unmute local Camera                                                                                                                                           |
| camera            | null   | false                             | Mute local Camera                                                                                                                                             |
| camera            | null   | toggle                            | Toggle the state of the local Camera                                                                                                                          |
| volume            | null   | true                              | Mutes all local audio tracks by setting the volume to 0%                                                                                                      |
| volume            | null   | false                             | Sets the playback volume of all audio tracks to 100%                                                                                                          |
| volume            | null   | {integer value between 0 and 100} | Sets the playback volume of all local playback audio                                                                                                          |
| sendChat          | null   | {some chat message}               | Sends a chat message to everyone connected. Better suited for the websocket API over the HTTP one.                                                            |
| record            | null   | true                              | Start recording the local video stream to disk; will probably create a popup currently                                                                        |
| record            | null   | false                             | Stops recording the local video stream                                                                                                                        |
| reload            | null   | null                              | Reload the current page                                                                                                                                       |
| hangup            | null   | null                              | Hang up the current connection. For the director, this just stops the mic and camera mainly.                                                                  |
| bitrate           | null   | true                              | Unlock/reset bitrate of all currently incoming video                                                                                                          |
| bitrate           | null   | false                             | Pause all currently incoming video streams (bitrate to 0)                                                                                                     |
| bitrate           | null   | {some integer}                    | Set video bitrate of all incoming video streams to target bitrate in kilobits per second.                                                                     |
| panning           | null   | true                              | Centers the pan                                                                                                                                               |
| panning           | null   | false                             | Centers the pan                                                                                                                                               |
| panning           | null   | {an integer between 0 and 180}    | Sets the stereo panning of all incoming audio streams; left to right, with 90 being center.                                                                   |
| togglehand        | null   | null                              | Toggles whether your hand is raised or not                                                                                                                    |
| togglescreenshare | null   | null                              | Toggles screen sharing on or off; will still ask you to select the screen though.                                                                             |
| forceKeyframe     | null   | null                              | Forces the publisher of a stream to issue keyframes to all viewers; "rainbow puke fix"                                                                        |
| group             | null   | {an integer between 1 and 8}      | Toggle the director of a room in/out of a specified group room (vdo.ninja +v22). Useful for Comms app, etc                                                    |
| joinGroup         | null   | {an integer between 1 and 8}      | Have the director of a room join a specified group room (vdo.ninja +v22.12)                                                                                   |
| leaveGroup        | null   | {an integer between 1 and 8}      | Have the director of a room leave a specified group room (vdo.ninja +v22.12)                                                                                  |
| viewGroup         | null   | {an integer between 1 and 8}      | Toggle the director of a room's preview of a specific group (vdo.ninja +v22). Useful for Comms app, etc                                                       |
| joinViewGroup     | null   | {an integer between 1 and 8}      | Have the director of a room preview a specific group (vdo.ninja +v22.12)                                                                                      |
| leaveViewGroup    | null   | {an integer between 1 and 8}      | Have the director of a room un-preview a specific group (vdo.ninja +v22.12)                                                                                   |
| getDetails        | null   | null                              | Will return a JSON object containing detailed state of everything. If a director, this will contain guest-state as seen by the director.                      |
| nextSlide         | null   | null                              | Next PowerPoint slide. See https://github.com/steveseguin/powerpoint\_remote for setup (vdo.ninja +v22.12)                                                    |
| prevSlide         | null   | null                              | Previous PowerPoint slide. See https://github.com/steveseguin/powerpoint\_remote for setup (vdo.ninja +v22.12)                                                |
| soloVideo         | null   | toggle                            | Toggle the Highlight of video for all guests (if a director) (vdo.ninja +v23)                                                                                 |
| soloVideo         | null   | true                              | Highlight your video for all guests (if a director) (vdo.ninja +v23)                                                                                          |
| soloVideo         | null   | false                             | Un-highlight your video for all guests (if a director) (vdo.ninja +v23)                                                                                       |
| stopRoomTimer     | null   | null                              | Stop the timer for everyone in the room (if a director) (vdo.ninja +v23.9)                                                                                    |
| startRoomTimer    | null   | Integer to count down from        | Value to count down from is in seconds in the room; applies to everyone in a room (if a director) (vdo.ninja +v23.9)                                          |
| PauseRoomTimer    | null   | null                              | Pause the timer for all everyone in the room (if a director) (vdo.ninja +v23.9)                                                                               |
| getGuestList      | null   | null                              | Returns an object containing the guest slots positional values, so "1", "2", etc. Each is a key that contains the stream ID and label for that guest as well. |

layout | null | {\*\* see below}

**Custom layout switching \*\***

You can create an array of layouts, set them via the URL parameters in VDO.Ninja, and then switch between them remotely using the API.

The value passed to the API can either be a number, representing the position in the array of the layout you want to activate, or it can be a single layout object.

`{action: "layout", value:3}` or `{action: "layout", value:[{"x":0,"y":0,"w":100,"h":100,"slot":0}]}`

```
layout 0 is the auto mixer
layout 1 is the first custom layout
layout 2 is the second custom layout
etc
```

If using the [Mixer App](../../../steves-helper-apps/mixer-app.md), the layout objects are controlled via the mixer app itself, so you don't need to pass an object in that case to the URL.

`?layouts=[[{"x":0,"y":0,"w":100,"h":100,"slot":0}],[{"x":0,"y":0,"w":100,"h":100,"slot":1}],[{"x":0,"y":0,"w":100,"h":100,"slot":2}],[{"x":0,"y":0,"w":100,"h":100,"slot":3}],[{"x":0,"y":0,"w":50,"h":100,"c":false,"slot":0},{"x":50,"y":0,"w":50,"h":100,"c":false,"slot":1}],[{"x":0,"y":0,"w":100,"h":100,"z":0,"c":false,"slot":1},{"x":70,"y":70,"w":30,"h":30,"z":1,"c":true,"slot":0}],[{"x":0,"y":0,"w":50,"h":50,"c":true,"slot":0},{"x":50,"y":0,"w":50,"h":50,"c":true,"slot":1},{"x":0,"y":50,"w":50,"h":50,"c":true,"slot":2},{"x":50,"y":50,"w":50,"h":50,"c":true,"slot":3}],[{"x":0,"y":16.667,"w":66.667,"h":66.667,"c":true,"slot":0},{"x":66.667,"y":0,"w":33.333,"h":33.333,"c":true,"slot":1},{"x":66.667,"y":33.333,"w":33.333,"h":33.333,"c":true,"slot":2},{"x":66.667,"y":66.667,"w":33.333,"h":33.333,"c":true,"slot":3}]]`

Some of these layout features are only available with [Version 22](../../../releases/v22.md) of VDO.Ninja; specifically the [`&layouts=`](../../director-parameters/and-layouts.md) parameter is available on v22.5 or newer only.

See for details and better documentation on this layout function:

[and-layouts.md](../../director-parameters/and-layouts.md "mention")

**Commands that target remote guests as a director (available on VDO.Ninja v19)**

The guest slot (1 to 99) or the guests's stream ID can be used as a target.

Currently toggling is primarily available for options; on/off absolute value options will be coming soon.

| Action                 | Target                    | Value                                              | Details                                                                                       |
| ---------------------- | ------------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| forward                | {guest slot or stream ID} | {destination room}                                 | Transfer guest to specified room                                                              |
| addScene               | {guest slot or stream ID} | {scene ID; 0 to 8, or an active custom scene name} | Toggle guest in/out of specified scene                                                        |
| muteScene              | {guest slot or stream ID} | {scene ID; 0 to 8, or an active custom scene name} | Toggle guest's mic audio in scenes                                                            |
| group                  | {guest slot or stream ID} | {group ID; 1 to 8}                                 | Toggle guest in/out of specified group; default group 1                                       |
| mic                    | {guest slot or stream ID} | null                                               | Toggle the mic of a specific guest                                                            |
| hangup                 | {guest slot or stream ID} | null                                               | Hangup a specific guest                                                                       |
| soloChat               | {guest slot or stream ID} | null                                               | Toggle solo chat with a specific guest                                                        |
| soloChatBidirectional  | {guest slot or stream ID} | null                                               | Toggle two-way solo chat with a specific guest                                                |
| speaker                | {guest slot or stream ID} | null                                               | Toggle speaker with a specific guest                                                          |
| display                | {guest slot or stream ID} | null                                               | Toggle whether a specific guest can see any video or not                                      |
| sendDirectorChat       | {guest slot or stream ID} | {some chat message}                                | Sends a chat message to a guest and overlays it on their screen. Expires after a few moments. |
| sendPinnedDirectorChat | {guest slot or stream ID} | {some chat message}                                | Same as sendDirectorChat, but stays until replaced with a new message                         |
| forceKeyframe          | {guest slot or stream ID} | null                                               | Trigger a keyframe for active scenes, wrt to a guest; helps resolve rainbow puke              |
| soloVideo              | {guest slot or stream ID} | null                                               | Toggle whether a video is highlighted everywhere                                              |
| volume                 | {guest slot or stream ID} | {0 to 100}                                         | Set the microphone volume of a specific remote guest                                          |
| stopRoomTimer          | {guest slot or stream ID} | null                                               | Stop the timer for the specific guest (+v23.9)                                                |
| startRoomTimer         | {guest slot or stream ID} | Integer to count down from                         | Value to count down from is in seconds (+v23.9)                                               |
| PauseRoomTimer         | {guest slot or stream ID} | null                                               | Pause the timer for the specific guest (+v23.9)                                               |

#### Callbacks / State Responses

Start with Version 22 of VDO.Ninja, the API requests will have a response reflecting the state of the request.

For example, if toggling a mic of a guest, the response of the HTTP API request will be `true` or `false`, based on whether the mic is now muted or not. If the request is an object, such as when using `getDetails`, you'll get a JSON response instead of basic text. There's also `getGuestList`, which can be useful for getting a set of possible guest slot positional values, along with its corresponding stream ID and label.

Basic text/word responses are such things as `true`, `false`, `null`, `fail`, {`somevalue`}, or `timeout`. Timeout occurs if there's no listener or no response to a request; the system will stop the callback and fail to a timeout after 1-second.

If the request was made via WebSockets, instead of the HTTP request, you'll get a JSON object back that contains the same data, along with the original request, including custom data fields. These custom data fields, such as `data.cid = 3124`, can be used to link requests with the callback, if precision with the requests is needed.

There is no time-out when using WebSockets; the callback can happen seconds or minutes later even, although normally a response should be expected in under a second as well.





---
description: Simple VDO.Ninja API WebSocket Client Example
---

# Client (node) event example

While I'm a fan of just connecting and seeing what the API outputs, based on different events/actions, here's some code to get you started with basic incoming connection detection.

## Simple VDO.Ninja API WebSocket Client Example

Here's a NodeJS example that demonstrates how to:

1. Connect to the VDO.Ninja API via WebSocket
2. Detect when streams connect or disconnect
3. Periodically poll for stream details

```javascript
const WebSocket = require('ws');

class VDONinjaMonitor {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.apiServer = 'wss://api.vdo.ninja:443';
    this.ws = null;
    this.connected = false;
    this.streams = {};
    this.reconnectTimeout = null;
    this.pollInterval = null;
  }

  // Connect to the WebSocket server
  connect() {
    console.log(`Connecting to ${this.apiServer}...`);
    
    this.ws = new WebSocket(this.apiServer);
    
    this.ws.on('open', () => {
      console.log('WebSocket connection established');
      // Join with the API key
      this.ws.send(JSON.stringify({ join: this.apiKey }));
      this.connected = true;
      
      // Start polling for details periodically
      this.startPolling();
    });
    
    this.ws.on('message', (data) => {
      try {
        const message = JSON.parse(data);
        this.handleMessage(message);
      } catch (error) {
        console.error('Error parsing message:', error);
      }
    });
    
    this.ws.on('close', () => {
      console.log('WebSocket connection closed');
      this.connected = false;
      this.stopPolling();
      this.scheduleReconnect();
    });
    
    this.ws.on('error', (error) => {
      console.error('WebSocket error:', error);
      this.stopPolling();
      this.scheduleReconnect();
    });
  }
  
  // Handle messages from the WebSocket
  handleMessage(message) {
    // Log all messages for debugging
    console.log('Received message:', JSON.stringify(message, null, 2));
    
    // Handle connection events
    if (message.action === 'guest-connected') {
      const streamID = message.streamID;
      console.log(`Stream connected: ${streamID}`);
      
      // Store stream info
      this.streams[streamID] = {
        connected: true,
        label: message.value?.label || 'Unknown',
        connectTime: new Date()
      };
      
      // You could trigger additional actions here
    }
    // Handle alternative connection event
    else if (message.action === 'push-connection' && (message.value === true || message.value === "true")) {
      const streamID = message.streamID;
      console.log(`Stream connected (via push-connection): ${streamID}`);
      
      // Store stream info or update existing
      if (!this.streams[streamID]) {
        this.streams[streamID] = {
          connected: true,
          connectTime: new Date()
        };
      } else {
        this.streams[streamID].connected = true;
        this.streams[streamID].reconnectTime = new Date();
      }
    }
    // Handle disconnection events
    else if (message.action === 'push-connection' && (message.value === false || message.value === "false")) {
      const streamID = message.streamID;
      console.log(`Stream disconnected: ${streamID}`);
      
      if (this.streams[streamID]) {
        this.streams[streamID].connected = false;
        this.streams[streamID].disconnectTime = new Date();
        
        // Optional: Remove from active streams after a period
        setTimeout(() => {
          if (this.streams[streamID] && !this.streams[streamID].connected) {
            delete this.streams[streamID];
          }
        }, 60000);
      }
    }
    
    // Handle responses to our getDetails requests
    else if (message.callback && message.callback.action === 'getDetails') {
      console.log('Received stream details:');
      
      // The result contains detailed information about all connected streams
      const details = message.callback.result;
      
      if (details && details.guests) {
        // Update our local cache with the latest details
        Object.keys(details.guests).forEach(streamID => {
          if (!this.streams[streamID]) {
            this.streams[streamID] = {
              connected: true,
              connectTime: new Date()
            };
            console.log(`Discovered stream in poll: ${streamID}`);
          }
          
          // Update stream details
          this.streams[streamID] = {
            ...this.streams[streamID],
            ...details.guests[streamID],
            lastSeen: new Date()
          };
        });
        
        // Check for streams that are in our cache but not in the response
        Object.keys(this.streams).forEach(streamID => {
          if (this.streams[streamID].connected && !details.guests[streamID]) {
            console.log(`Stream not found in poll, marking as disconnected: ${streamID}`);
            this.streams[streamID].connected = false;
            this.streams[streamID].disconnectTime = new Date();
          }
        });
      }
    }
    
    // Handle action-specific events
    else if (message.action) {
      switch (message.action) {
        case 'remote-mute-state':
          // Handle remote mute state changes
          if (message.streamID && this.streams[message.streamID]) {
            this.streams[message.streamID].remoteMuted = message.value;
            console.log(`Stream ${message.streamID} remote mute state: ${message.value}`);
          }
          break;
          
        case 'remote-video-mute-state':
          // Handle remote video mute state changes
          if (message.streamID && this.streams[message.streamID]) {
            this.streams[message.streamID].videoMuted = message.value;
            console.log(`Stream ${message.streamID} video mute state: ${message.value}`);
          }
          break;
        
        case 'director':
        case 'codirector':
          // Handle director status changes
          if (message.streamID && this.streams[message.streamID]) {
            this.streams[message.streamID].isDirector = message.value;
            console.log(`Stream ${message.streamID} director state: ${message.value}`);
          }
          break;
      }
    }
  }
  
  // Send a command to the WebSocket
  sendCommand(action, value = null, target = null) {
    if (!this.connected) {
      console.warn('Cannot send command: WebSocket not connected');
      return false;
    }
    
    const command = { action };
    if (value !== null) command.value = value;
    if (target !== null) command.target = target;
    
    try {
      this.ws.send(JSON.stringify(command));
      return true;
    } catch (error) {
      console.error('Error sending command:', error);
      return false;
    }
  }
  
  // Request updated details about all streams
  requestDetails() {
    return this.sendCommand('getDetails');
  }
  
  // Start polling for stream details
  startPolling(intervalMs = 10000) {
    this.stopPolling();
    this.pollInterval = setInterval(() => {
      this.requestDetails();
    }, intervalMs);
    
    // Initial request
    this.requestDetails();
  }
  
  // Stop polling
  stopPolling() {
    if (this.pollInterval) {
      clearInterval(this.pollInterval);
      this.pollInterval = null;
    }
  }
  
  // Schedule reconnection attempt
  scheduleReconnect(delayMs = 5000) {
    if (this.reconnectTimeout) {
      clearTimeout(this.reconnectTimeout);
    }
    
    this.reconnectTimeout = setTimeout(() => {
      console.log('Attempting to reconnect...');
      this.connect();
    }, delayMs);
  }
  
  // Get a summary of connected streams
  getStreamSummary() {
    const connectedStreams = Object.keys(this.streams).filter(id => this.streams[id].connected);
    
    console.log(`\n=== Stream Summary ===`);
    console.log(`Total tracked streams: ${Object.keys(this.streams).length}`);
    console.log(`Currently connected: ${connectedStreams.length}`);
    
    console.log(`\nConnected streams:`);
    connectedStreams.forEach(streamID => {
      const stream = this.streams[streamID];
      console.log(`- ${streamID} (${stream.label || 'Unlabeled'})`);
    });
    
    return {
      total: Object.keys(this.streams).length,
      connected: connectedStreams.length,
      streams: this.streams
    };
  }
  
  // Close the connection
  disconnect() {
    this.stopPolling();
    if (this.reconnectTimeout) {
      clearTimeout(this.reconnectTimeout);
      this.reconnectTimeout = null;
    }
    
    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
    
    this.connected = false;
  }
}

// Usage example
const API_KEY = 'YOUR_API_KEY_HERE'; // Replace with your actual API key
const monitor = new VDONinjaMonitor(API_KEY);

// Connect to the API
monitor.connect();

// Periodically print a summary of streams (every 30 seconds)
setInterval(() => {
  monitor.getStreamSummary();
}, 30000);

// Handle application shutdown
process.on('SIGINT', () => {
  console.log('Shutting down...');
  monitor.disconnect();
  process.exit(0);
});
```

### How to Use This Example

1. Save this code as `vdo-ninja-monitor.js`
2.  Install the WebSocket dependency:

    ```
    npm install ws
    ```
3. Replace `'YOUR_API_KEY_HERE'` with your actual VDO.Ninja API key
4.  Run the script:

    ```
    node vdo-ninja-monitor.js
    ```

### Key Features

This script demonstrates:

1. **WebSocket Connection**: Establishes and maintains a connection to the VDO.Ninja API
2. **Event Handling**: Detects when streams connect and disconnect
3. **Auto-Reconnection**: Reconnects if the connection drops
4. **Periodic Polling**: Requests updated details every 10 seconds
5. **Stream Tracking**: Maintains a record of all seen streams with their status

You can extend this example to:

* Send notifications when streams connect/disconnect
* Log connection events to a database
* Trigger actions based on specific stream events
* Control streams or layouts based on connection patterns

### Usage on links

Any link type that connects to a stream can use the API parameter to detect the incoming media connection status:

1. **View link**: `https://vdo.ninja/?view=streamID&api=myapikey` - Detects when the broadcaster you're viewing connects/disconnects
2. **Scene link**: `https://vdo.ninja/?scene&view=streamID&api=myapikey` - Shows the video while monitoring connection status
3. **Director link**: `https://vdo.ninja/?director=roomname&api=myapikey` - Monitors all connections in a specific room

Each option enables the WebSocket API that sends events when streams connect or disconnect. The monitoring code works with any of these link types, though director links provide the most comprehensive monitoring if you're using rooms.\
\
The key difference is which connection events you'll receive - view links only report on the specific stream being viewed, while director links report on all room participants.\
\
You can also detect events from publishers, or those pushing media streams, however each publisher may need the `&api` added to detect when they go live. When they disconnect, you may or may not get a notification from them that they are hanging up — it depends on if they do a proper hang-up or a hard-close.




---
description: Filters, adding delay, bitrate, channels, mono/stereo, muting guests etc.
---

# Audio Parameters

They are separated in three groups: [general options](./#general-options) (push and view), [source side](./#source-side-options) (push) options and [viewer side](./#viewer-side-options) (view) options.

## General options

You can add them to both, source ([`&push`](../../source-settings/push.md)) and viewer ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md) or [`&solo`](../mixer-scene-parameters/and-solo.md)) sides.

<table><thead><tr><th width="266.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-proaudio.md"><code>&#x26;proaudio</code></a></td><td>Improves the audio quality, changes default audio settings and sets the audio mode to stereo</td></tr><tr><td><a href="../../general-settings/stereo.md"><code>&#x26;stereo</code></a></td><td>Sets the audio mode to stereo and changes default audio settings to improve audio quality</td></tr><tr><td><a href="../../source-settings/and-mutespeaker.md"><code>&#x26;mutespeaker</code></a></td><td>Auto mutes the speaker</td></tr><tr><td><a href="../../general-settings/deafen.md"><code>&#x26;deafen</code></a></td><td>Audio playback is muted</td></tr><tr><td><a href="../../general-settings/noaudioprocessing.md"><code>&#x26;noaudioprocessing</code></a></td><td>Disables all webaudio audio-processing pipelines</td></tr></tbody></table>

## Source side options

You have to add them to the source side ([`&push`](../../source-settings/push.md)).

<table><thead><tr><th width="286.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../source-settings/audiodevice.md"><code>&#x26;audiodevice</code></a></td><td>Pre-configures the selected audio device</td></tr><tr><td><a href="../../source-settings/aec.md"><code>&#x26;echocancellation</code></a></td><td>Automatic echo-cancellation is ON or OFF</td></tr><tr><td><a href="and-audiogain.md"><code>&#x26;audiogain</code></a></td><td>Applies a gain multiplier (as a percentage) to the local microphone</td></tr><tr><td><a href="../../source-settings/autogain.md"><code>&#x26;autogain</code></a></td><td>Sets whether audio auto-normalization is ON or OFF</td></tr><tr><td><a href="../../source-settings/and-compressor.md"><code>&#x26;compressor</code></a></td><td>Applies a generic audio compressor to the local microphone</td></tr><tr><td><a href="../../source-settings/and-denoise.md"><code>&#x26;denoise</code></a></td><td>Turn audio noise reduction filter ON or OFF</td></tr><tr><td><a href="and-distort.md"><code>&#x26;distort</code></a></td><td>Will try to "distort" your microphone's output audio, making your voice a bit anonymous</td></tr><tr><td><a href="../../source-settings/and-equalizer.md"><code>&#x26;equalizer</code></a></td><td>Provides access to a generic audio equalizer that can be applied to the local microphone</td></tr><tr><td><a href="../../source-settings/and-limiter.md"><code>&#x26;limiter</code></a></td><td>Applies a generic audio limiter to the local microphone</td></tr><tr><td><a href="../../source-settings/lowcut.md"><code>&#x26;lowcut</code></a></td><td>Adds a low-cut filter</td></tr><tr><td><a href="../../source-settings/noisegate.md"><code>&#x26;noisegate</code></a></td><td>Lowers your mic volume to 10% of its current value based on volume-level activity</td></tr><tr><td><a href="and-noisegatesettings.md"><code>&#x26;noisegatesettings</code></a></td><td>Lets you tweak the &#x26;noisegate variables, making it more or less aggressive as needed</td></tr><tr><td><a href="and-audiocontenthint.md"><code>&#x26;audiocontenthint</code></a></td><td><code>=music</code> fixed bitrate; <code>=speech</code> bitrate is variable</td></tr><tr><td><a href="../../newly-added-parameters/and-audiolatency.md"><code>&#x26;audiolatency</code></a></td><td>Adds an audio-latency to the published audio stream</td></tr><tr><td><a href="../../source-settings/and-micdelay.md"><code>&#x26;micdelay</code></a></td><td>Delays the microphone by specified time in ms</td></tr><tr><td><a href="../../source-settings/and-mute.md"><code>&#x26;mute</code></a></td><td>Starts with the microphone muted by default</td></tr><tr><td><a href="and-automute.md"><code>&#x26;automute</code></a></td><td>Will mute the microphone of a guest when not loaded in an active OBS scene</td></tr><tr><td><a href="../../source-settings/and-outboundaudiobitrate.md"><code>&#x26;outboundaudiobitrate</code></a></td><td>Target audio bitrate and max bitrate for outgoing audio streams</td></tr><tr><td><a href="and-inputchannels.md"><code>&#x26;inputchannels</code></a></td><td>Audio capture device to select N-number of audio channels</td></tr><tr><td><a href="and-monomic.md"><code>&#x26;monomic</code></a></td><td>Sets a guest's audio input to mono (1-channel)</td></tr></tbody></table>

## **Viewer side options**

You have to add them to the viewer side ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md) or [`&solo`](../mixer-scene-parameters/and-solo.md)).

<table><thead><tr><th width="245.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../setup-parameters/and-audiooutput.md"><code>&#x26;audiooutput</code></a></td><td>Like <a href="../view-parameters/and-sink.md"><code>&#x26;sink</code></a>, but selects the audio output device</td></tr><tr><td><a href="../view-parameters/and-sink.md"><code>&#x26;sink</code></a></td><td>Outputs the audio to the specified audio output device, rather than the default</td></tr><tr><td><a href="and-volume.md"><code>&#x26;volume</code></a></td><td>Sets the 'default' playback volume for all video elements</td></tr><tr><td><a href="and-volumecontrol.md"><code>&#x26;volumecontrol</code></a></td><td>Shows a dedicated local audio-volume control bar for canvas or image elements</td></tr><tr><td><a href="../view-parameters/audiobitrate.md"><code>&#x26;audiobitrate</code></a></td><td>Manually sets the audio bitrate in kbps</td></tr><tr><td><a href="../view-parameters/vbr.md"><code>&#x26;vbr</code></a></td><td>Sets the audio bitrate to be variable, instead of constant</td></tr><tr><td><a href="../view-parameters/mono.md"><code>&#x26;mono</code></a></td><td>Has the inbound audio playback as mono audio</td></tr><tr><td><a href="../view-parameters/noaudio.md"><code>&#x26;noaudio</code></a></td><td>Delivers video only streams; audio playback is disabled</td></tr><tr><td><a href="and-nodirectoraudio.md"><code>&#x26;nodirectoraudio</code></a>*</td><td>Disables all audio playback from room directors</td></tr><tr><td><a href="../view-parameters/and-panning.md"><code>&#x26;panning</code></a></td><td>Pans the outgoing audio left or right, allowing for spatial audio group chats</td></tr><tr><td><a href="../view-parameters/sync.md"><code>&#x26;sync</code></a></td><td>Sets an offset (in ms) for the automatic audio sync fix node</td></tr><tr><td><a href="../view-parameters/and-samplerate.md"><code>&#x26;samplerate</code></a></td><td>Audio playback sample-rate, in hz</td></tr><tr><td><a href="../view-parameters/and-channels.md"><code>&#x26;channels</code></a></td><td>Specifies the number of output audio channels you wish to mix up or down to</td></tr><tr><td><a href="../view-parameters/and-channeloffset.md"><code>&#x26;channeloffset</code></a></td><td>Shifts audio channels 0 and 1 up channels, based on the offset value</td></tr><tr><td><a href="and-channeloffset-1.md"><code>&#x26;playchannel</code></a></td><td>Will play either the left or right audio stream-only for an incoming stereo stream</td></tr><tr><td><a href="../view-parameters/and-ptime.md"><code>&#x26;ptime</code></a></td><td>Audio packet size</td></tr><tr><td><a href="../view-parameters/and-maxptime.md"><code>&#x26;maxptime</code></a></td><td>Maximum packet size of audio</td></tr><tr><td><a href="../view-parameters/minptime.md"><code>&#x26;minptime</code></a></td><td>Minimum packet size of audio</td></tr><tr><td><a href="minptime-1.md"><code>&#x26;audiocodec</code></a></td><td>Lets you specify the audio codec</td></tr><tr><td><a href="minptime-2.md"><code>&#x26;dtx</code></a></td><td>Turns off the audio encoder automatically when no little to no sound is detected</td></tr><tr><td><a href="minptime-3.md"><code>&#x26;nofec</code></a></td><td>Disables FEC (audio forward error correction)</td></tr></tbody></table>

\*NEW IN [VERSION 24](../../releases/v24.md)




---
description: '=music fixed bitrate; =speech bitrate is variable'
---

# \&audiocontenthint

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&audiohint`
* `&audiocontenttype`
* `&audiocontent`

## Options

Example: `&audiocontenthint=music`

| Value    | Description                                                 |
| -------- | ----------------------------------------------------------- |
| `music`  | seems to be a fixed bitrate of 32-kbps sent out by default  |
| `speech` | bitrate is variable, using less bandwidth when not speaking |

## Details

There are two options for `&audiocontenthint`: `speech` and `music`. No idea what it does exactly, but when using `music` there seems to be a fixed bitrate of 32-kbps sent out by default, where as with `speech` it is variable, using less bandwidth when not speaking.

{% hint style="warning" %}
This parameter has been tested on Chrome, but other browsers may vary in behavior. Safari seems to just ignore things, for example.
{% endhint %}

## Related

{% content-ref url="../view-parameters/vbr.md" %}
[vbr.md](../view-parameters/vbr.md)
{% endcontent-ref %}

{% content-ref url="../video-parameters/and-contenthint.md" %}
[and-contenthint.md](../video-parameters/and-contenthint.md)
{% endcontent-ref %}




---
description: Applies a gain multiplier (as a percentage) to the local microphone
---

# \&audiogain

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&g`
* `&gain`

## Options

Example: `&audiogain=80`

<table><thead><tr><th width="196">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>0</code></td><td>mutes the microphone so that only the Director can unmute it; the guest cannot unmute.</td></tr><tr><td><code>100</code></td><td>full volume - default</td></tr><tr><td>(integer value)</td><td>value will be applied as a percentage.</td></tr></tbody></table>

## Details

Adding `&audiogain=50` to a source link sets the audio gain of the source to 50%.

* Can be used to have a guest muted by default when joining a room (`&audiogain=0`).
* Can be remotely controlled by the Director if in a room; the guest cannot unmute themselves.
* Only applies to the first audio-source selected by a guest, if there is more than one selected.
* If audio processing is on, then this should be available by default for the director to remotely control.
* The gain function will NOT work if web-audio node processing cannot be enabled.

In Version 22 you can control the audio gain in the Audio Settings. If you want the guests to be able to change it by themselves, you can add [`&mediasettings`](../../newly-added-parameters/and-mediasettings.md) to the guests' link.\
.png>)

{% hint style="warning" %}
Enables the audio processing pipeline.
{% endhint %}

## Related

{% content-ref url="and-volume.md" %}
[and-volume.md](and-volume.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/autogain.md" %}
[autogain.md](../../source-settings/autogain.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-limiter.md" %}
[and-limiter.md](../../source-settings/and-limiter.md)
{% endcontent-ref %}




---
description: Will mute the microphone of a guest when not loaded in an active OBS scene
---

# \&automute

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&am`

## Options

Example: `&automute=2`

<table><thead><tr><th width="171">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>will auto mute the microphone of a guest when not loaded in an active OBS scene</td></tr><tr><td><code>2</code></td><td>will mute it everywhere, while the default will still allow the director to speak to the guest, even if not in a scene</td></tr></tbody></table>

## Details

[`&automute`](and-automute.md) will auto mute the microphone of a guest when not loaded in an active OBS scene. Useful for perhaps limiting the discussion in a group chat to those on air.

`&automute=2` will mute it everywhere, while the default will still allow the director to speak to the guest, even if not in a scene.

This is a guest-side URL parameter; you may want to apply it to all guests.

Required quite a bit of code reworking; error reporting is on in the console, so please report issues. Feedback also welcomed.

## Related

{% content-ref url="../../source-settings/and-mute.md" %}
[and-mute.md](../../source-settings/and-mute.md)
{% endcontent-ref %}

{% content-ref url="and-audiogain.md" %}
[and-audiogain.md](and-audiogain.md)
{% endcontent-ref %}




# &bufferaudio

**Also known as:** `&audiobuffer`

#### **Description**

Sets a minimum audio buffer duration in milliseconds for incoming audio streams to improve playback stability.

#### **Viewer-Side Option**

This parameter controls the audio buffering for received streams, helping to smooth out network jitter.

#### **Usage**

* **`&bufferaudio=100`** - Sets 100ms audio buffer
* **`&bufferaudio=250`** - Sets 250ms audio buffer  
* **`&bufferaudio=0`** - Minimal buffering (lowest latency)
* **`&audiobuffer=200`** - Alias usage

#### **Examples**

```
https://vdo.ninja/?view=streamID&bufferaudio=150
https://vdo.ninja/?scene=1&room=roomname&bufferaudio=200
https://vdo.ninja/?director&room=roomname&audiobuffer=100
```

#### **Details**

* Value in milliseconds (ms)
* Higher values increase stability but add latency
* Lower values reduce latency but may cause glitches
* Helps with poor network conditions
* Only affects received audio, not sent audio

#### **Recommended Values**

* **0-50ms**: Ultra-low latency, stable networks only
* **100-200ms**: Good balance for most situations
* **250-500ms**: Poor network conditions
* **500ms+**: Very unstable connections

#### **Trade-offs**

**Low Buffer (0-50ms):**
- ✅ Minimal latency
- ❌ May glitch on poor networks
- ❌ Sensitive to jitter

**High Buffer (200ms+):**
- ✅ Smooth playback
- ✅ Handles network issues
- ❌ Noticeable delay

#### **Use Cases**

* Music performances requiring sync
* Interviews over unstable connections
* International calls with high latency
* Mobile connections with variable quality

#### **Notes**

* Independent from video buffering
* Applies to all incoming audio streams
* May affect lip-sync at high values
* Consider network conditions when setting

#### **Related Parameters**

* [`&buffer`](../view-parameters/buffer.md) - Video buffer control
* [`&buffer2`](../video-parameters/and-buffer2.md) - Alternative buffer method
* [`&audiolatency`](../newly-added-parameters/and-audiolatency.md) - Audio latency control
* [`&sync`](../view-parameters/sync.md) - Audio/video synchronization




---
description: >-
  Will play either the left or right audio stream-only for an incoming stereo
  stream
---

# \&playchannel

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&playchannel=1`

<table><thead><tr><th width="202">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code></td><td>Will play the left audio channel only</td></tr><tr><td><code>2</code></td><td>Will play the right audio channel only</td></tr><tr><td>3-6</td><td>Will play the selected channel</td></tr></tbody></table>

## Details

`&playchannel` will play either the left or right audio stream-only for an incoming stereo stream.

It will play back the selected channel as mono audio, dropping other channels from the playback. `&playchannel=1` is left channel; `2` is right; and if multi channel works for you, then you can target 6 different channels.

This is useful if you wanted to capture the left and right audio channels of a remote guest in OBS in different browser sources, without having to do any fancy audio routing on the studio side.

Both left and right audio channels are still sent; it's just during local playback that the non-selected channels are dropped, so it's not as efficient as local routing, nor will both channel be in exact sync anymore either.

This will not currently work in conjunction with [`&panning`](../view-parameters/and-panning.md) of [`&channeloffset`](../view-parameters/and-channeloffset.md); and will override those options.

Example usage: [https://vdo.ninja/?view=XXXXXXXX\&stereo\&playchannel=1](https://vdo.ninja/?view=XXXXXXXX\&stereo\&playchannel=1)

## Related

{% content-ref url="../view-parameters/and-channels.md" %}
[and-channels.md](../view-parameters/and-channels.md)
{% endcontent-ref %}

{% content-ref url="and-inputchannels.md" %}
[and-inputchannels.md](and-inputchannels.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/and-channels.md" %}
[and-channels.md](../view-parameters/and-channels.md)
{% endcontent-ref %}




---
description: >-
  Will try to "distort" your microphone's output audio, making your voice a bit
  anonymous
---

# \&distort

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

`&distort` as a URL parameter for the sender's side will try to "distort" your microphone's output audio, making your voice a bit anonymous.\
[https://vdo.ninja/?push\&webcam\&distort](https://vdo.ninja/?push\&webcam\&distort)




---
description: >-
  Audio capture device to select N-number of audio channels; force mono or
  stereo capture
---

# \&inputchannels

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&channelcount`
* `&ac`

## Options

Example: `&inputchannels=6`

| Value             | Description                                 |
| ----------------- | ------------------------------------------- |
| `1`               | Audio capture device set to mono; 1 channel |
| `2`               | Audio capture device set to 2 channels      |
| `6`               | Audio capture device set to 6 channels      |
| (integer value X) | Audio capture device set to X channels      |

## Details

`&inputchannels=N` tells the audio capture device explicitly to select N-number of audio channels.&#x20;

Setting [`&stereo=0`](../../general-settings/stereo.md) will set `&inputchannels=1` by default.

If using [`&proaudio`](and-proaudio.md) you want want to disable stereo-audio capture, particularly if you are using an XLR to USB microphone preamp that has two channels, but only one microphone connected.

For example, if a guest joins and you can only hear them in the left or right channel, either add [`&mono`](../view-parameters/mono.md) to the view-link or add `&inputchannels=1` to the respective guest invite-link.

### Mono-specific alias

If looking for a memorable parameter to set a guest's audio input to mono (1-channel), [`&monomic`](and-monomic.md) is the same as `&inputchannels=1`. This was added in VDO.Ninja v22.

## Related

{% content-ref url="and-monomic.md" %}
[and-monomic.md](and-monomic.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/mono.md" %}
[mono.md](../view-parameters/mono.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/stereo.md" %}
[stereo.md](../../general-settings/stereo.md)
{% endcontent-ref %}




---
description: Sets a guest's audio input to mono (1-channel)
---

# \&monomic

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&channelcount=1`
* `&ac=1`
* `&inputchannels=1`

## Details

`&monomic` sets a guest's audio input to mono (1-channel). `&monomic` is the same as [`&inputchannels=1`](and-inputchannels.md).

There is [`&mono`](../view-parameters/mono.md) to set the audio output to mono on the viewer's side.

## Related

{% content-ref url="and-inputchannels.md" %}
[and-inputchannels.md](and-inputchannels.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/mono.md" %}
[mono.md](../view-parameters/mono.md)
{% endcontent-ref %}




---
description: Disables all audio playback from room directors
---

# \&nodirectoraudio

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Details

`&nodirectoraudio` is just like [`&noaudio`](../view-parameters/noaudio.md) (disables all audio playback on the local computer), except it only applies to incoming connections from room directors. So, if your are using the [Mixer App](../../steves-helper-apps/mixer-app.md) with OBS, but you want to exclude the audio of yourself from the OBS, this potentially could be an easy way to do that.

## Related

{% content-ref url="../view-parameters/noaudio.md" %}
[noaudio.md](../view-parameters/noaudio.md)
{% endcontent-ref %}

{% content-ref url="../video-parameters/and-nodirectorvideo.md" %}
[and-nodirectorvideo.md](../video-parameters/and-nodirectorvideo.md)
{% endcontent-ref %}

{% content-ref url="../../viewers-settings/director.md" %}
[director.md](../../viewers-settings/director.md)
{% endcontent-ref %}

{% content-ref url="../../steves-helper-apps/mixer-app.md" %}
[mixer-app.md](../../steves-helper-apps/mixer-app.md)
{% endcontent-ref %}




---
description: >-
  Lets you tweak the &noisegate variables, making it more or less aggressive as
  needed
---

# \&noisegatesettings

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&noisegatesettings=10,25,3000`

| Value                                   | Description                                                          |
| --------------------------------------- | -------------------------------------------------------------------- |
| (TargetGain,Threshold,GateOpenPosition) | see [Details](and-noisegatesettings.md#details) for more information |
| `10,25,3000`                            | example                                                              |

## Details

`&noisegatesettings` is used in conjunction with [`&noisegate`](../../source-settings/noisegate.md). This feature lets you tweak the noise-gate's variables, making it more or less aggressive as needed.

It takes a comma separated list:

* First value is target volume (0 to 100), although 0 to 40 is probably the recommended range here.
  * Since how we perceive loudness isn't linear, to have the audio become inaudible, you'll want to set this to 0 to 3. Setting it to 10 for example will leave it still quite audible, but just dampened.
* Second value is the threshold value where the gate is triggered if below it. \~ 100 is loudly speaking, \~ 20 is light background noise levels, and under 5 is quiet background levels.
* Third value is how 'sticky' the gate-open position is, in milliseconds. Having this set to a few seconds should prevent someone from being cut off while speaking or if taking a short pause.
  * You may want to try a value of 10 to 300 for this third value, if just testing or want a sharper cut off.&#x20;

Example:\
[`https://vdo.ninja/?noisegate&noisegatesettings=10,25,3000`](https://vdo.ninja/?noisegate\&noisegatesettings=10,25,3000)

To help users with testing the noise gate and configurating the noise gate settings, there's an interactive page here for it: [https://vdo.ninja/noisegate](https://vdo.ninja/noisegate)

## Related

{% content-ref url="../../source-settings/noisegate.md" %}
[noisegate.md](../../source-settings/noisegate.md)
{% endcontent-ref %}




# &outboundsamplerate

**Also known as:** `&obsr`

#### **Description**

Sets the sample rate for outbound audio processing in the web audio pipeline.

#### **Sender-Side Option**

This parameter controls the sample rate used for audio resampling before transmission.

#### **Usage**

* **`&outboundsamplerate=48000`** - Sets sample rate to 48kHz (default in v24+)
* **`&outboundsamplerate=44100`** - Sets sample rate to 44.1kHz
* **`&outboundsamplerate=0`** - Disables resampling
* **`&obsr=48000`** - Short alias for the parameter

#### **Examples**

```
https://vdo.ninja/?push=streamID&outboundsamplerate=48000
https://vdo.ninja/?push=streamID&obsr=44100
https://vdo.ninja/?push=streamID&outboundsamplerate=0
```

#### **Details**

* In VDO.Ninja v24+, audio is automatically resampled to 48kHz for web audio processing
* This parameter allows override of the default resampling behavior
* Audio is encoded to 48kHz by Opus regardless of this setting
* Mainly useful for debugging or testing audio issues

#### **Platform Behavior**

* **Chrome/Chromium:** Resampling enabled by default (can be disabled)
* **Firefox/Safari:** No default resampling (can be force-enabled)
* **Mobile browsers:** No default resampling (can be force-enabled)

#### **Important Notes**

* High sample rates can crash the web audio pipeline
* Avoid sample rates above 48kHz
* Setting to 0 or omitting value disables resampling
* Using `&noap` disables the entire web audio pipeline

#### **Technical Background**

* Resampling ensures consistent audio processing across different input devices
* Helps prevent audio glitches with certain hardware configurations
* Final transmission uses Opus codec at 48kHz regardless

#### **Related Parameters**

* [`&samplerate`](../view-parameters/and-samplerate.md) - Sets playback sample rate (viewer-side)
* [`&noaudioprocessing`](../../general-settings/noaudioprocessing.md) - Disables audio processing
* [`&audiocodec`](minptime-1.md) - Selects audio codec




# &preferaudiocodec

#### **Description**

Sets the preferred audio codec for outgoing streams, allowing the sender to specify which audio codec they prefer to use.

#### **Sender-Side Option**

This parameter influences which audio codec is negotiated during the WebRTC connection setup.

#### **Usage**

* **`&preferaudiocodec=opus`** - Prefer Opus codec (default for most browsers)
* **`&preferaudiocodec=red`** - Prefer RED (redundancy encoding) for packet loss resilience
* **`&preferaudiocodec=g722`** - Prefer G.722 codec

#### **Examples**

```
https://vdo.ninja/?push=streamID&preferaudiocodec=opus
https://vdo.ninja/?push=streamID&preferaudiocodec=red
https://vdo.ninja/?push=streamID&whipout=whipserver&preferaudiocodec=g722
```

#### **Details**

* The parameter sets a preference, but the final codec is negotiated between peers
* Both sender and receiver must support the codec for it to be used
* Primarily intended for debugging or WHIP publishing scenarios
* Codec names are case-insensitive (converted to lowercase)

#### **Available Codecs**

* **opus** - Default, high-quality codec with good compression
* **red** - Redundancy encoding, better for poor network conditions
* **g722** - Traditional telephony codec, wider compatibility

#### **Notes**

* Not all browsers support all codecs
* Using RED codec may limit bitrate to 216 kbps
* This is an advanced parameter mainly for debugging or specific use cases
* WHIP servers may require specific codecs

#### **Related Parameters**

* [`&audiocodec`](../audio-parameters/minptime-1.md) - Forces a specific audio codec (viewer-side)
* [`&audiobitrate`](../view-parameters/audiobitrate.md) - Sets the audio bitrate
* [`&whipout`](../whip-parameters/and-whipout.md) - Publishes via WHIP protocol


# &prefervideocodec

#### **Description**

Lets the publisher request a preferred video codec order for every peer it negotiates with, so you can steer viewers toward the codec you know works best without asking them to append `&codec`.

#### **Sender-Side Option**

Attach this flag to push / room / studio URLs where you originate streams. Any viewers that connect to that page inherit the requested codec preference during SDP negotiation.

#### **Usage**

* **`&prefervideocodec=vp9`** – Favor VP9 before falling back to VP8/H264
* **`&prefervideocodec=h264`** – Encourage hardware-friendly H.264
* **`&prefervideocodec=av1`** – Attempt AV1 first when both sides support it

#### **Examples**

```
https://vdo.ninja/?push=streamID&prefervideocodec=vp9
https://vdo.ninja/?push=myfeed&prefervideocodec=h264&preferaudiocodec=opus
```

#### **Details**

* Uses the same codec keywords as `&codec` (case-insensitive)
* Viewer-side `&codec` still wins if explicitly set
* Applies to every new peer connection made from that page (primary video, scenes, director relays, etc.)
* Negotiation still depends on browser capabilities; unsupported codecs fall back automatically

#### **Related Parameters**

* [`&codec`](../view-parameters/codec.md) - Viewer-side codec override
* [`&preferaudiocodec`](#preferaudiocodec) - Audio equivalent


---
description: >-
  Improves the audio quality, changes default audio settings and sets the audio
  mode to stereo
---

# \&proaudio

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* [`&stereo`](../../general-settings/stereo.md)
* `&s`

## Options

Example: `&proaudio=1`

<table><thead><tr><th width="184">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>it behaves like 3 or 1, depending on if you are a guest or not</td></tr><tr><td><code>0</code></td><td>will try to down-mix your mic to mono. Does not enable any pro-audio settings</td></tr><tr><td><code>1</code></td><td>enables it for both push and view (if used on both links) and switches off <a href="../../source-settings/aec.md">aec</a>/<a href="../../source-settings/and-denoise.md">denoise</a>/<a href="../../source-settings/autogain.md">autogain</a> settings</td></tr><tr><td><code>2</code></td><td>enables it just for viewing requests and not publishing requests</td></tr><tr><td><code>3</code></td><td>enables it for just publishing requests and not viewing requests</td></tr><tr><td><code>4</code></td><td>enables 5.1-multichannel audio support (Experimental and may require a Chrome flag to be set)</td></tr><tr><td><code>5</code></td><td>this is the default if nothing is set. It behaves like 3 or 1, depending on if you are a guest or not</td></tr><tr><td><code>6</code></td><td>solely just enables stereo for both in/out</td></tr></tbody></table>

## Details

Adding `&proaudio` to the URL will apply audio-specific setting presets. For inbound audio streams, it can be used to increase the audio bitrate from 32-kbps to 256-kbps. For outbound streams, it will disable echo-cancellation and noise-reduction. When applied to both the outbound and inbound sides of an audio stream, it will also enable stereo audio if available.

There are a variety of different modes that apply different combination of presets. You can also override any preset with other URL parameters, such as [`&audiobitrate`](../view-parameters/audiobitrate.md), [`&outboundaudiobitrate`](../../source-settings/and-outboundaudiobitrate.md), and [`&aec=1`](../../source-settings/aec.md).

If using a microphone, wearing headphones is strongly recommended if using this parameter, along with knowledge of correctly setting your microphone gain settings. Echo and feedback issues can occur if this option is used incorrectly.

When using this option in a group room, you can't simply just apply this URL option to the director and have it apply to all guests. You will need to add the flag to each guest and to each scene-link to enable the pro-audio stereo mode. Depending on the value you pass to the URL parameter, you will get slightly different outcomes.

There is a director's room toggle for guest's invite link and for scene links:\
 (1).png>)

### More Details

`&stereo` and `&proaudio` currently do the same thing, so they are just aliases of each other. When used, they can be used to setup the audio transfer pipeline to allow for unprocessed, high-bitrate, stereo audio.

Use of this option is generally for advanced users who understand the consequences of enabling this. High-quality audio can cause audio clicking, reduced video quality, feedback issues, low volume levels, and higher background noise levels.

For stereo-channel support to work, you will want both the viewer AND the publisher of the stream to have the respective `&proaudio` flag add to their URL.

You can customize things further using [`&aec`](../../source-settings/aec.md), [`&ag`](../../source-settings/autogain.md), [`&dn`](../../source-settings/and-denoise.md), [`&ab`](../view-parameters/audiobitrate.md) and [`&mono`](../view-parameters/mono.md). These flags will override the presets applied by the `&proaudio` flag.  Please note, depending on your browser, enabling `&aec`, `&ag`, or `&dn` can force disable stereo audio.

The most powerful mode is `proaudio=1` , which if enabled:

* Turns off audio normalization or auto-gain when publishing ([`&push`](../../source-settings/push.md))
* Turns off noise-cancellation when publishing
* Turns off echo-cancellation when publishing
* Enables higher audio bitrate playback, up to 256-kbps, when listening ([`&view`](../view-parameters/view.md))

If the parameter is used, but left without a value, it is treated as a special case (either 1 or 3). Please see follow link for more info:

[https://docs.google.com/spreadsheets/d/e/2PACX-1vS7Up5jgXPcmg\_tN52JLgXBZG3wfHB3pZDQWimzxixiuRIDbeMdmU11fgrMpdYFT6yy4Igrkc9hnReY/pubhtml](https://docs.google.com/spreadsheets/d/e/2PACX-1vS7Up5jgXPcmg\_tN52JLgXBZG3wfHB3pZDQWimzxixiuRIDbeMdmU11fgrMpdYFT6yy4Igrkc9hnReY/pubhtml)

<table><thead><tr><th align="center">Option</th><th width="82">alias</th><th width="74">aec</th><th width="112">autogain</th><th width="96">denoise</th><th width="159">stereo playback</th><th width="144">stereo output</th><th width="137">default ab in</th><th width="133">max ab out</th><th width="137">limited ab in</th><th>cbr</th></tr></thead><tbody><tr><td align="center"><code>&#x26;proaudio=0</code></td><td>off</td><td>on</td><td>on</td><td>on</td><td><em>off</em></td><td><em>no</em></td><td>32</td><td>510</td><td>510</td><td><em>no</em></td></tr><tr><td align="center"><code>&#x26;proaudio=1</code></td><td>both</td><td><em>off</em></td><td><em>off</em></td><td><em>off</em></td><td>on</td><td>yes</td><td>256</td><td>510</td><td>510</td><td>yes</td></tr><tr><td align="center"><code>&#x26;proaudio=2</code></td><td>in</td><td>on</td><td>on</td><td>on</td><td>on</td><td><em>no</em></td><td>256</td><td>510</td><td>510</td><td>yes</td></tr><tr><td align="center"><code>&#x26;proaudio=3</code></td><td>out</td><td><em>off</em></td><td><em>off</em></td><td><em>off</em></td><td><em>off</em></td><td>yes</td><td>32</td><td>510</td><td>510</td><td><em>no</em></td></tr><tr><td align="center"><code>&#x26;proaudio=4</code></td><td>multi</td><td><em>off</em></td><td><em>off</em></td><td><em>off</em></td><td>on (5.1)</td><td>yes</td><td>256</td><td>510</td><td>510</td><td>yes</td></tr></tbody></table>

### Newbie mode

The default mode when `&proaudio` is used alone is `&proaudio=5`, which acts like either `&proaudio=3` or `&proaudio=1`, depending on whether the link its applied to is a room guest or not. This option will make the most sense for most users.

| Option        | Context     | alias | aec   | autogain | denoise | stereo playback | stereo output | default ab in | max ab out | limited ab in | cbr  |
| ------------- | ----------- | ----- | ----- | -------- | ------- | --------------- | ------------- | ------------- | ---------- | ------------- | ---- |
| `&proaudio=5` | Regular/OBS | 5     | _off_ | _off_    | _off_   | on              | yes           | 256           | 510        | 510           | yes  |
| `&proaudio=5` | Director    | 5     | _off_ | _off_    | _off_   | on              | yes           | 32            | 510        | 510           | _no_ |
| `&proaudio=5` | Room Guest  | 5     | _off_ | _off_    | _off_   | _off_           | yes           | 32            | 510        | 510           | _no_ |

### iOS Devices

| Option      | alias | aec | autogain | denoise | stereo playback | stereo output | default ab in | max ab out | limited ab in | cbr  |
| ----------- | ----- | --- | -------- | ------- | --------------- | ------------- | ------------- | ---------- | ------------- | ---- |
| iOS devices |       | on  | on       | on      | _off_           | _off_         | 32            | 32         | 32            | _no_ |

Just for reference, the audio codec used by VDO.Ninja is OPUS (48khz), which can provide high-fidelity music transfer when the audio bitrate is set to 80-kbps per channel or higher. The default audio bitrate used is 32-kbps VBR, which is sufficient for most voice applications. Increasing the audio bitrate to a near-lossless 500-kbps or something may end up causing more problems than anything, but that is supported if needed.

### Disabling stereo when using \&proaudio

If you want to use the `&proaudio` parameter but wish the output to still be mono (1-channel), there's some options.

* [`&inputchannels=1`](and-inputchannels.md) or [`&monomic`](and-monomic.md) can be used on the sender's side, which will force their audio-capture device (microphone) to only capture in mono.
* [`&mono`](../view-parameters/mono.md) can be added to the viewer's side, which will try to playback incoming audio as mono.
* If using OBS, in the audio settings, you can set the browser-source's audio to be mono.

## Related

{% content-ref url="../view-parameters/audiobitrate.md" %}
[audiobitrate.md](../view-parameters/audiobitrate.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-outboundaudiobitrate.md" %}
[and-outboundaudiobitrate.md](../../source-settings/and-outboundaudiobitrate.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-screensharestereo.md" %}
[and-screensharestereo.md](../../newly-added-parameters/and-screensharestereo.md)
{% endcontent-ref %}




---
description: Sets the 'default' playback volume for all video elements
---

# \&volume

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&vol`

## Options

Example: `&volume=50`

| Value   | Description                      |
| ------- | -------------------------------- |
| (0-100) | audio playback volume in percent |

## Details

`&volume` can set the 'default' playback volume for all video elements in VDO.Ninja. Currently the range is 0 to 100 and other volume commands or mute states may override this value. The default is 100.

 (1) (2) (1).png>)

`&volume=50`

## Related

{% content-ref url="and-audiogain.md" %}
[and-audiogain.md](and-audiogain.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/autogain.md" %}
[autogain.md](../../source-settings/autogain.md)
{% endcontent-ref %}

{% content-ref url="and-volumecontrol.md" %}
[and-volumecontrol.md](and-volumecontrol.md)
{% endcontent-ref %}




---
description: Shows a dedicated local audio-volume control bar for canvas or image elements
---

# \&volumecontrol

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&volumecontrols`
* `&vc`

## Details

`&volumecontrol` shows a dedicated local audio-volume control bar for canvas or image elements. Video elements already have a control-bar with volume, so I don't show it there currently.

<figure><figcaption></figcaption></figure>

The [Comms app](../../steves-helper-apps/comms.md) is a good demonstrator of the feature @[vdo.ninja/alpha/comms](https://vdo.ninja/alpha/comms).

## Related

{% content-ref url="and-volume.md" %}
[and-volume.md](and-volume.md)
{% endcontent-ref %}

{% content-ref url="and-audiogain.md" %}
[and-audiogain.md](and-audiogain.md)
{% endcontent-ref %}




---
description: Lets you specify the audio codec
---

# \&audiocodec

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Options

Example: `&audiocodec=opus`

| Value  | Description                                  |
| ------ | -------------------------------------------- |
| `opus` | default; selects audio codec opus            |
| `red`  | selects audio codec [red](minptime-1.md#red) |
| `pcmu` | selects audio codec pcmu                     |
| `pcma` | selects audio codec pcma                     |
| `isac` | selects audio codec isac                     |
| `g722` | selects audio codec g722                     |
| `pcm`  | selects audio codec [pcm](minptime-1.md#pcm) |

## Details

`&audiocodec` on the viewer side can let you specify the audio codec; `opus` (default), `pcmu`, `pcma`, `isac`, `g722`, `red` and `pcm`.

#### red

`&audiocodec=red` is pretty much like sending two opus streams, with one as a backup in case of packet loss; support in Chromium 97 and up, but the only way I can so far tell that it is working is to check if the audio bitrate has doubled.

When using [`&proaudio`](and-proaudio.md), [`&stereo`](../../general-settings/stereo.md), or higher than [`&audiobitrate=216`](../view-parameters/audiobitrate.md) with this, the resulting bitrate may not actually double. I don't quite understand what's going on here, if its still working or not, so to be safe when using [`&proaudio`](and-proaudio.md) or [`&stereo`](../../general-settings/stereo.md), along with `&audiocodec=red`, I set the bitrate to 216 by default, which will then result in a sending bitrate of around 440-kbps.

I've tried to enable RED-mode to work with PCM audio, but so far it will only work with OPUS audio.

#### pcm

`&audiocodec=pcm` now will support 48khz and 44.1khz mono playback (48khz default), and if [`&stereo`](../../general-settings/stereo.md) is used, it changes to two-channel stereo 32khz.

The existing [`&samplerate=44100`](../view-parameters/and-samplerate.md) option can lower the sample rate of this pcm mode (down to 8khz even), and hence the resulting audio bitrate. Since PCM is raw, [`&audiobitrate`](../view-parameters/audiobitrate.md) won't work, so expect 550 to 1200-kbps in just audio bitrates per viewer.

There may be clicking when using PCM mode (L16) if you are on a bad connection, as PCM doesn't have much in the way of error correction.  You'll need to address this yourself probably with post-processing if any issue.

#### Future options

In the near future you'll be able to send PCM audio via [`&chunked`](../../newly-added-parameters/and-chunked.md) mode, which will guarantees delivery of all packets sent, however there may be buffering issues if your connection can't keep up with bandwidth requirements.

Currently [`&chunked`](../../newly-added-parameters/and-chunked.md) mode does work with OPUS-audio though; please provide feedback and requests if you use it. Chunked mode does not support [WHIP/WHEP](../../steves-helper-apps/whip-and-whep-tooling.md) or [Meshcast](../../newly-added-parameters/and-meshcast.md).

## Related

{% content-ref url="../view-parameters/codec.md" %}
[codec.md](../view-parameters/codec.md)
{% endcontent-ref %}

{% content-ref url="minptime-3.md" %}
[minptime-3.md](minptime-3.md)
{% endcontent-ref %}




---
description: >-
  Turns off the audio encoder automatically when no little to no sound is
  detected
---

# \&dtx

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&usedtx`

## Details

Using `&dtx` will turn off the audio encoder automatically when no little to no sound is detected. The VDO.Ninja default uses a dynamic audio bitrate mode ([`&vbr`](../view-parameters/vbr.md)), but using `&dtx` takes things to the next level. It might be useful as a very mild [noise-gate](../../source-settings/noisegate.md) I suppose?

## Related

{% content-ref url="../view-parameters/vbr.md" %}
[vbr.md](../view-parameters/vbr.md)
{% endcontent-ref %}

{% content-ref url="minptime-3.md" %}
[minptime-3.md](minptime-3.md)
{% endcontent-ref %}

{% content-ref url="minptime-1.md" %}
[minptime-1.md](minptime-1.md)
{% endcontent-ref %}




---
description: Disables FEC (audio forward error correction)
---

# \&nofec

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Details

&#x20;`&nofec` on the viewer side can disable audio forward error correction (FEC). I show the audio codec now used in the stats, along with whether FEC is on or not (on by default).\
 (5).png>)




---
description: Show/hide buttons, adjust the user control bar and video control bar
---

# Buttons and Control Bar Parameters

## User Control Bar Options

<div align="left">

<figure><figcaption><p>The user control bar</p></figcaption></figure>

</div>

<table><thead><tr><th width="254.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../parameters-only-on-beta/and-autohide.md"><code>&#x26;autohide</code></a></td><td>Auto-hides the control bar after a few moments of the mouse being idle</td></tr><tr><td><a href="../settings-parameters/and-controlbarspace.md"><code>&#x26;controlbarspace</code></a></td><td>Forces the user control bar to be in its own dedicated space</td></tr><tr><td><a href="../../source-settings/and-nosettings.md"><code>&#x26;nosettings</code></a></td><td>Disables the local settings button</td></tr><tr><td><a href="../../viewers-settings/nomicbutton.md"><code>&#x26;nomicbutton</code></a></td><td>Disables the mic button; guests can't mute audio</td></tr><tr><td><a href="../../source-settings/and-nospeakerbutton.md"><code>&#x26;nospeakerbutton</code></a></td><td>Hides the speaker button</td></tr><tr><td><a href="../../viewers-settings/and-novideobutton.md"><code>&#x26;novideobutton</code></a></td><td>Disables the video button; guests can't mute video</td></tr><tr><td><a href="../../source-settings/nofileshare.md"><code>&#x26;nofileshare</code></a></td><td>Hides the ability for a guest to upload a file</td></tr><tr><td><a href="../settings-parameters/and-screensharebutton.md"><code>&#x26;screensharebutton</code></a></td><td>Forces the screen-share button to appear for guests</td></tr><tr><td><a href="../settings-parameters/and-nohangupbutton.md"><code>&#x26;nohangupbutton</code></a></td><td>Hides the hang-up button</td></tr><tr><td><a href="../../general-settings/chatbutton.md"><code>&#x26;chatbutton</code></a></td><td>Shows or hides the chat button</td></tr><tr><td><a href="../../newly-added-parameters/and-bigbutton.md"><code>&#x26;bigbutton</code></a></td><td>Makes the microphone mute button a lot bigger</td></tr><tr><td><a href="../settings-parameters/and-fullscreenbutton.md"><code>&#x26;fullscreenbutton</code></a></td><td>Adds a full-screen button to the control bar</td></tr><tr><td><a href="../../source-settings/nowebsite.md"><code>&#x26;nowebsite</code></a></td><td>Disables IFrames from loading, such as remotely shared websites by another guest or director</td></tr><tr><td><a href="../../source-settings/and-hands.md"><code>&#x26;hands</code></a></td><td>Enables a "Raise Hand" button for guests</td></tr></tbody></table>

#### Positioning the control bar

While you can position the control bar by dragging it around, you can also set it's initial position with the use of a custom CSS parameter. For example:

`&cssb64=I3N1YkNvbnRyb2xCdXR0b25ze3RyYW5zZm9ybTp0cmFuc2xhdGUoMHB4LCBjYWxjKC0xMDB2aCArIDkwcHgpKSFpbXBvcnRhbnR9Ow`

The above is a base64 encoded version of the following CSS, which positions the control bar at the top by default. Base64 encoding allows us to use stylings safely as a URL parameter.

`#subControlButtons{transform:translate(0px, calc(-100vh + 90px))!important};`

## Video Control Bar Options

<div align="left">

<figure><figcaption><p>The video control bar</p></figcaption></figure>

</div>

<table><thead><tr><th width="267">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../newly-added-parameters/and-videocontrols.md"><code>&#x26;videocontrols</code></a></td><td>Shows the video control bar</td></tr><tr><td><a href="../settings-parameters/and-nocontrols.md"><code>&#x26;nocontrols</code></a></td><td>Will force hide the video control bar</td></tr><tr><td><a href="and-hands-1.md"><code>&#x26;forcecontrols</code></a>*</td><td>Will try to keep the video controls visible, even if your mouse isn't hovering over the video</td></tr></tbody></table>

\*NEW IN [VERSION 24](../../releases/v24.md)




# &controlbarspace

**Also known as:** `&nocontrolbarspace` (to disable)

#### **Description**

Reserves dedicated space for the control bar to prevent video content from being obscured when controls appear.

#### **General Option**

This parameter ensures the control bar has its own space rather than overlaying on top of video content.

#### **Usage**

* **`&controlbarspace`** - Reserves space for control bar
* **`&nocontrolbarspace`** - Disables reserved space (overlay mode)

#### **Examples**

```
https://vdo.ninja/?push=streamID&controlbarspace
https://vdo.ninja/?view=streamID&controlbarspace
https://vdo.ninja/?room=roomname&nocontrolbarspace
```

#### **Visual Behavior**

**With `&controlbarspace`:**
- Video content is sized to leave room for controls
- Controls don't cover any video content
- Consistent layout whether controls are visible or hidden

**Without (or with `&nocontrolbarspace`):**
- Controls overlay on top of video
- Full video area when controls are hidden
- May obscure bottom portion when controls appear

#### **Details**

* Affects layout calculations for video sizing
* Useful for professional presentations
* Prevents important content from being hidden
* Trade-off between screen space and visibility

#### **Interaction with Other Parameters**

* Disabled by default when using [`&autohide`](../newly-added-parameters/and-autohide.md)
* Works with all control bar configurations
* Affects both sender and viewer interfaces

#### **Use Cases**

* Professional broadcasts
* Educational content where controls are frequently used
* Presentations with important bottom content
* Kiosk displays with permanent controls

#### **Notes**

* Consider your content layout when choosing
* More important for content with subtitles or lower thirds
* Can affect overall video size calculations

#### **Related Parameters**

* [`&autohide`](../newly-added-parameters/and-autohide.md) - Auto-hides controls
* [`&nocontrols`](and-nocontrols.md) - Removes all controls
* [`&controlbar`](README.md) - Control bar options
* [`&hidemenu`](../design-parameters/and-hidemenu.md) - Hides menu elements




---
description: >-
  Will try to keep the video controls visible, even if your mouse isn't hovering
  over the video
---

# \&forcecontrols

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Details

`&forcecontrols` is experimental, but it will try to keep the video controls visible, even if your mouse isn't hovering over the video.

{% hint style="info" %}
The VDO.Ninja tab/window still needs to be 'active' however, for this to work; changing focus to another tab will stop it.
{% endhint %}

{% hint style="warning" %}
Only works really for Chrome/Chromium on desktop; not Firefox, etc.
{% endhint %}

## Related

{% content-ref url="../newly-added-parameters/and-videocontrols.md" %}
[and-videocontrols.md](../newly-added-parameters/and-videocontrols.md)
{% endcontent-ref %}

{% content-ref url="../settings-parameters/and-nocontrols.md" %}
[and-nocontrols.md](../settings-parameters/and-nocontrols.md)
{% endcontent-ref %}




---
description: Options to pre-set the camera settings
---

# Camera Parameters

## General options

You have to add the parameters to the source link ([`&push`](../../source-settings/push.md)).

<table><thead><tr><th width="209.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-whitebalance.md"><code>&#x26;whitebalance</code></a>*</td><td>Lets you manually pre-set the white balance of the camera/webcam</td></tr><tr><td><a href="and-exposure.md"><code>&#x26;exposure</code></a>*</td><td>Lets you manually pre-set the exposure of the camera/webcam</td></tr><tr><td><a href="and-saturation.md"><code>&#x26;saturation</code></a>*</td><td>Lets you manually pre-set the saturation of the camera/webcam</td></tr><tr><td><a href="and-sharpness.md"><code>&#x26;sharpness</code></a>*</td><td>Lets you manually pre-set the sharpness of the camera/webcam</td></tr><tr><td><a href="and-contrast.md"><code>&#x26;contrast</code></a>*</td><td>Lets you manually pre-set the contrast of the camera/webcam</td></tr><tr><td><a href="and-brightness.md"><code>&#x26;brightness</code></a>*</td><td>Lets you manually pre-set the brightness of the camera/webcam</td></tr></tbody></table>

Please see [https://vdo.ninja/supports](https://vdo.ninja/supports) for a list of values that are available.\
\
Some option may be supported via URL but not yet listed in the documentation yet.\
\
If options are not available via the URL parameters, you can often still access them vid the Settings -> Video settings menu within a Chromium-based browser. From there you can adjust dynamically via sliders, toggles, or drop-down menus.\
\
Firefox, Safari, and non-Chromium-based browsers may not support options, nor will all devices. Many cameras on Windows, Mac, or Linux will have limit options, although typically Logitech webcams have good support.




---
description: Lets you manually pre-set the brightness of the camera/webcam
---

# \&brightness

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&brightness=128`

<table><thead><tr><th width="270">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer value; <code>1</code> to <code>255</code>)</td><td>brightness of the camera</td></tr></tbody></table>

## Details

Lets you manually pre-set the brightness of the camera/webcam:

It will normally take an integer value in the range of `1` to `255`, at least for a Logitech webcam, but will vary based on the camera / device you are using.

VDO.Ninja already tries to auto-save camera settings for android devices that support video settings, but for desktop browsers, it does not. Using these new values though you can manually set things to auto-configure as you want.

These settings will apply to ALL video devices though, not just a specific one. If a setting isn't supported by your camera or browser, it will just fail quietly, and not apply. You'll see an error in the console log though.\

{% hint style="warning" %}
* Firefox and Safari may not support this feature.
* Not all cameras/smartphones will support this option
{% endhint %}

You can check the video settings menu as to whether a device supports a certain feature or what value ranges are support; you can also check it out here [https://vdo.ninja/supports](https://vdo.ninja/supports).

## Related

{% content-ref url="./" %}
[.](./)
{% endcontent-ref %}




---
description: Lets you manually pre-set the contrast of the camera/webcam
---

# \&contrast

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&contrast=128`

<table><thead><tr><th width="270">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer value; <code>1</code> to <code>255</code>)</td><td>contrast of the camera</td></tr></tbody></table>

## Details

Lets you manually pre-set the contrast of the camera/webcam:

It will normally take an integer value in the range of `1` to `255`, at least for a Logitech webcam, but will vary based on the camera / device you are using.

VDO.Ninja already tries to auto-save camera settings for android devices that support video settings, but for desktop browsers, it does not. Using these new values though you can manually set things to auto-configure as you want.

These settings will apply to ALL video devices though, not just a specific one. If a setting isn't supported by your camera or browser, it will just fail quietly, and not apply. You'll see an error in the console log though.\

{% hint style="warning" %}
* Firefox and Safari may not support this feature.
* Not all cameras/smartphones will support this option
{% endhint %}

You can check the video settings menu as to whether a device supports a certain feature or what value ranges are support; you can also check it out here [https://vdo.ninja/supports](https://vdo.ninja/supports).

## Related

{% content-ref url="./" %}
[.](./)
{% endcontent-ref %}




---
description: Lets you manually pre-set the exposure of the camera/webcam
---

# \&exposure

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&exposure=128`

<table><thead><tr><th width="270">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer value; <code>1</code> to <code>255</code>)</td><td>exposure of the camera for a Logitech webcam</td></tr><tr><td>(integer value; <code>1</code> to <code>8000</code>)</td><td>exposure of the camera for a Pixel 4a Android smartphone</td></tr></tbody></table>

## Details

Lets you manually pre-set the exposure of the camera/webcam:

It will normally take an integer value in the range of `1` to `255`, at least for a Logitech webcam, but will vary based on the camera / device you are using. On Android, it's a specific time value, represented as exposure time, often in milliseconds.

VDO.Ninja already tries to auto-save camera settings for android devices that support video settings, but for desktop browsers, it does not. Using these new values though you can manually set things to auto-configure as you want.

These settings will apply to ALL video devices though, not just a specific one. If a setting isn't supported by your camera or browser, it will just fail quietly, and not apply. You'll see an error in the console log though.

## Shutter Speed

On Android/Chrome , the `exposureTime` value is often loosely consider the same as shutter speed. Depending on what the camera driver reports, it might be in seconds of milliseconds. To be safe,  you might want to try a few different exposure times, look at the current frame rate, and deduce your own look-up-chart.&#x20;

| Shutter Speed (photography) | `exposureTime` (seconds) | `exposureTime` (milliseconds) |
| --------------------------- | ------------------------ | ----------------------------- |
| 1/8000 s                    | 0.000125                 | 0.125 ms                      |
| 1/4000 s                    | 0.00025                  | 0.25 ms                       |
| 1/2000 s                    | 0.0005                   | 0.5 ms                        |
| 1/1000 s                    | 0.001                    | 1 ms                          |
| 1/500 s                     | 0.002                    | 2 ms                          |
| 1/250 s                     | 0.004                    | 4 ms                          |
| 1/125 s                     | 0.008                    | 8 ms                          |
| 1/60 s                      | 0.0167                   | 16.7 ms                       |
| 1/30 s                      | 0.0333                   | 33.3 ms                       |
| 1/15 s                      | 0.0667                   | 66.7 ms                       |
| 1/8 s                       | 0.125                    | 125 ms                        |
| 1/4 s                       | 0.25                     | 250 ms                        |
| 1/2 s                       | 0.5                      | 500 ms                        |
| 1 s                         | 1.0                      | 1000 ms                       |

{% hint style="warning" %}
* Firefox and Safari may not support this feature.
* Not all cameras/smartphones will support this option
{% endhint %}

You can check the video settings menu as to whether a device supports a certain feature or what value ranges are support; you can also check it out here [https://vdo.ninja/supports](https://vdo.ninja/supports).

## Related

{% content-ref url="./" %}
[.](./)
{% endcontent-ref %}




# &focus

#### **Description**

Manually sets the camera focus distance for devices that support manual focus control.

#### **Sender-Side Option**

This parameter overrides auto-focus and sets a specific focal distance for the camera.

#### **Usage**

* **`&focus=100`** - Sets focus distance to 100 units
* **`&focus=0`** - Sets focus to closest distance (macro)
* **`&focus=1000`** - Sets focus to far distance

#### **Examples**

```
https://vdo.ninja/?push=streamID&focus=100
https://vdo.ninja/?push=streamID&focus=500
```

#### **Details**

* Only works on devices/browsers that support manual focus control
* Most effective on mobile devices (smartphones/tablets)
* Desktop webcams rarely support manual focus via browser APIs
* Value represents arbitrary focus distance units (not standardized)
* Disables auto-focus when set

#### **Device Support**

* **Supported:** Most modern smartphones (iOS/Android)
* **Limited Support:** Some tablets
* **Rarely Supported:** Desktop webcams
* **Not Supported:** Virtual cameras, screen shares

#### **Notes**

* Useful for fixed-focus scenarios (e.g., document cameras, product demos)
* Can prevent focus hunting during streams
* May need experimentation to find optimal value for your setup
* Focus capability depends on browser MediaStream API support

#### **Related Parameters**

* [`&autogain`](../audio-parameters/autogain.md) - Controls automatic gain (audio equivalent)
* [`&brightness`](and-brightness.md) - Adjusts camera brightness
* [`&contrast`](and-contrast.md) - Adjusts camera contrast
* [`&zoom`](../video-parameters/and-zoom.md) - Controls camera zoom level




---
description: Lets you manually pre-set the saturation of the camera/webcam
---

# \&saturation

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&saturation=128`

<table><thead><tr><th width="270">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer value; <code>1</code> to <code>255</code>)</td><td>saturation of the camera for a Logitech camera</td></tr></tbody></table>

## Details

Lets you manually pre-set the saturation of the camera/webcam:

It will normally take an integer value in the range of `1` to `255`, at least for a Logitech webcam, but will vary based on the camera / device you are using.

VDO.Ninja already tries to auto-save camera settings for android devices that support video settings, but for desktop browsers, it does not. Using these new values though you can manually set things to auto-configure as you want.

These settings will apply to ALL video devices though, not just a specific one. If a setting isn't supported by your camera or browser, it will just fail quietly, and not apply. You'll see an error in the console log though.\

{% hint style="warning" %}
* Firefox and Safari may not support this feature.
* Not all cameras/smartphones will support this option
{% endhint %}

You can check the video settings menu as to whether a device supports a certain feature or what value ranges are support; you can also check it out here [https://vdo.ninja/supports](https://vdo.ninja/supports).

## Related

{% content-ref url="./" %}
[.](./)
{% endcontent-ref %}




---
description: Lets you manually pre-set the sharpness of the camera/webcam
---

# \&sharpness

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&sharpness=128`

<table><thead><tr><th width="270">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer value; <code>1</code> to <code>255</code>)</td><td>sharpness of the camera</td></tr></tbody></table>

## Details

Lets you manually pre-set the sharpness of the camera/webcam:

It will normally take an integer value in the range of `1` to `255`, at least for a Logitech webcam, but will vary based on the camera / device you are using.

VDO.Ninja already tries to auto-save camera settings for android devices that support video settings, but for desktop browsers, it does not. Using these new values though you can manually set things to auto-configure as you want.

These settings will apply to ALL video devices though, not just a specific one. If a setting isn't supported by your camera or browser, it will just fail quietly, and not apply. You'll see an error in the console log though.\

{% hint style="warning" %}
* Firefox and Safari may not support this feature.
* Not all cameras/smartphones will support this option
{% endhint %}

You can check the video settings menu as to whether a device supports a certain feature or what value ranges are support; you can also check it out here [https://vdo.ninja/supports](https://vdo.ninja/supports).

## Related

{% content-ref url="./" %}
[.](./)
{% endcontent-ref %}




---
description: Lets you manually pre-set the white balance of the camera/webcam
---

# \&whitebalance

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&wb`

## Options

Example: `&whitebalance=5000`

<table><thead><tr><th width="186">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer value)</td><td>white balance in Kelvin (5000 to 6500 are typical values)</td></tr></tbody></table>

## Details

Lets you manually pre-set the white balance of the camera/webcam:

It is normally in Kelvin, so `5000` or `6500` are typical values it will take.

VDO.Ninja already tries to auto-save camera settings for android devices that support video settings, but for desktop browsers, it does not. Using these new values though you can manually set things to auto-configure as you want.

These settings will apply to ALL video devices though, not just a specific one. If a setting isn't supported by your camera or browser, it will just fail quietly, and not apply. You'll see an error in the console log though.\

{% hint style="warning" %}
* Firefox and Safari may not support this feature.
* Not all cameras/smartphones will support this option
{% endhint %}

You can check the video settings menu as to whether a device supports a certain feature or what value ranges are support; you can also check it out here [https://vdo.ninja/supports](https://vdo.ninja/supports).

## Related

{% content-ref url="./" %}
[.](./)
{% endcontent-ref %}




---
description: Cheat sheet of the basic URL-based settings
---

# Most common Parameters

VDO.Ninja makes heavy use of URL-based parameters to configure settings. Some of the most commonly used ones are listed below, with a brief explanation of what they are for and links to more detail.&#x20;

| Sender-side parameter                                                | Explanation                                                                                                                                                                                                                                                                                                                                                                         |
| -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`&push`](https://docs.vdo.ninja/source-settings/push)               | The stream ID you wish to publish your video under; it must be unique. The value can be defined manually and reused. If left blank, a value will be generated automatically.                                                                                                                                                                                                        |
| [`&quality`](https://docs.vdo.ninja/source-settings/quality)         | Sets the default target resolution and frame rate. If not used, the system default is 720p60. Setting `&quality=0`will result in 1080p60 being the new target default, but this may significantly increase the CPU load on the sender's computer.                                                                                                                                   |
| [`&videodevice`](../../source-settings/videodevice.md)               | Specify an video device to auto-select on load. If left blank, the system's default audio device will be selected.                                                                                                                                                                                                                                                                  |
| [`&audiodevice`](https://docs.vdo.ninja/source-settings/audiodevice) | Specify an audio device to auto-select on load. If left blank, the system's default audio device will be selected.                                                                                                                                                                                                                                                                  |
| [`&effects`](../../source-settings/effects.md)                       | This parameter will allow for digital effects to be applied to the video, including background-blurring and a digital greenscreen. You can preset which effect is loaded by setting this value to a corresponding number, such as `&effects=4`.                                                                                                                                     |
| [`&label`](https://docs.vdo.ninja/general-settings/label)            | Allows the guest connection to be assigned a display name, which will be used in chat and if overlays are turned on. If left blank, the guest will be prompted to enter a display name.                                                                                                                                                                                             |
| [`&meshcast`](../../newly-added-parameters/and-meshcast.md)          | Adding `&meshcast` to a guest or director link will trigger the service, causing the outbound audio/video stream to be transferred to a hosted server, which then distributes the stream to all the viewers. This adds a bit of latency to the stream, but it implies the guest/director does not need to encode and upload multiple videos, lowering CPU load and bandwidth usage. |

| Viewer-side parameter                                                   | Explanation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`&view`](https://docs.vdo.ninja/viewers-settings/view)                 | <p>The stream ID you wish to view/hear; a comma-separated list can be passed as well to view multiple at a time. This isn't required if using a group room, but it can be used in conjunction with the <a href="../../source-settings/push.md"><code>&#x26;push</code></a> parameter to create <em>faux-rooms</em>.<br><br>Using <code>&#x26;view</code> without passing any values to it will prevent any incoming peer connections. It technically is responsible for allowing inbound connections, and not explicitly in control of whether video or audio is requested.</p> |
| [`&videobitrate`](../video-bitrate-parameters/bitrate.md)               | <p>The video bitrate you wish to view a video at, in kbps. The default is 2500-kbps and is well-suited for interviews and talking-heads, but you may need to increase it if video contains significant motion and scene changes.<br><br>This parameter will not work for guests in a group room, but should work elsewhere.</p>                                                                                                                                                                                                                                                 |
| [`&audiobitrate`](https://docs.vdo.ninja/viewers-settings/audiobitrate) | Sets the audio bitrate, in kbps. The system default is 32-kbps, with the max limit being between 300 to 510-kbps, based on other factors. Too high and you may actually introduce clicking noise issues.                                                                                                                                                                                                                                                                                                                                                                        |
| [`&codec`](https://docs.vdo.ninja/viewers-settings/codec)               | h264, vp9, vp8, and sometimes av1 are options. Setting `&codec=h264` can sometimes trigger the sender's hardware encoder to be used, but this can often have unexpected consequences. The default is left up to the browsers to decide.                                                                                                                                                                                                                                                                                                                                         |
| [`&novideo`](https://docs.vdo.ninja/viewers-settings/novideo)           | This flag will disable incoming video streams. Connections will still be established, allowing for data and audio still. You can pass a list of stream IDs to exempt streams from this filter.                                                                                                                                                                                                                                                                                                                                                                                  |
| [`&noaudio`](https://docs.vdo.ninja/viewers-settings/noaudio)           | This flag will disable incoming audio streams. Connections will still be established, allowing for data and video still. You can pass a list of stream IDs to exempt streams from this filter.                                                                                                                                                                                                                                                                                                                                                                                  |
| [`&showlabels`](https://docs.vdo.ninja/general-settings/showlabels)     | If the sender has set a display name, you can overlay that name by using this parameter. Different styles of labels are available, which can be set by passing their corresponding style ID to this parameter.                                                                                                                                                                                                                                                                                                                                                                  |

| Director, room, and general parameters                            | Explanation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`&room`](https://docs.vdo.ninja/general-settings/room)           | <p>Defines a room for guests to chat in. If used, everyone in a room will auto-connect to each other on joining, unless <a href="../view-parameters/view.md"><code>&#x26;view</code></a> is used. Rooms benefit from allowing for echo-free conversation and rooms can be managed by a director.</p><p></p><p>Guests in a room have limited control and will see videos at reduced quality; this is intentional.</p>                                                                                                                                                                                                          |
| [`&director`](https://docs.vdo.ninja/viewers-settings/director)   | The director flag should be set to whatever the room name is. The first director to join a room then becomes the controller of the room. They have the ability to remotely control guest's settings, such as microphone volume of a guest, and they can add and remove guests to scenes.                                                                                                                                                                                                                                                                                                                                      |
| [`&proaudio`](../audio-parameters/and-proaudio.md)                | <p>Several other parameters into one, designed to quick-start applications needing high-quality audio. This parameter can be considered pretty heavy duty, so it's primarily designed for professional users needing near-raw audio quality, such as music DJs.<br><br>If used on the sender's side, it disable echo-cancellation, noise-reduction, and auto-volume leveling. It also requests stereo audio from the microphone source.</p><p></p><p>When applied to the viewer's side as well, it will increase the connection's audio bitrate to 256-kbps and request stereo-audio from the sender, if it is available.</p> |
| [`&scene`](https://docs.vdo.ninja/viewers-settings/scene)         | <p>If using a room, then to view a specific stream or collection of streams, the <code>&#x26;scene</code> and <a href="../../general-settings/room.md"><code>&#x26;room</code></a> parameter must be added to any view link. The scene parameter lets the system know the connection is not a guest, but rather designed for capture.</p><p></p><p>Different scenes and scene types are available, and since a director can add and remove streams from scenes from their control room, multiple scenes can be used together to act as media slots in complex show layouts.</p>                                               |
| [`&roombitrate`](../video-bitrate-parameters/roombitrate.md)      | <p>This parameter can be added to a guest's invite link to reduce the maximum video bandwidth they will make available to each other guest.</p><p></p><p>On mobile devices, outbound bandwidth to other guest is already set very low, but if a guest is still struggling to participate in a group room, adding <code>&#x26;roombitrate=0</code> to their invite link will disable their outbound video to other guests and free up even more CPU. See <a href="../video-bitrate-parameters/totalroombitrate.md"><code>&#x26;totalroombitrate</code></a> for another option.</p>                                             |
| [`&password`](https://docs.vdo.ninja/general-settings/password)   | <p>Specifies the custom password to be used. If left blank, the user will be prompted for the password on page load. Passwords are not stored and used purely client-side. They are used to encrypt the initial connection handshake between peers and to obfuscate room names.<br><br>The <a href="../../newly-added-parameters/and-hash.md"><code>&#x26;hash</code></a> parameter is system-generated and is a bit like the <code>&#x26;password</code> parameter, except it has the ability to validate a user-entered password.</p>                                                                                       |
| [`&broadcast`](https://docs.vdo.ninja/viewers-settings/broadcast) | Adding this flag will have guests only accept video connections from the director, but still share audio and accept audio-connections from other guests. This reduces the CPU and network load on guests, allowing for larger rooms, so long as the director can also support those larger rooms.                                                                                                                                                                                                                                                                                                                             |

{% content-ref url="../../advanced-settings.md" %}
[advanced-settings.md](../../advanced-settings.md)
{% endcontent-ref %}




---
description: A complete list of URL parameters, although not documented
---

# Complete List of Parameters

## This is a near-complete list of all the URL parameters within VDO.Ninja (current as of v27.7). It does not offer help in explaining what a parameter does, as it's provided purely as a technical reference.

This list is not exhaustive, it may have flawed descriptions, and it does not offer links or specifics. Please refer to other support material in the documentation for details on how certain parameters actually work. If a parameter below is not found in the rest of the documentation, please refer to the code directly.\
\
This list is AI-generated, based on the contents of the `main.js` file, which you can [refer to on the Github.](https://github.com/steveseguin/vdo.ninja/blob/develop/main.js) Searching through the `lib.js` file also will help provide added detail into any function calls the parameters are calling.  Using an LLM with a sufficiently large context-window can help explain the code, as well as nearly any function, so give that a try if stuck.

If you are self-hosting VDO.Ninja, often these URL parameters can be hard-coded to have a certain value without needing URL parameters. Please refer to the `main.js` file as well for a sense of what needs to be done to accomplish that though.

### A

| Parameter          | Aliases                               | Values                                          | Description                               |
| ------------------ | ------------------------------------- | ----------------------------------------------- | ----------------------------------------- |
| `action`           | -                                     | -                                               | -                                         |
| `ad`               | See `audiodevice`                     | -                                               | -                                         |
| `addstun`          | -                                     | String (format: username;password;url)          | Adds additional STUN server               |
| `ado`              | See `audiodevice`                     | -                                               | -                                         |
| `adevice`          | See `audiodevice`                     | -                                               | -                                         |
| `ag`               | See `autogain`                        | -                                               | -                                         |
| `agc`              | See `autogain`                        | -                                               | -                                         |
| `alertvolume`      | -                                     | 0-100                                           | Sets volume for alert sounds              |
| `alpha`            | -                                     | Boolean                                         | -                                         |
| `am`               | See `automute`                        | -                                               | -                                         |
| `apiserver`        | -                                     | URL                                             | Sets custom API server                    |
| `ar`               | See `aspectratio`                     | -                                               | -                                         |
| `aspectratio`      | `ar`                                  | Number/String (`portrait`,`landscape`,`square`) | Sets aspect ratio                         |
| `audience`         | -                                     | String                                          | -                                         |
| `audiobitrate`     | -                                     | Integer (kbps)                                  | Sets audio bitrate                        |
| `audiocontenthint` | `audiocontent`, `audiohint`           | String                                          | Sets audio content processing hint        |
| `audiodevice`      | `adevice`, `ad`, `device`, `d`, `ado` | Device ID/name or `0`/`false`/`no`/`off`        | Selects audio input device                |
| `audioeffects`     | -                                     | Boolean                                         | Enables audio effects processing          |
| `autoadd`          | -                                     | Stream ID(s) (comma-separated)                  | Auto-adds specified streams               |
| `autogain`         | `ag`, `agc`                           | Boolean                                         | Controls automatic gain control           |
| `automute`         | `am`                                  | Boolean                                         | Enables automatic audio muting            |
| `autorecord`       | -                                     | Boolean/Integer                                 | Starts recording automatically            |
| `autorecordlocal`  | -                                     | Boolean/Integer                                 | -                                         |
| `autorecordremote` | -                                     | Boolean/Integer                                 | -                                         |
| `autoreload`       | -                                     | Integer (minutes)                               | Auto reloads page after specified minutes |
| `autoreload24`     | -                                     | Time (HH:MM)                                    | Reloads at specified time                 |
| `autostart`        | `as`                                  | Boolean                                         | Auto starts session                       |
| `autohide`         | -                                     | Boolean                                         | -                                         |
| `avatarimg`        | `bgimage`, `bgimg`                    | URL                                             | Sets avatar/background image              |
| `avatarimg2`       | `bgimage2`, `bgimg2`                  | URL                                             | Sets secondary avatar/background image    |
| `avatarimg3`       | `bgimage3`, `bgimg3`                  | URL                                             | Sets tertiary avatar/background image     |

### B

| Parameter           | Aliases                         | Values             | Description                       |
| ------------------- | ------------------------------- | ------------------ | --------------------------------- |
| `background`        | `appbg`                         | URL                | Sets application background       |
| `base64css`         | `b64css`, `cssbase64`, `cssb64` | Base64 encoded CSS | Applies custom CSS                |
| `base64js`          | `b64js`, `jsbase64`, `jsb64`    | Base64 encoded JS  | Applies custom JavaScript         |
| `batterymeeter`     | -                               | Boolean            | Shows battery meter               |
| `beep`              | `notify`, `tone`                | Boolean            | Enables notification sounds       |
| `beepvolume`        | -                               | 0-100              | Sets volume for beep sounds       |
| `bgimage`           | See `avatarimg`                 | -                  | -                                 |
| `bgimage2`          | See `avatarimg2`                | -                  | -                                 |
| `bgimage3`          | See `avatarimg3`                | -                  | -                                 |
| `bgimg`             | See `avatarimg`                 | -                  | -                                 |
| `bgimg2`            | See `avatarimg2`                | -                  | -                                 |
| `bgimg3`            | See `avatarimg3`                | -                  | -                                 |
| `bigbutton`         | -                               | String             | Shows large mute button with text |
| `bitrate`           | -                               | Integer (kbps)     | Sets video bitrate                |
| `bitratecutoff`     | `bitcut`                        | Integer            | Sets bitrate cutoff threshold     |
| `blackout`          | `blackoutmode`, `bo`, `bom`     | Boolean            | -                                 |
| `blur`              | -                               | Integer (1-10)     | Sets background blur amount       |
| `bc`                | See `broadcast`                 | -                  | -                                 |
| `bct`               | See `broadcasttransfer`         | -                  | -                                 |
| `broadcast`         | `bc`                            | Boolean            | Enables broadcast mode            |
| `broadcasttransfer` | `bct`                           | Boolean            | -                                 |
| `buffer`            | -                               | Number             | Sets buffer delay                 |
| `buffer2`           | -                               | Number             | Alternative buffer setting        |
| `bundle`            | -                               | String             | Sets bundle policy                |
| `bypass`            | -                               | Boolean            | -                                 |

### C

| Parameter            | Aliases                                         | Values                | Description                     |
| -------------------- | ----------------------------------------------- | --------------------- | ------------------------------- |
| `cb`                 | See `chatbutton`                                | -                     | -                               |
| `cbr`                | -                                               | Boolean               | Enables constant bitrate        |
| `cc`                 | See `closedcaptions`                            | -                     | -                               |
| `cccolored`          | `cccoloured`, `coloredcc`, `colorcc`, `cccolor` | Boolean               | Enables colored closed captions |
| `cftoken`            | `cft`                                           | String                | -                               |
| `channelcount`       | `ac`, `inputchannels`                           | Integer               | Sets number of audio channels   |
| `channeloffset`      | -                                               | Integer               | -                               |
| `chat`               | See `chatbutton`                                | -                     | -                               |
| `chatbutton`         | `chat`, `cb`                                    | Boolean               | Shows chat button               |
| `chroma`             | -                                               | Color code            | Sets chroma key color           |
| `chunked`            | `chunk`                                         | Integer               | Sets chunked transfer size      |
| `chunkedbuffer`      | `sendingbuffer`                                 | Integer               | Sets chunk buffer size          |
| `clean`              | See `cleanoutput`                               | -                     | -                               |
| `cleanoutput`        | `clean`                                         | Boolean               | Minimizes UI elements           |
| `cleanish`           | -                                               | Boolean               | -                               |
| `cleanstorage`       | `clear`                                         | Boolean               | Clears stored settings          |
| `clock`              | `clock24`                                       | 0-9                   | Shows clock with position       |
| `closedcaptions`     | `cc`, `captions`                                | Boolean               | Enables closed captions         |
| `codec`              | `codecs`, `videocodec`                          | String                | Sets video codec                |
| `codirector`         | See `directorpassword`                          | -                     | -                               |
| `compressor`         | `comp`                                          | Boolean/Integer       | Audio compression settings      |
| `consent`            | -                                               | Boolean               | -                               |
| `contenthint`        | `contenttype`, `content`, `hint`                | String                | Sets content processing hint    |
| `controlbarspace`    | -                                               | Boolean               | -                               |
| `controls`           | `videocontrols`                                 | Boolean               | Shows video controls            |
| `controlroombitrate` | `crb`                                           | Boolean               | -                               |
| `cover`              | -                                               | Boolean               | Sets cover mode for video       |
| `crop`               | -                                               | Integer (-100 to 100) | Sets video crop                 |
| `css`                | -                                               | URL                   | Applies external CSS            |

### D

| Parameter          | Aliases                         | Values         | Description                |
| ------------------ | ------------------------------- | -------------- | -------------------------- |
| `d`                | See `audiodevice`/`videodevice` | -              | -                          |
| `darkmode`         | `nightmode`, `darktheme`        | Boolean        | Enables dark theme         |
| `deaf`             | `deafen`                        | Boolean        | -                          |
| `defaultlabel`     | `labelsuggestion`, `ls`         | String         | Sets default label         |
| `delay`            | See `micdelay`                  | -              | -                          |
| `denoise`          | `dn`                            | Boolean        | Controls noise suppression |
| `device`           | See `audiodevice`/`videodevice` | -              | -                          |
| `director`         | `dir`                           | String/Boolean | Enables director mode      |
| `directorchat`     | `dc`                            | Boolean        | -                          |
| `directorpassword` | `dirpass`, `dp`, `codirector`   | String         | Sets director password     |
| `directorview`     | `dv`                            | Boolean        | -                          |
| `displaysurface`   | -                               | String         | -                          |
| `dp`               | See `directorpassword`          | -              | -                          |
| `dpi`              | `dpr`                           | Number         | Sets display pixel ratio   |
| `drawing`          | -                               | Boolean        | -                          |
| `dtx`              | `usedtx`                        | Boolean        | -                          |
| `dv`               | See `directorview`              | -              | -                          |

### E

| Parameter          | Aliases                | Values         | Description                   |
| ------------------ | ---------------------- | -------------- | ----------------------------- |
| `e2ee`             | -                      | Boolean        | Enables end-to-end encryption |
| `ec`               | See `echocancellation` | -              | -                             |
| `echocancellation` | `aec`, `ec`            | Boolean        | Controls echo cancellation    |
| `effect`           | `effects`              | String/Integer | Applies video effects         |
| `effectvalue`      | `ev`                   | Number         | Sets effect intensity         |
| `electronic`       | -                      | Boolean        | -                             |
| `enhance`          | -                      | Boolean        | -                             |
| `entrymsg`         | `welcome`              | String         | Sets welcome message          |
| `equalizer`        | `eq`                   | Boolean        | Enables audio equalizer       |
| `exclude`          | `ex`                   | Stream ID(s)   | Excludes specified streams    |
| `excludeaudio`     | `exaudio`, `silence`   | Stream ID(s)   | -                             |
| `experimental`     | -                      | Boolean        | Enables experimental features |
| `exposure`         | -                      | Number         | Sets camera exposure          |

### F

| Parameter              | Aliases                  | Values                        | Description                  |
| ---------------------- | ------------------------ | ----------------------------- | ---------------------------- |
| `facingmode`           | -                        | String (`user`/`environment`) | Sets camera facing mode      |
| `fadein`               | -                        | Number/Boolean                | Sets fade in effect          |
| `fakeguests`           | `fakefeeds`, `fakeusers` | Integer                       | -                            |
| `fb`                   | See `feedbackbutton`     | -                             | -                            |
| `feedbackbutton`       | `fb`                     | Boolean/Number                | Shows feedback button        |
| `fileshare`            | `fs`                     | Boolean                       | Enables file sharing         |
| `fit`                  | -                        | Boolean                       | Sets fit mode for video      |
| `fl`                   | See `forcelandscape`     | -                             | -                            |
| `flagship`             | -                        | Boolean                       | -                            |
| `flip`                 | -                        | Boolean                       | Flips video                  |
| `focus`                | -                        | Number                        | Sets camera focus            |
| `forceios`             | -                        | Boolean                       | -                            |
| `forcelandscape`       | `forcedlandscape`, `fl`  | Boolean                       | Forces landscape orientation |
| `forceportrait`        | `forcedportrait`, `fp`   | Boolean                       | Forces portrait orientation  |
| `forceviewerlandscape` | -                        | Integer                       | -                            |
| `forceviewerportrait`  | -                        | Integer                       | -                            |
| `fp`                   | See `forceportrait`      | -                             | -                            |
| `frameRate`            | `fr`, `fps`              | Integer                       | Sets frame rate              |
| `fs`                   | See `fileshare`          | -                             | -                            |
| `fsb`                  | See `fullscreenbutton`   | -                             | -                            |
| `fullhd`               | -                        | Boolean                       | Enables 1080p quality        |
| `fullscreen`           | -                        | Boolean                       | Enables fullscreen mode      |
| `fullscreenbutton`     | `fsb`                    | Boolean                       | Shows fullscreen button      |

### G

| Parameter    | Aliases           | Values    | Description           |
| ------------ | ----------------- | --------- | --------------------- |
| `ga`         | See `groupaudio`  | -         | -                     |
| `gain`       | See `audiogain`   | -         | -                     |
| `gate`       | See `noisegate`   | -         | -                     |
| `gating`     | See `noisegate`   | -         | -                     |
| `gdrive`     | -                 | Boolean   | -                     |
| `gm`         | See `groupmode`   | -         | -                     |
| `group`      | `groups`          | String(s) | Sets group membership |
| `groupaudio` | `ga`              | Boolean   | -                     |
| `groupmode`  | `gm`              | Boolean   | -                     |
| `groupview`  | `viewgroup`, `gv` | String(s) | Sets group view       |
| `gv`         | See `groupview`   | -         | -                     |

### H

| Parameter         | Aliases             | Values     | Description               |
| ----------------- | ------------------- | ---------- | ------------------------- |
| `h`               | See `height`        | -          | -                         |
| `h264profile`     | -                   | String     | Sets H264 profile         |
| `hands`           | `hand`              | Boolean    | -                         |
| `hangupbutton`    | `hub`, `humb64`     | Boolean    | Shows hangup button       |
| `hangupmessage`   | `hum`, `humb64`     | String     | Sets hangup message       |
| `height`          | `h`                 | Integer    | Sets video height         |
| `hh`              | See `hideheader`    | -          | -                         |
| `hidecodirector`  | `hidedirector`      | Boolean    | Hides director controls   |
| `hidecursor`      | See `nocursor`      | -          | -                         |
| `hideheader`      | `noheader`, `hh`    | Boolean    | Hides header              |
| `hidemouse`       | See `nocursor`      | -          | -                         |
| `hidesolo`        | `hs`                | Boolean    | -                         |
| `hidescreenshare` | `hidess`, `sshide`  | Boolean    | Hides screen share option |
| `hint`            | See `contenthint`   | -          | -                         |
| `holdercolor`     | `videobg`, `videobgcolor`, `videobackground`, `videobackgroundcolor`, `holderbg`, `holderbgcolor` | Color code | Sets the video holder background color |
| `host`            | -                   | Boolean    | -                         |
| `hotkeys`         | See `midi`          | -          | -                         |
| `hs`              | See `hidesolo`      | -          | -                         |
| `hub`             | See `hangupbutton`  | -          | -                         |
| `hum`             | See `hangupmessage` | -          | -                         |
| `humb64`          | See `hangupmessage` | -          | -                         |

### I

| Parameter           | Aliases                | Values         | Description                    |
| ------------------- | ---------------------- | -------------- | ------------------------------ |
| `icefilter`         | -                      | String         | Sets ICE filter                |
| `id`                | See `push`             | -              | -                              |
| `iframe`            | See `website`          | -              | -                              |
| `iframetarget`      | -                      | String         | Sets iframe target             |
| `imagelist`         | -                      | JSON array     | Sets list of background images |
| `include`           | -                      | Stream ID(s)   | Includes specified streams     |
| `insertablestreams` | `is`                   | Boolean/String | -                              |
| `intro`             | `ib`                   | Boolean        | Shows intro                    |
| `isolation`         | `voiceisolation`, `vi` | Boolean        | -                              |

### J

| Parameter  | Aliases | Values | Description                 |
| ---------- | ------- | ------ | --------------------------- |
| `js`       | -       | URL    | Applies external JavaScript |
| `justtalk` | -       | String | -                           |

### K

| Parameter          | Aliases                           | Values  | Description            |
| ------------------ | --------------------------------- | ------- | ---------------------- |
| `keyframe`         | See `keyframeinterval`            | -       | -                      |
| `keyframerate`     | See `keyframeinterval`            | -       | -                      |
| `keyframeinterval` | `keyframerate`, `keyframe`, `fki` | Integer | Sets keyframe interval |

### L

| Parameter   | Aliases                 | Values      | Description        |
| ----------- | ----------------------- | ----------- | ------------------ |
| `l`         | See `label`             | -           | -                  |
| `label`     | `l`                     | String      | Sets display name  |
| `labelsize` | `sizelabel`, `fontsize` | Integer     | Sets label size    |
| `lanonly`   | -                       | Boolean     | -                  |
| `latency`   | `al`, `audiolatency`    | Integer     | Sets audio latency |
| `layout`    | -                       | JSON/String | Sets video layout  |
| `layouts`   | -                       | JSON array  |                    |

### L (continued)

| Parameter           | Aliases         | Values                                          | Description                   |
| ------------------- | --------------- | ----------------------------------------------- | ----------------------------- |
| `limittotalbitrate` | `ltb`           | Number                                          | Sets bitrate limit            |
| `locked`            | -               | Number/String (`portrait`,`landscape`,`square`) | Locks aspect ratio            |
| `locksize`          | -               | Boolean                                         | -                             |
| `lowcut`            | `lc`, `higpass` | Integer                                         | Sets low-cut filter frequency |
| `lowbitratescene`   | `cutscene`      | String                                          | -                             |
| `lowmobilebitrate`  | -               | Integer                                         | -                             |

### M

| Parameter              | Aliases              | Values               | Description                 |
| ---------------------- | -------------------- | -------------------- | --------------------------- |
| `maxbitrate`           | `mvb`                | Integer              | Sets maximum bitrate        |
| `maxbandwidth`         | -                    | Integer (0-200)      | -                           |
| `maxconnections`       | `mc`                 | Integer              | Maximum allowed connections |
| `maxframerate`         | `mfr`, `mfps`        | Integer              | Sets maximum framerate      |
| `maxpublishers`        | `mp`                 | Integer              | Maximum allowed publishers  |
| `maxtotalscenebitrate` | `mtsb`, `tsb`        | Integer              | -                           |
| `maxvideobitrate`      | -                    | Integer              | -                           |
| `maxviewers`           | `mv`                 | Integer              | Maximum allowed viewers     |
| `mc`                   | See `maxconnections` | -                    | -                           |
| `mcaudiobitrate`       | `mcab`               | Integer              | -                           |
| `mcbitrate`            | `mcb`                | Integer              | -                           |
| `mccodec`              | -                    | String               | -                           |
| `mcscale`              | `meshcastscale`      | Integer              | -                           |
| `mcscreensharebitrate` | `mcssbitrate`        | Integer              | -                           |
| `mcscreensharecodec`   | `mcsscodec`          | String               | -                           |
| `md`                   | See `micdelay`       | -                    | -                           |
| `mediasettings`        | -                    | Boolean              | Shows media settings        |
| `meshcast`             | -                    | String               | -                           |
| `meshcastcode`         | `mccode`             | String               | -                           |
| `meter`                | `meterstyle`         | Integer              | Sets audio meter style      |
| `micdelay`             | `delay`, `md`        | Integer              | Sets microphone delay       |
| `mididevice`           | -                    | Integer              | -                           |
| `midihotkeys`          | -                    | Boolean/Integer      | -                           |
| `midiiframe`           | -                    | Boolean              | -                           |
| `midioffset`           | -                    | Integer              | -                           |
| `minipreview`          | `mini`               | Boolean/Integer      | Shows mini preview          |
| `minipreviewoffset`    | `mpo`                | Integer (-20 to 120) | -                           |
| `minroombitrate`       | `mrb`                | Integer              | -                           |
| `mirror`               | -                    | Integer (0-3)        | Sets mirror mode            |
| `mono`                 | -                    | Boolean              | Forces mono audio           |
| `morescenes`           | -                    | Integer              | -                           |
| `motionswitch`         | `motiondetection`    | Integer              | -                           |
| `mp`                   | See `maxpublishers`  | -                    | -                           |
| `mrb`                  | See `minroombitrate` | -                    | -                           |
| `mv`                   | See `maxviewers`     | -                    | -                           |
| `mvb`                  | See `maxbitrate`     | -                    | -                           |

### N

| Parameter            | Aliases                              | Values          | Description                       |
| -------------------- | ------------------------------------ | --------------- | --------------------------------- |
| `na`                 | See `noaudio`                        | -               | -                                 |
| `ng`                 | See `noisegate`                      | -               | -                                 |
| `nme`                | See `nomouseevents`                  | -               | -                                 |
| `noap`               | See `noaudioprocessing`              | -               | -                                 |
| `noaudio`            | `na`, `hideaudio`                    | Stream ID(s)    | Disables audio for streams        |
| `noaudioprocessing`  | `noap`                               | Boolean         | Disables audio processing         |
| `nocursor`           | `hidecursor`, `nomouse`, `hidemouse` | Boolean         | Hides cursor                      |
| `nocontrols`         | -                                    | Boolean         | -                                 |
| `nocontrolbar`       | -                                    | Boolean         | -                                 |
| `nodownloads`        | See `nofileshare`                    | -               | -                                 |
| `nofec`              | -                                    | Boolean         | Disables forward error correction |
| `nofileshare`        | `nofiles`                            | Boolean         | Disables file sharing             |
| `nofullscreenbutton` | `nofsb`                              | Boolean         | -                                 |
| `noheader`           | See `hideheader`                     | -               | -                                 |
| `nohub`              | See `nohangupbutton`                 | -               | -                                 |
| `nohangupbutton`     | `nohub`                              | Boolean         | Hides hangup button               |
| `noisegate`          | `gating`, `gate`, `ng`               | Boolean/Integer | Sets noise gate                   |
| `nomouseevents`      | `nme`                                | Boolean         | -                                 |
| `nopreview`          | `np`                                 | Boolean         | Disables preview                  |
| `nopush`             | `noseed`                             | Boolean         | -                                 |
| `noremb`             | -                                    | Boolean         | -                                 |
| `noscale`            | `noscaling`                          | Boolean         | Disables scaling                  |
| `nosettings`         | `ns`                                 | Boolean         | Hides settings                    |
| `nostats`            | -                                    | Boolean         | Hides statistics                  |
| `notios`             | -                                    | Boolean         | -                                 |
| `novideo`            | `nv`, `hidevideo`                    | Stream ID(s)    | Disables video for streams        |
| `np`                 | See `nopreview`                      | -               | -                                 |
| `ns`                 | See `nosettings`                     | -               | -                                 |
| `nv`                 | See `novideo`                        | -               | -                                 |

### O

| Parameter              | Aliases                         | Values          | Description          |
| ---------------------- | ------------------------------- | --------------- | -------------------- |
| `oab`                  | See `outboundaudiobitrate`      | -               | -                    |
| `obscontrols`          | `remoteobs`, `obsremote`, `obs` | Boolean/String  | Enables OBS controls |
| `obsfix`               | -                               | Boolean/Integer | -                    |
| `obsoff`               | `oo`                            | Boolean         | -                    |
| `optimize`             | -                               | Integer         | -                    |
| `order`                | -                               | Integer         | -                    |
| `orderby`              | -                               | String          | -                    |
| `orientation`          | -                               | String          | -                    |
| `outboundaudiobitrate` | `oab`                           | Integer         | -                    |
| `outboundvideobitrate` | `ovb`                           | Integer         | -                    |
| `overlaycontrols`      | -                               | Boolean         | -                    |
| `ovb`                  | See `outboundvideobitrate`      | -               | -                    |

### P

| Parameter         | Aliases                | Values         | Description             |
| ----------------- | ---------------------- | -------------- | ----------------------- |
| `p`               | See `password`         | -              | -                       |
| `p0`              | -                      | Boolean        | -                       |
| `pan`             | See `panning`          | -              | -                       |
| `panning`         | `pan`                  | Boolean/String | Sets audio panning      |
| `password`        | `pass`, `pw`, `p`      | String         | Sets room password      |
| `pcm`             | -                      | Boolean        | -                       |
| `permaid`         | See `push`             | -              | -                       |
| `pie`             | -                      | String/Boolean | -                       |
| `pip`             | -                      | Boolean        | Picture-in-picture mode |
| `pip2`            | `pipall`               | Boolean        | -                       |
| `pip3`            | `mypip`, `pipme`       | Boolean        | -                       |
| `planb`           | -                      | Boolean        | -                       |
| `playchannel`     | -                      | Integer        | -                       |
| `poster`          | -                      | URL            | Sets poster image       |
| `postimage`       | -                      | URL            | -                       |
| `postinterval`    | -                      | Integer        | -                       |
| `ppt`             | -                      | Boolean/String | Push-to-talk settings   |
| `pptcontrols`     | `slides`, `powerpoint` | Boolean        | -                       |
| `preloadbitrate`  | -                      | Integer        | -                       |
| `private`         | See `privacy`          | -              | -                       |
| `privacy`         | `private`, `relay`     | Boolean        | Enables privacy mode    |
| `prompt`          | -                      | Boolean        | -                       |
| `proxy`           | -                      | Boolean        | -                       |
| `push`            | `id`, `permaid`        | String         | Sets stream ID          |
| `pusheffectsdata` | -                      | Boolean        | -                       |
| `pushloudness`    | `getloudness`          | Boolean        | -                       |
| `pw`              | See `password`         | -              | -                       |

### Q

| Parameter | Aliases         | Values         | Description            |
| --------- | --------------- | -------------- | ---------------------- |
| `q`       | See `quality`   | -              | -                      |
| `quality` | `q`             | Integer/String | Sets video quality     |
| `queue`   | -               | Boolean/String | Enables queue system   |
| `queue2`  | `screen`        | Boolean        | Alternative queue mode |
| `queue3`  | `hold`          | Boolean        | Queue with hold        |
| `queue4`  | `holdwithvideo` | Boolean        | Queue with video       |

### R

| Parameter           | Aliases           | Values             | Description            |
| ------------------- | ----------------- | ------------------ | ---------------------- |
| `r`                 | See `room`        | -                  | -                      |
| `rampuptime`        | -                 | Integer            | -                      |
| `rc`                | See `recordcodec` | -                  | -                      |
| `record`            | -                 | Boolean            | Enables recording      |
| `recordcodec`       | `rc`              | String             | Sets recording codec   |
| `recordfolder`      | -                 | String             | Sets recording folder  |
| `reload`            | -                 | Boolean            | -                      |
| `requireencryption` | -                 | Boolean            | -                      |
| `retransmit`        | -                 | Boolean            | -                      |
| `retrytimeout`      | -                 | Integer (min 5000) | -                      |
| `room`              | `r`, `roomid`     | String             | Sets room ID           |
| `roombitrate`       | `rbr`             | Integer            | Sets room bitrate      |
| `rounded`           | `round`           | Integer            | Sets rounded corners   |
| `ruler`             | `grid`, `thirds`  | URL/Boolean        | Shows composition grid |

### S

| Parameter                | Aliases                                    | Values                   | Description                   |
| ------------------------ | ------------------------------------------ | ------------------------ | ----------------------------- |
| `salt`                   | -                                          | String                   | -                             |
| `samplerate`             | `sr`                                       | Integer                  | Sets audio sample rate        |
| `saturation`             | -                                          | Number                   | Sets video saturation         |
| `scale`                  | -                                          | Integer/Boolean          | Sets video scale              |
| `scene`                  | `scn`                                      | String/Integer           | Sets scene                    |
| `scenetype`              | `type`                                     | Integer                  | -                             |
| `screenshare`            | `ss`                                       | Boolean/String           | Enables screen sharing        |
| `screensharecontenthint` | `sscontenthint`, `sscontent`, `sshint`     | String                   | -                             |
| `screenshareaec`         | `ssec`, `ssaec`                            | Boolean                  | Screen share audio settings   |
| `screensharebitrate`     | `ssbitrate`                                | Integer                  | Sets screen share bitrate     |
| `screensharecodec`       | -                                          | String                   | -                             |
| `screensharefps`         | `ssfps`                                    | Integer                  | Sets screen share framerate   |
| `screenshareid`          | `ssid`                                     | String                   | -                             |
| `screensharelabel`       | `sslabel`                                  | String                   | -                             |
| `screensharequality`     | `ssq`                                      | Integer/String           | Sets screen share quality     |
| `screensharetype`        | `sstype`                                   | Integer                  | -                             |
| `secure`                 | -                                          | Boolean                  | -                             |
| `selfbrowsersurface`     | -                                          | String                   | -                             |
| `sendframes`             | -                                          | String                   | -                             |
| `sensordata`             | `sensor`, `gyro`, `gyros`, `accelerometer` | Integer                  | -                             |
| `sensorfilter`           | `sensorsfilter`, `filtersensor`            | String (comma-separated) | -                             |
| `sharpness`              | -                                          | Number                   | Sets video sharpness          |
| `showall`                | -                                          | Boolean                  | -                             |
| `showdirector`           | `sd`                                       | Boolean/Integer          | -                             |
| `showlist`               | -                                          | Boolean                  | -                             |
| `sizelabel`              | See `labelsize`                            | -                        | -                             |
| `slideshow`              | -                                          | Integer                  | -                             |
| `slot`                   | -                                          | Integer                  | -                             |
| `slots`                  | -                                          | Integer                  | -                             |
| `slotmode`               | `slotsmode`                                | Integer                  | -                             |
| `smallshare`             | `smallscreen`                              | Boolean                  | -                             |
| `solo`                   | -                                          | Boolean                  | -                             |
| `speedtest`              | -                                          | Boolean/String           | -                             |
| `splitrecording`         | -                                          | Integer                  | Sets recording split interval |
| `ss`                     | See `screenshare`                          | -                        | -                             |
| `ssb`                    | -                                          | Boolean                  | -                             |
| `ssec`                   | See `screenshareaec`                       | -                        | -                             |
| `sshint`                 | See `screensharecontenthint`               | -                        | -                             |
| `ssid`                   | See `screenshareid`                        | -                        | -                             |
| `sspaused`               | `sspause`, `ssp`                           | Boolean                  | -                             |
| `ssq`                    | See `screensharequality`                   | -                        | -                             |
| `sstype`                 | See `screensharetype`                      | -                        | -                             |
| `stereo`                 | `s`, `proaudio`                            | String/Integer           | Sets stereo mode              |
| `streamid`               | See `view`                                 | -                        | -                             |
| `style`                  | `st`                                       | Integer (0-7)            | Sets interface style          |
| `stun`                   | -                                          | String                   | Sets STUN server              |
| `surfaceswitching`       | -                                          | String                   | -                             |
| `svc`                    | `scalabilitymode`                          | String                   | Sets scalability mode         |
| `systemaudio`            | -                                          | String                   | -                             |

### T

| Parameter          | Aliases                    | Values        | Description                  |
| ------------------ | -------------------------- | ------------- | ---------------------------- |
| `tallyoff`         | `notally`, `to`            | Boolean       | -                            |
| `tc`               | `timecode`, `showtimecode` | Boolean       | -                            |
| `tcp`              | -                          | Boolean       | Forces TCP mode              |
| `timer`            | -                          | Integer (1-9) | Sets timer position          |
| `to`               | See `tallyoff`             | -             | -                            |
| `token`            | -                          | String        | Authentication token         |
| `totalbitrate`     | `tb`                       | Integer       | -                            |
| `totalroombitrate` | `trb`, `tb`                | Integer       | Sets total room bitrate      |
| `transcript`       | `transcribe`, `trans`      | String        | -                            |
| `transparent`      | `transparency`             | Boolean       | Makes background transparent |
| `trb`              | See `totalroombitrate`     | -             | -                            |
| `turn`             | -                          | String        | Sets TURN server             |
| `type`             | See `scenetype`            | -             | -                            |

### U

| Parameter | Aliases   | Values  | Description |
| --------- | --------- | ------- | ----------- |
| `unsafe`  | -         | Boolean | -           |
| `usedtx`  | See `dtx` | -       | -           |

### V

| Parameter | Aliases            | Values  | Description           |
| --------- | ------------------ | ------- | --------------------- |
| `v`       | See `view`         | -       | -                     |
| `vb`      | See `videobitrate` | -       | -                     |
| `vbr`     | -                  | Boolean | Variable bitrate mode |
| `vd`      | See `videodevice`  | -       | -                     |
| `vdevice` | See `videodevice`  | -       | -                     |
| `ve`      | See `viewereffect` | -       | -                     |
| `vh`      | See `viewheight`   | -       | -                     |
| `vi`      | See `isolation`    | -       | -                     |
| `video`   | -                  | Boolean | -                     |

### V (continued)

| Parameter        | Aliases                               | Values                                   | Description                |
| ---------------- | ------------------------------------- | ---------------------------------------- | -------------------------- |
| `videobitrate`   | `bitrate`, `vb`                       | Integer                                  | Sets video bitrate         |
| `videocontrols`  | See `controls`                        | -                                        | -                          |
| `videodevice`    | `vdevice`, `vd`, `device`, `d`, `vdo` | Device ID/name or `0`/`false`/`no`/`off` | Selects video input device |
| `view`           | `v`, `streamid`                       | Stream ID                                | Sets view mode             |
| `viewereffect`   | `viewereffects`, `ve`                 | Integer                                  | Sets viewer effects        |
| `viewgroup`      | See `groupview`                       | -                                        | -                          |
| `viewheight`     | `vh`                                  | Integer                                  | Sets view height           |
| `viewwidth`      | `vw`                                  | Integer                                  | Sets view width            |
| `virtualeffects` | -                                     | Boolean                                  | -                          |
| `vdo`            | See `videodevice`                     | -                                        | -                          |
| `volume`         | `vol`                                 | 0-100                                    | Sets volume level          |
| `vred`           | -                                     | Boolean                                  | -                          |
| `vw`             | See `viewwidth`                       | -                                        | -                          |

### W

| Parameter                   | Aliases            | Values      | Description               |
| --------------------------- | ------------------ | ----------- | ------------------------- |
| `w`                         | See `width`        | -           | -                         |
| `waitmessage`               | -                  | String      | Sets wait message         |
| `waitimage`                 | -                  | URL         | Sets wait screen image    |
| `waittimeout`               | -                  | Integer     | Sets wait timeout         |
| `wb`                        | See `whitebalance` | -           | -                         |
| `webp`                      | `images`           | String      | Sets WebP image format    |
| `webpquality`               | `webpq`, `wq`      | Integer     | Sets WebP quality         |
| `website`                   | `iframe`           | URL         | Embeds website            |
| `welcomehtml`               | -                  | HTML/Base64 | Sets welcome HTML         |
| `welcomeimage`              | `welcomeimg`       | URL         | Sets welcome image        |
| `welcomemessage`            | -                  | String      | Sets welcome message      |
| `whep`                      | `whepplay`         | URL         | WHEP playback URL         |
| `whepicewait`               | `whepwait`         | Integer     | WHEP ICE timeout          |
| `whepshare`                 | `whepsrc`          | URL         | WHEP share URL            |
| `whepsharetoken`            | `whepsrctoken`     | String      | WHEP share token          |
| `wheptoken`                 | `whepplaytoken`    | String      | WHEP auth token           |
| `whip`                      | `whipview`         | URL         | WHIP URL                  |
| `whipicewait`               | `whipwait`         | Integer     | WHIP ICE timeout          |
| `whipout`                   | `whippush`         | URL         | WHIP output URL           |
| `whipoutaudiobitrate`       | `woab`             | Integer     | WHIP audio bitrate        |
| `whipoutaudiocodec`         | `woac`             | String      | WHIP audio codec          |
| `whipoutcodec`              | `woc`, `wovc`      | String      | WHIP video codec          |
| `whipoutscreensharebitrate` | `wossbitrate`      | Integer     | WHIP screen share bitrate |
| `whipoutscreensharecodec`   | `wosscodec`        | String      | WHIP screen share codec   |
| `whipouttoken`              | -                  | String      | WHIP output token         |
| `whipoutvideobitrate`       | `wovb`             | Integer     | WHIP video bitrate        |
| `whitebalance`              | `wb`, `temp`       | Number      | Sets white balance        |
| `width`                     | `w`                | Integer     | Sets video width          |
| `widgetleft`                | -                  | Boolean     | -                         |
| `widgetwidth`               | -                  | Number      | -                         |
| `wq`                        | See `webpquality`  | -           | -                         |
| `wss`                       | -                  | URL         | Signaling server URL; also enables generic-relay mode (client-side addressing) |
| `wss2`                      | -                  | URL         | Signaling server URL; standard server-routed protocol. Ignored if `wss` is set |

### Y

| Parameter | Aliases | Values | Description             |
| --------- | ------- | ------ | ----------------------- |
| `youtube` | -       | String | YouTube integration key |

### Z

| Parameter       | Aliases | Values  | Description               |
| --------------- | ------- | ------- | ------------------------- |
| `zoom`          | -       | Boolean | Enables zoom effect       |
| `zoomedbitrate` | `zb`    | Integer | Sets zoomed video bitrate |

### Notes

1. Boolean parameters can typically be set to `true`, `false`, `0`, `1`, `off`, or `no`
2. Many parameters that take integer values have specific valid ranges or expected values
3. Some parameters may behave differently depending on browser, device, or other active parameters
4. URL parameters are case-insensitive
5. When multiple aliases exist for a parameter, they all provide the same functionality
6. Some parameters may require specific hardware, browser support, or other parameters to function

For the most current and detailed information, please refer to the official VDO.Ninja documentation.




---
description: >-
  Labels, styles, clean output, CSS, mirroring, margin, dark mode, background
  color, disable tallies etc.
---

# Design Parameters

They are separated in three groups: [general options](./#general-options) (push and view), [source side](./#source-side-options) (push) options and [viewer side](./#viewer-side-options) (view) options.

## General options

You can add them to both, source ([`&push`](../../source-settings/push.md)) and viewer ([`&view`](../view-parameters/view.md) or [`&scene`](../view-parameters/scene.md)) sides.

<table><thead><tr><th width="251.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../general-settings/label.md"><code>&#x26;label</code></a></td><td>Sets a display name label</td></tr><tr><td><a href="showlabels.md"><code>&#x26;showlabels</code></a></td><td>Display labels as a video overlay</td></tr><tr><td><a href="../view-parameters/fontsize.md"><code>&#x26;fontsize</code></a></td><td>Let you set font-size of the closed captions and stream labels</td></tr><tr><td><a href="style.md"><code>&#x26;style</code></a></td><td>Lets you select how audio-only elements are displayed in OBS and for guests</td></tr><tr><td><a href="and-bgimage.md"><code>&#x26;bgimage</code></a></td><td>Can be used to set the default image avatar, when using <a href="style.md"><code>&#x26;style=0</code></a> or <a href="style.md"><code>&#x26;style=6</code></a></td></tr><tr><td><a href="and-showall.md"><code>&#x26;showall</code></a></td><td>Includes non-media-based push connections as video elements in a group room</td></tr><tr><td><a href="meterstyle.md"><code>&#x26;meterstyle</code></a></td><td>Optional audio meter style type</td></tr><tr><td><a href="cleanoutput.md"><code>&#x26;cleanoutput</code></a></td><td>Keeps the output as clean as possible from UI elements</td></tr><tr><td><a href="cleanish.md"><code>&#x26;cleanish</code></a></td><td>Cleaner output; not as clean as <a href="cleanoutput.md"><code>&#x26;cleanoutput</code></a></td></tr><tr><td><a href="css.md"><code>&#x26;css</code></a></td><td>Loads a custom CSS file</td></tr><tr><td><a href="and-base64css.md"><code>&#x26;base64css</code></a></td><td>Lets you add css to the URL, but as a single string, so no external reference to a file is needed</td></tr><tr><td><a href="and-js.md"><code>&#x26;js</code></a></td><td>Lets you pass a third party hosted javascript file URL</td></tr><tr><td><a href="and-base64js.md"><code>&#x26;base64js</code></a></td><td>Lets a user add raw javascript to the URL to run on page load</td></tr><tr><td><a href="and-mirror.md"><code>&#x26;mirror</code></a></td><td>Inverts the video so it is the mirror reflection</td></tr><tr><td><a href="and-nomirror-alpha.md"><code>&#x26;nomirror</code></a>*</td><td>Disables the default mirror state of the video preview for a guest</td></tr><tr><td><a href="and-flip.md"><code>&#x26;flip</code></a></td><td>Inverts the video so it is upside down</td></tr><tr><td><a href="and-rotatewindow.md"><code>&#x26;rotatewindow</code></a></td><td>Will rotate the contents of the VDO.Ninja window</td></tr><tr><td><a href="and-structure.md"><code>&#x26;structure</code></a></td><td>Will have the video holding div element be structured to the aspect ratio</td></tr><tr><td><a href="and-color.md"><code>&#x26;color</code></a></td><td>You can specify the background color independent of the border color</td></tr><tr><td><a href="and-blur.md"><code>&#x26;blur</code></a></td><td>Will try to add a blurred background to the video so it fits the structured video container</td></tr><tr><td><a href="and-border.md"><code>&#x26;border</code></a></td><td>Adds a border around the videos</td></tr><tr><td><a href="and-bordercolor.md"><code>&#x26;bordercolor</code></a></td><td>Defines the color of <a href="and-border.md"><code>&#x26;border</code></a></td></tr><tr><td><a href="rounded.md"><code>&#x26;rounded</code></a></td><td>Rounds the edges of videos</td></tr><tr><td><a href="margin.md"><code>&#x26;margin</code></a></td><td>Adds a margin around the videos in pixel</td></tr><tr><td><a href="darkmode.md"><code>&#x26;darkmode</code></a></td><td>Darkens the website and interface</td></tr><tr><td><a href="and-lightmode.md"><code>&#x26;lightmode</code></a></td><td>Forces to enable the lightmode / disable the darkmode</td></tr><tr><td><a href="and-background.md"><code>&#x26;background</code></a></td><td>Accepts a URL-encoded image URL to make as the app's default background</td></tr><tr><td><a href="chroma.md"><code>&#x26;chroma</code></a></td><td>Sets the background for the website to a particular hex color</td></tr><tr><td><a href="and-transparent.md"><code>&#x26;transparent</code></a></td><td>Makes the background transparent</td></tr><tr><td><a href="../../general-settings/and-nocursor.md"><code>&#x26;nocursor</code></a></td><td>Hides the mouse cursor over videos at a CSS level</td></tr><tr><td><a href="and-favicon-alpha.md"><code>&#x26;favicon</code></a></td><td>Will change the browser's page favicon image</td></tr><tr><td><a href="and-headertitle.md"><code>&#x26;headertitle</code></a></td><td>Will change the browser's page title</td></tr><tr><td><a href="and-pipall-alpha.md"><code>&#x26;pipall</code></a>*</td><td>New floating picture in picture mode, so you can pop out the entire video mix as a pinned window overlay</td></tr><tr><td><a href="and-pipme-alpha.md"><code>&#x26;pipme</code></a>*</td><td>Will cause your self-video preview window to pop out into its own picture in picture</td></tr></tbody></table>

\*NEW IN VERSION 24

## Source side options

You have to add them to the source side ([`&push`](../../source-settings/push.md)).

<table><thead><tr><th width="200.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-rotate.md"><code>&#x26;rotate</code></a></td><td>Rotates the camera</td></tr><tr><td><a href="grid.md"><code>&#x26;grid</code></a></td><td>Applies an rule-of-thirds grid overlay to the self-preview</td></tr><tr><td><a href="and-hideheader.md"><code>&#x26;hideheader</code></a></td><td>Hides just the top header-bar</td></tr><tr><td><a href="and-hidemenu.md"><code>&#x26;hidemenu</code></a></td><td>Hides the VDO.Ninja-branded menu and header bar</td></tr><tr><td><a href="tallyoff.md"><code>&#x26;tally</code></a></td><td>Will make the tally sign larger and colorize the background of the page</td></tr><tr><td><a href="tallyoff-1.md"><code>&#x26;tallyoff</code></a></td><td>Disables the Tally Light's visibility for that particular guest</td></tr></tbody></table>

## **Viewer side options**

You have to add them to the viewer side ([`&view`](../view-parameters/view.md) or [`&scene`](../view-parameters/scene.md)).

<table><thead><tr><th width="216.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-cleanviewer.md"><code>&#x26;cleanviewer</code></a></td><td>Hides many of the UI elements and pop-ups that may cause unwanted visual elements</td></tr><tr><td><a href="and-obsoff.md"><code>&#x26;obsoff</code></a></td><td>Disables the tally light effects</td></tr><tr><td><a href="and-pip.md"><code>&#x26;pip</code></a></td><td>Auto PIP the first loaded video</td></tr></tbody></table>




---
description: Accepts a URL-encoded image URL to make as the app's default background
---

# \&background

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&appbg`

## Options

Example: `&background=./media/logo_cropped.png`

| Value         | Description                         |
| ------------- | ----------------------------------- |
| (encoded URL) | Changes the background of VDO.Ninja |

## Details

Accepts a URL-encoded image URL to make as the app's default background.

To test:\
[`https://vdo.ninja/?background=./media/logo_cropped.png`](https://vdo.ninja/?background=./media/logo\_cropped.png)

The image will scale in size to cover the VDO.Ninja app's background. [`&chroma`](chroma.md) can still be used to set the background color, if using transparencies. There already exists [`&bgimage`](and-bgimage.md), which will set the default background image for videos; this however will set a background image for the entire page.

You can encode and decode a URL here:\
[https://www.urlencoder.org/](https://www.urlencoder.org/)

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="and-bgimage.md" %}
[and-bgimage.md](and-bgimage.md)
{% endcontent-ref %}

{% content-ref url="chroma.md" %}
[chroma.md](chroma.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-waitimage.md" %}
[and-waitimage.md](../newly-added-parameters/and-waitimage.md)
{% endcontent-ref %}




---
description: >-
  Lets you add css to the URL, but as a single string, so no external reference
  to a file is needed
---

# \&base64css

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&b64css`
* `&cssbase64`
* `&cssb64`

## Options

Example: `&base64css=JTIzbWFpbm1lbnUlN0JiYWNrZ3JvdW5kLWNvbG9yJTNBJTIwcGluayUzQiUyMCVFMiU5RCVBNA`

| Value    | Description          |
| -------- | -------------------- |
| (string) | Custom base64 string |

## Details

This command lets you add CSS to VDO.Ninja via the URL, but as a single string, so no external reference to a file is needed.

Example usage:\
[`https://vdo.ninja/?base64css=JTIzbWFpbm1lbnUlN0JiYWNrZ3JvdW5kLWNvbG9yJTNBJTIwcGluayUzQiUyMCVFMiU5RCVBNA`](https://vdo.ninja/?base64css=JTIzbWFpbm1lbnUlN0JiYWNrZ3JvdW5kLWNvbG9yJTNBJTIwcGluayUzQiUyMCVFMiU5RCVBNA)\
\
You can create the base64 encoding using `btoa(encodeURIComponent(csshere))`, for example `window.btoa(encodeURIComponent("#mainmenu{background-color: pink; ❤" ));`

Will return the base64 encoded string required. Special non-latin characters are supported with this approach; not just latin characters.

The [https://invite.vdo.ninja/](https://invite.vdo.ninja/) tool has an option to do these base64 encoding steps under "General Options".\
\
There's also a page dedicated to creating these base64 encodings here: [https://vdo.ninja/base64](https://vdo.ninja/base64)

## Related

{% content-ref url="css.md" %}
[css.md](css.md)
{% endcontent-ref %}




---
description: Lets a user add raw javascript to the URL to run on page load
---

# \&base64js

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md),[`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&jsb64`
* `&b64js`
* `&jsb64`

## Options

Example: `&base64js=YWxlcnQoJ2hpJyk=`

| Value    | Description    |
| -------- | -------------- |
| (string) | Javascript URL |

## Details

`&base64js` lets a user add raw java script to the URL to run on page load.

To test:\
[`https://vdo.ninja/?base64js=YWxlcnQoJ2hpJyk=`](https://vdo.ninja/?base64js=YWxlcnQoJ2hpJyk=)

## Related

{% content-ref url="and-base64css.md" %}
[and-base64css.md](and-base64css.md)
{% endcontent-ref %}

{% content-ref url="and-js.md" %}
[and-js.md](and-js.md)
{% endcontent-ref %}




---
description: Can be used to set the default image avatar, when using &style=0 or &style=6
---

# \&bgimage

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&bgimg`
* `&avatarimg`

## Options

Example: `&bgimage=https%3A%2F%2Fvdo.ninja%2Fmedia%2Fold_icon.png`

<table><thead><tr><th width="371">Value</th><th>Description</th></tr></thead><tbody><tr><td>(Encoded URL)</td><td>URL or base64 data image/svg</td></tr></tbody></table>

## Details

`&bgimage` can be used to set the default image avatar, when using [`&style=0`](style.md) or [`&style=6`](style.md). This only impacts what the person with the parameter added sees and must be either a URL or a base64 data image/svg. URL-encoded values.

[`https://vdo.ninja/?push=aSmexM6&style=0&vd=0&webcam&bgimage=https%3A%2F%2Fvdo.ninja%2Fmedia%2Fold_icon.png`](https://vdo.ninja/?push=aSmexM6\&style=0\&vd=0\&webcam\&bgimage=https%3A%2F%2Fvdo.ninja%2Fmedia%2Fold\_icon.png)

 (1) (4).png>)

You can encode your URL here:\
[https://www.urlencoder.org/](https://www.urlencoder.org/)

If you want to change the background image / avatar on the sender's side for all viewers, use [`&avatar`](../video-parameters/and-avatar.md).

## `&bgimage2` and `&bgimage3`

`&bgimage2` and `&bgimage3` work in conjunction with the existing `&bgimage` parameter. You pass an URL-encoded image URL to each, and when a guest speaks, it will switch their background image between the 3 possible images, based on their loudness.

eg:

```
vdo.ninja/alpha/?view=stream2,stream2&avatarimg=./media/avatar1.png&avatarimg2=./media/avatar2.png&avatarimg3=./media/avatar3.png
```

I've included some hand-drawn avatar sample images to test with; they are the default values for `&bgimage`, `&bgimage2`, and `&bgimage3`.

The images will only show when there is no active video and is essentially the same as using [`&meterstyle=4`](meterstyle.md) with some custom CSS to specify the behaviour, but it is not stream ID specific however.

## Related

{% content-ref url="style.md" %}
[style.md](style.md)
{% endcontent-ref %}

{% content-ref url="../video-parameters/and-avatar.md" %}
[and-avatar.md](../video-parameters/and-avatar.md)
{% endcontent-ref %}

{% content-ref url="../newly-added-parameters/and-waitimage.md" %}
[and-waitimage.md](../newly-added-parameters/and-waitimage.md)
{% endcontent-ref %}

{% content-ref url="and-background.md" %}
[and-background.md](and-background.md)
{% endcontent-ref %}




---
description: >-
  Will try to add a blurred background to the video so it fits the structured
  video container
---

# \&blur

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Options

Example: `&blur=25`

| Value            | Description             |
| ---------------- | ----------------------- |
| (no value given) | blurring intensity = 10 |
| (integer)        | blurring intensity      |
| `25`             | blurring intensity = 25 |

## Details

`&blur` which will try to add a blurred background to the video so it fits the structured video container. Using `&blur` auto enables [`&structure`](and-structure.md).

Code in the auto mixer, so you won't see the effect in a simple preview or some self-preview types.

`&blur` doesn't work with [`&color`](and-color.md), etc.

You can change the blurring intensity with `&blur=25` or whatever; `10` is default

`&blur=0` works as well.

May be buggy if using it with [`&forcedlandscape`](../mobile-parameters/and-forcelandscape.md) or [`&rotate`](and-rotate.md)

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="and-structure.md" %}
[and-structure.md](and-structure.md)
{% endcontent-ref %}

{% content-ref url="and-border.md" %}
[and-border.md](and-border.md)
{% endcontent-ref %}

{% content-ref url="and-color.md" %}
[and-color.md](and-color.md)
{% endcontent-ref %}




---
description: Adds a border around the videos
---

# \&border

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Options

Example: `&border=20`

<table><thead><tr><th width="238">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>adds a border with 10 px</td></tr><tr><td>(integer value)</td><td>adds a border in px</td></tr></tbody></table>

## Details

Adds a border around the videos.

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="and-bordercolor.md" %}
[and-bordercolor.md](and-bordercolor.md)
{% endcontent-ref %}

{% content-ref url="margin.md" %}
[margin.md](margin.md)
{% endcontent-ref %}

{% content-ref url="rounded.md" %}
[rounded.md](rounded.md)
{% endcontent-ref %}




---
description: Defines the color of &border
---

# \&bordercolor

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Options

Example: `&bordercolor=ffffff` or `&bordercolor=white`

| Value                 | Description                       |
| --------------------- | --------------------------------- |
| (no value given)      | black border                      |
| (HEX) \| (color name) | specifies the color of the border |
| `ffffff`              | white border                      |

{% hint style="danger" %}
Do not include the # character with the hex value.
{% endhint %}

## Details

Defines the color of `&border`.

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="and-border.md" %}
[and-border.md](and-border.md)
{% endcontent-ref %}

{% content-ref url="margin.md" %}
[margin.md](margin.md)
{% endcontent-ref %}

{% content-ref url="rounded.md" %}
[rounded.md](rounded.md)
{% endcontent-ref %}




---
description: >-
  Hides many of the UI elements and pop-ups that may cause unwanted visual
  elements
---

# \&cleanviewer

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&cv`

## Details

This is the exact same thing as [`&cleanoutput`](cleanoutput.md), except it only triggers if added to a view-only link.

Hides many of the UI elements and pop-ups that may cause unwanted visual elements not desired in a high-stakes live stream.

## Related

{% content-ref url="cleanoutput.md" %}
[cleanoutput.md](cleanoutput.md)
{% endcontent-ref %}




---
description: You can specify the background color independent of the border color
---

# \&color

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Options

Example: `&color=ffffff` or `&color=white`

| Value                 | Description                           |
| --------------------- | ------------------------------------- |
| (no value given)      | black background                      |
| (HEX) \| (color name) | specifies the color of the background |
| `ffffff`              | white background                      |

{% hint style="danger" %}
Do not include the # character with the hex value.
{% endhint %}

## Details

You can specify the background color independent of the border color with `&color`. If using [`&border`](and-border.md), it will not set the background color, so you may need to use both `&border` and `&color`.

May not yet work with [`&forcedlandscape`](../mobile-parameters/and-forcelandscape.md) or [`&rotate`](and-rotate.md).\

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="and-structure.md" %}
[and-structure.md](and-structure.md)
{% endcontent-ref %}

{% content-ref url="and-border.md" %}
[and-border.md](and-border.md)
{% endcontent-ref %}

{% content-ref url="and-blur.md" %}
[and-blur.md](and-blur.md)
{% endcontent-ref %}

{% content-ref url="and-bordercolor.md" %}
[and-bordercolor.md](and-bordercolor.md)
{% endcontent-ref %}




---
description: Will change the browser's page favicon image
---

# \&favicon

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Options

Example: `&favicon=https%3A%2F%2Fmeshcast.io%2Ffavicon.ico`

<table><thead><tr><th width="339">Value</th><th>Description</th></tr></thead><tbody><tr><td>(URL encoded URL)</td><td>Changes the favicon</td></tr></tbody></table>

[https://www.urlencoder.org/](https://www.urlencoder.org/)

## Details

`&favicon` will change the browser's page favicon image. Passed values should be URL encoded. (Google URL encoding if needed). Since this is Javascript based, the values only update once the page loads. Meta-page-previews will likely not reflect the values.\
\
Sample link: [`https://vdo.ninja/?headertitle=LINDENKRON4TW&favicon=https%3A%2F%2Fmeshcast.io%2Ffavicon.ico`](https://vdo.ninja/?headertitle=LINDENKRON4TW\&favicon=https%3A%2F%2Fmeshcast.io%2Ffavicon.ico)

<div align="left">

<figure><figcaption></figcaption></figure>

</div>

## Related

{% content-ref url="and-headertitle.md" %}
[and-headertitle.md](and-headertitle.md)
{% endcontent-ref %}




---
description: Inverts the video so it is upside down
---

# \&flip

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Details

Inverts the video so it is upside down. That's it. It doesn't change the viewer's link. If you want to have the viewer's link. If you want to flip the viewer's link as well, you have to add `&flip` to the viewer's side as well.

#### Alternative method for mirroring and flipping

If you are looking for a form of rotation and flipping that rotates the actual video, rather than relying on CSS to achieve it, you can check out the sender-side [`&effects`](../../source-settings/effects.md) options.\
\
`https://vdo.ninja/?effects=-1`, which will flip the video \
`https://vdo.ninja/?effects=-2`, which will flip and mirror the video\
`https://vdo.ninja/?effects=2`, which will mirror the video\
\
Effects however may increase CPU/GPU usage, and could cause frame rate instability, especially if the browser tab is not in active focus.

### Dedicated teleprompter tool that works for most sites

There's a dedicated tool for mirror, flipping, and rotating websites as part of VDO.Ninja as well:

[teleprompter-tool.md](../../steves-helper-apps/teleprompter-tool.md "mention")

In case the built-in options to mirror or flip don't work, the teleprompter app might be a good alternative.

## Related

{% content-ref url="../../steves-helper-apps/teleprompter-tool.md" %}
[teleprompter-tool.md](../../steves-helper-apps/teleprompter-tool.md)
{% endcontent-ref %}

{% content-ref url="and-mirror.md" %}
[and-mirror.md](and-mirror.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/effects.md" %}
[effects.md](../../source-settings/effects.md)
{% endcontent-ref %}




---
description: Will change the browser's page title
---

# \&headertitle

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Options

Example: `&headertitle=LINDENKRON4TW`

<table><thead><tr><th width="339">Value</th><th>Description</th></tr></thead><tbody><tr><td>(string)</td><td>Changes the browser's page title</td></tr></tbody></table>

## Details

`&headertitle` will change the browser's page title.\
\
Sample link: [`https://vdo.ninja/?headertitle=LINDENKRON4TW&favicon=https%3A%2F%2Fmeshcast.io%2Ffavicon.ico`](https://vdo.ninja/?headertitle=LINDENKRON4TW\&favicon=https%3A%2F%2Fmeshcast.io%2Ffavicon.ico)

<div align="left">

<figure><figcaption></figcaption></figure>

</div>

## Related

{% content-ref url="and-favicon-alpha.md" %}
[and-favicon-alpha.md](and-favicon-alpha.md)
{% endcontent-ref %}




---
description: Hides just the top header-bar
---

# \&hideheader

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&noheader`
* `&hh`

## Details

`&hideheader` could be useful for hiding VDO.Ninja branding, making videos a bit larger at times, or for IFRAME use-case applications.

It hides this:

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="and-hidemenu.md" %}
[and-hidemenu.md](and-hidemenu.md)
{% endcontent-ref %}




---
description: Hides the VDO.Ninja-branded menu and header bar
---

# \&hidemenu

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&hm`

## Details

Hides the VDO.Ninja-branded menu and header bar.

Useful for making videos larger for guests by freeing up space.

## Related

{% content-ref url="and-hideheader.md" %}
[and-hideheader.md](and-hideheader.md)
{% endcontent-ref %}




---
description: Lets you pass a third party hosted javascript file URL
---

# \&js

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Options

Example: `&js=https%3A%2F%2Fvdo.ninja%2Fexamples%2Ftestjs.js`

| Value         | Description                             |
| ------------- | --------------------------------------- |
| (encoded URL) | Third party hosted java script file URL |

## Details

`&js` lets you pass a third party hosted java script file URL (URL-encoded), allowing for a custom code injection without self-hosting, IFrames or chrome extensions.

Example:\
[https://vdo.ninja/?js=https%3A%2F%2Fvdo.ninja%2Fexamples%2Ftestjs.js](https://vdo.ninja/?js=https%3A%2F%2Fvdo.ninja%2Fexamples%2Ftestjs.js)

You can use this tool to encode the URL you want to link to\
[https://www.urlencoder.org/](https://www.urlencoder.org/)

## Related

{% content-ref url="and-base64js.md" %}
[and-base64js.md](and-base64js.md)
{% endcontent-ref %}




---
description: Forces to enable the lightmode / disable the darkmode
---

# \&lightmode

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Details

Forces to enable the lightmode. It's the same like [`&darkmode=0`](darkmode.md) or [`&darkmode=false`](darkmode.md).

## Related

{% content-ref url="darkmode.md" %}
[darkmode.md](darkmode.md)
{% endcontent-ref %}




---
description: Inverts the video so it is the mirror reflection
---

# \&mirror

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Options

Example: `&mirror=2`

<table><thead><tr><th width="217">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>Mirroring is forced for all videos</td></tr><tr><td><code>0</code></td><td>Preview video is mirrored only (excluding rear cameras and OBS Virtualcam/NDI)</td></tr><tr><td><code>1</code></td><td>Mirroring is forced for all videos</td></tr><tr><td><code>2</code></td><td>Inverts the default; local previews are not mirrored, but guests are mirrored</td></tr><tr><td><code>3</code></td><td>Same as default, except everything is mirrored, including text - useful for teleprompters</td></tr></tbody></table>

## Details

Mirroring does not work if using the browser's native video full-screen button. Use [`&effects=2`](../../source-settings/effects.md) instead for this use case.

Try `F11` or the Electron Capture app (right-click → Resize window -> Fullscreen) to hide the browser menu instead.

#### Alternative method for mirroring and flipping

If you are looking for a form of rotation and flipping that rotates the actual video, rather than relying on CSS to achieve it, you can check out the sender-side [`&effects`](../../source-settings/effects.md) options.\
\
`https://vdo.ninja/beta/?effects=-1`, which will flip the video `https://vdo.ninja/beta/?effects=-2`, which will flip and mirror the video\
`https://vdo.ninja/beta/?effects=2`, which will mirror the video\
\
Effects however may increase CPU/GPU usage, and could cause frame rate instability, especially if the browser tab is not in active focus.

### Dedicated teleprompter tool that works for most sites

There's a dedicated tool for mirror, flipping, and rotating websites as part of VDO.Ninja as well:

[teleprompter-tool.md](../../steves-helper-apps/teleprompter-tool.md "mention")

In case the built-in options to mirror or flip don't work, the teleprompter app might be a good alternative.

## Related

{% content-ref url="../../steves-helper-apps/teleprompter-tool.md" %}
[teleprompter-tool.md](../../steves-helper-apps/teleprompter-tool.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/effects.md" %}
[effects.md](../../source-settings/effects.md)
{% endcontent-ref %}

{% content-ref url="and-flip.md" %}
[and-flip.md](and-flip.md)
{% endcontent-ref %}




---
description: Disables the default mirror state of the video preview for a guest
---

# \&nomirror

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Details

`&nomirror` disables the default mirror state of the video preview for a guest, unlike [`&mirror=0`](and-mirror.md). Previews are often mirrored by default. [`&mirror`](and-mirror.md) can be applied on top of that state, to mirror things back for everyone if needed.

## Related

{% content-ref url="and-mirror.md" %}
[and-mirror.md](and-mirror.md)
{% endcontent-ref %}

{% content-ref url="../../guides/how-to-mirror-a-video-while-full-screen-for-ipads-and-teleprompters.md" %}
[how-to-mirror-a-video-while-full-screen-for-ipads-and-teleprompters.md](../../guides/how-to-mirror-a-video-while-full-screen-for-ipads-and-teleprompters.md)
{% endcontent-ref %}




---
description: Disables the tally light effects
---

# \&obsoff

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&oo`
* `&disableobs`

## Details

Disables the tally light effects; can be applied to both viewer or publisher. Tally lights are represented as a glowing red border around videos. When the light is on, the video is considered "VISIBLE" within OBS Studio. This is based on whether OBS Studio tells VDO.Ninja if a video is active or not.

{% hint style="info" %}
Videos on **first-load** in OBS, even if visible in OBS, **don't glow red**; it requires an **initial visibility change to trigger it**.
{% endhint %}

`&obsoff` can be used to set permissions to fully off (also disables tally light and scene optimizations tho) when added to the OBS browser source link.

## Related

{% content-ref url="../settings-parameters/and-controlobs.md" %}
[and-controlobs.md](../settings-parameters/and-controlobs.md)
{% endcontent-ref %}

{% content-ref url="tallyoff-1.md" %}
[tallyoff-1.md](tallyoff-1.md)
{% endcontent-ref %}




---
description: Auto PIP the first loaded video
---

# \&pip

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Details

Adding this to a guest's link in a room, it forces the system-based PIP to trigger on the first video that loads.

.png>)

## Related

{% content-ref url="and-pipall-alpha.md" %}
[and-pipall-alpha.md](and-pipall-alpha.md)
{% endcontent-ref %}

{% content-ref url="and-pipme-alpha.md" %}
[and-pipme-alpha.md](and-pipme-alpha.md)
{% endcontent-ref %}




---
description: >-
  New floating picture in picture mode, so you can pop out the entire video mix
  as a pinned window overlay
---

# \&pipall

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&pip2`

## Details

Added a new floating picture in picture mode, so you can pop out the entire video mix as a pinned window overlay.

`&pipall` will add a dedicated button for this mode.\
 (1) (1) (1) (1).png>)

Or just right-click any video and select "Picture in picture all" from the context menu. This is available without any URL option.\
.png>)

This requires Chrome v115 right now; it might vanish in v116 due to it being in a `chrome field trial`, and so you might need to enable it via `chrome:flags` if it stops working.

Update: Doesn't break the site if browser does not supported.

## Related

{% content-ref url="and-pip.md" %}
[and-pip.md](and-pip.md)
{% endcontent-ref %}

{% content-ref url="and-pipme-alpha.md" %}
[and-pipme-alpha.md](and-pipme-alpha.md)
{% endcontent-ref %}




---
description: >-
  Will cause your self-video preview window to pop out into its own picture in
  picture
---

# \&pipme

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&mypip`
* `&pip3`

## Details

`&pipme` will cause your self-video preview window to pop out into its own picture in picture (floating/draggable) on load.

This is not compatible with [`&autostart`](../../source-settings/and-autostart.md). Works with director or guest; not tested on mobile.

`CTRL + ALT + P` will also toggle the picture in picture, without needing any URL parameters. (`cmd + ALT + P` on Mac)

## Related

{% content-ref url="and-pip.md" %}
[and-pip.md](and-pip.md)
{% endcontent-ref %}

{% content-ref url="and-pipall-alpha.md" %}
[and-pipall-alpha.md](and-pipall-alpha.md)
{% endcontent-ref %}




---
description: Rotates the camera
---

# \&rotate

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&rotate=180`

<table><thead><tr><th width="212">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given) | <code>90</code></td><td>90 degree</td></tr><tr><td>(degree)</td><td>Rotates the camera in the specified value in degree</td></tr></tbody></table>

## Details

Applies to the publisher's side. Rotates the camera 90-deg by default, or specify `&rotate=180` or `&rotate=270` to rotate more.

Rotates your video for the guests/OBS as well. The rotation uses CSS.

{% hint style="warning" %}
CSS-based video effects will not work in full-screen mode. As well, the control-bar gets rotated with the video, when using CSS.&#x20;
{% endhint %}

#### If looking to flip or mirror a video instead:

If you are looking for a form of mirroring and flipping that changes the actual video, rather than relying on CSS to achieve the effect, you can check out the sender-side [`&effects`](../../source-settings/effects.md) options.\
\
`https://vdo.ninja/beta/?effects=-1`,  which will flip the video `https://vdo.ninja/beta/?effects=-2`,  which will flip and mirror the video\
`https://vdo.ninja/beta/?effects=2`,  which will mirror the video\
\
Effects however may increase CPU/GPU usage, and could cause frame rate instability, especially if the browser tab is not in active focus.

There's also the [`&flip`](and-flip.md) and [`&mirror`](and-mirror.md) options, which use CSS, but are generally viewer-side only.

### Dedicated teleprompter tool that works for most sites

There's a dedicated tool for mirror, flipping, and rotating websites as part of VDO.Ninja as well:

[https://vdo.ninja/teleprompter](https://vdo.ninja/teleprompter)

In case the built-in options to mirror or flip don't work, the teleprompter app might be a good alternative.

## Related

{% content-ref url="../../source-settings/effects.md" %}
[effects.md](../../source-settings/effects.md)
{% endcontent-ref %}

{% content-ref url="and-flip.md" %}
[and-flip.md](and-flip.md)
{% endcontent-ref %}

{% content-ref url="and-mirror.md" %}
[and-mirror.md](and-mirror.md)
{% endcontent-ref %}

{% content-ref url="and-rotatewindow.md" %}
[and-rotatewindow.md](and-rotatewindow.md)
{% endcontent-ref %}




---
description: Will rotate the contents of the VDO.Ninja window
---

# \&rotatewindow

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&rotatepage`

## Options

Example: `&rotatewindow=270`

<table><thead><tr><th width="212">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given) | <code>90</code></td><td>90 degree</td></tr><tr><td>(degree)</td><td>Rotates the page in the specified value in degree</td></tr></tbody></table>

## Details

`&rotatewindow` will rotate the contents of the VDO.Ninja window. It doesn't target any specific video, and can be used on the viewer-side, not just the sender.

This will be overridden by [`&forcelandscape`](../mobile-parameters/and-forcelandscape.md) mode, if that is used also.

You can pass `90`, `180`, or `270` as a value to the parameter, to rotate accordingly. The default is `90` though, if used without any value.

You might still want to use OBS to rotate instead, but if not using OBS and find the teleprompter app too cumbersome, this is a good option.

<div align="left"><figure><figcaption></figcaption></figure></div>

## Related

{% content-ref url="and-rotate.md" %}
[and-rotate.md](and-rotate.md)
{% endcontent-ref %}

{% content-ref url="and-flip.md" %}
[and-flip.md](and-flip.md)
{% endcontent-ref %}

{% content-ref url="and-mirror.md" %}
[and-mirror.md](and-mirror.md)
{% endcontent-ref %}




---
description: Lets you specify how many rows to use in the VDO.Ninja auto mixer.,
---

# \&rows

`&rows` lets you specify how many rows to use in the VDO.Ninja auto mixer.,

* eg: [https://vdo.ninja/?scene=0\&room=123123123333\&cover\&rows=1,1,1,2\&fakeguests=3](https://vdo.ninja/alpha/?scene=0\&room=123123123333\&cover\&rows=1,1,1,2\&fakeguests=3),
* you'll notice the parameter can take comma separated values, or just 1 value if needed,
* row=1 will be just one row, regardless of how many guests, and row=1,1,1,2 for example will be 1 row if 1 guest, 2 guest, or 3 guest, but two rows (2x2) if 4 guests. If more than than, the guests will squeeze into still just two rows.

<figure><figcaption></figcaption></figure>

When using `&rows` a negative row value will now center the videos in the row if not a complete row.

* eg: `&rows=1,-2` vs `&rows=1,2`

<div align="left" data-full-width="false"><figure><figcaption><p>Not-Centered: https://vdo.ninja/alpha/?fakeguests=3&#x26;room=XX&#x26;scene&#x26;rows=1,2</p></figcaption></figure></div>

<figure><figcaption><p>Centered: https://vdo.ninja/alpha/?fakeguests=3&#x26;room=XX&#x26;scene&#x26;rows=1,-2</p></figcaption></figure>

```
Centered: https://vdo.ninja/alpha/?fakeguests=3&room=XX&scene&rows=1,-2

Not-Centered: https://vdo.ninja/alpha/?fakeguests=3&room=XX&scene&rows=1,2
```




---
description: Includes non-media-based push connections as video elements in a group room
---

# \&showall

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&style=7`

## Details

Added `&showall` (or [`&style=7`](style.md)), which will include non-media-based push connections as video elements in a group room. This can include guests that joined without audio/video, directors, or a data-only connection, like maybe MIDI-output source.

To help avoid some types of connections showing up when using `&showall`, I've also added a [`&nopush`](../settings-parameters/and-nopush.md) mode, which blocks outbound publishing connections. This acts a bit like a [`&scene=1`](../view-parameters/scene.md) link, so unless `&showall` is added, you'll need to use the IFRAME API to show/hide videos in it.

## Related

{% content-ref url="style.md" %}
[style.md](style.md)
{% endcontent-ref %}

{% content-ref url="../settings-parameters/and-nopush.md" %}
[and-nopush.md](../settings-parameters/and-nopush.md)
{% endcontent-ref %}




---
description: Will have the video holding div element be structured to the aspect ratio
---

# \&structure

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Details

`&structure` will have the video holding div element be structured to 16:9 (or whatever [`&aspectratio`](../video-parameters/and-aspectratio.md) is set to), making it easier to apply custom CSS backgrounds to videos.

It will have the label/border/margins align relative to the 16:9 holder element, rather than video itself.

Also related, you can also specify the background color independent of the border color with [`&color`](and-color.md). If using [`&border`](and-border.md), it will not set the background color, so you may need to use both `&border` and `&color`.

May not yet work with [`&forcedlandscape`](../mobile-parameters/and-forcelandscape.md) or [`&rotate`](and-rotate.md).

<figure><figcaption></figcaption></figure>

Updated `&structure` to work with [`&cover`](../view-parameters/cover.md), allowing for some more flexibility with controlling fixed aspect-ratios from the viewer/scene side.\
ie: `https://vdo.ninja/?room=XXXXX&scene&cover&structure&square&fakeguests=10`\
 (1) (1) (1) (1) (1) (1).png>) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)

## Related

{% content-ref url="../mixer-scene-parameters/and-locked.md" %}
[and-locked.md](../mixer-scene-parameters/and-locked.md)
{% endcontent-ref %}

{% content-ref url="and-color.md" %}
[and-color.md](and-color.md)
{% endcontent-ref %}

{% content-ref url="and-blur.md" %}
[and-blur.md](and-blur.md)
{% endcontent-ref %}

{% content-ref url="and-border.md" %}
[and-border.md](and-border.md)
{% endcontent-ref %}




---
description: Makes the background transparent
---

# \&transparent

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&transparency`

## Details

Makes the background for the website transparent using CSS.

The browser source in OBS already has a transparent background by default.

This is useful for embedding VDO.Ninja as an [IFRAME](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe).\
Not helpful with the Electron Capture app.\
Not needed for OBS if using default OBS CSS stylesheet:

```css
body {
    background-color: rgba(0, 0, 0, 0);
    margin: 0px auto;
    overflow: hidden;
}
```

## Related

A video demo of the [`&chunked`](../../newly-added-parameters/and-chunked.md) transfer and how to enable support for alpha-channel transparency is available here: [https://youtu.be/SWDlm1Jf-Oo](https://youtu.be/SWDlm1Jf-Oo)

{% content-ref url="chroma.md" %}
[chroma.md](chroma.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-chunked.md" %}
[and-chunked.md](../../newly-added-parameters/and-chunked.md)
{% endcontent-ref %}




---
description: Sets the background for the website to a particular hex color
---

# \&chroma

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Options

Example: `&chroma=F0F`

| Value            | Description             |
| ---------------- | ----------------------- |
| (no value given) | green background        |
| `F0F`            | any RGB format color    |
| `DEDEDE`         | any RRGGBB format color |

{% hint style="info" %}
Use it to chroma-key out the background on the Electron Capture app.
{% endhint %}

{% hint style="danger" %}
Do not include the # character with the hex value.
{% endhint %}

Can be 3 or 6 characters in length, 0 to F, in RGB or RRGGBB format.

[https://vdo.ninja/?scene\&room=roomname\&chroma](https://vdo.ninja/?scene\&room=roomname\&chroma)\
 (1) (1) (2) (2).png>)

See [`&color`](and-color.md) if you want to set the background color of one single video feed.

## Related

{% content-ref url="and-color.md" %}
[and-color.md](and-color.md)
{% endcontent-ref %}

{% content-ref url="and-transparent.md" %}
[and-transparent.md](and-transparent.md)
{% endcontent-ref %}

{% content-ref url="and-background.md" %}
[and-background.md](and-background.md)
{% endcontent-ref %}




---
description: Cleaner output; not as clean as &cleanoutput
---

# \&cleanish

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Details

Same as [`&cleanoutput`](cleanoutput.md), except:

* It still shows the play button that allows handling gesture requirements in chrome.
* Director direct overlay messages are still visible.
* When using `&cleanish` and [`&record`](../recording-parameters/and-record.md), you'll get the record button showing, but nothing else.

and as of VDO.Ninja version 26.4,&#x20;

* You can still access the right-click menu, while you can't if using \&clean\
  \

## Related

{% content-ref url="cleanoutput.md" %}
[cleanoutput.md](cleanoutput.md)
{% endcontent-ref %}

{% content-ref url="../../director-settings/cleandirector.md" %}
[cleandirector.md](../../director-settings/cleandirector.md)
{% endcontent-ref %}




---
description: Keeps the output as clean as possible from UI elements
---

# \&cleanoutput

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&clean`

## Details

Hides many of the UI elements and pop-ups that may cause unwanted visual elements not desired in a high-stakes live stream.\
\
`&cleanish`is a slightly less strict version, which tries to better balance what is available and what isn't in this mode.\

As of VDO.Ninja version 26.4,&#x20;

* You cannot access the right-click menu when using \&clean, however you can with \&cleanish

## Related

{% content-ref url="cleanish.md" %}
[cleanish.md](cleanish.md)
{% endcontent-ref %}

{% content-ref url="../../director-settings/cleandirector.md" %}
[cleandirector.md](../../director-settings/cleandirector.md)
{% endcontent-ref %}

{% content-ref url="and-cleanviewer.md" %}
[and-cleanviewer.md](and-cleanviewer.md)
{% endcontent-ref %}




---
description: Loads a custom CSS file
---

# \&css

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Options

Example: `&css=https%3A%2F%2Fbackup.vdo.ninja%2Fdev4321%2Fexamples%2Fmain.css`

<table><thead><tr><th width="188.55474452554745">Value</th><th>Description</th></tr></thead><tbody><tr><td>(encoded URL)</td><td>will show the VU-style meter that the director has by default already</td></tr></tbody></table>

Any URL-encoded URL that links to a CSS file.

Example:\
[https://vdo.ninja/?css=https%3A%2F%2Fbackup.vdo.ninja%2Fdev4321%2Fexamples%2Fmain.css](https://vdo.ninja/?css=https%3A%2F%2Fbackup.vdo.ninja%2Fdev4321%2Fexamples%2Fmain.css)

You can use this tool to encode the URL you want to link to\
[https://www.urlencoder.org/](https://www.urlencoder.org/)

## Details

Link to a remotely hosted CSS style sheet via the URL. You can stylize VDO.Ninja without needing to host anything more than a CSS file. The page elements are not visible until the remote style sheet has been loaded.

I've made the `&css` parameter within VDO.Ninja more tolerant to invalid forms of input, so if you don't know what URL or Base64 encoding is, you might be able to get away without using any now.\
[`https://vdo.ninja/?css=body{background-color:blue!important}`](https://vdo.ninja/?css=body{background-color:blue!important})

### base64css

You can pass CSS as a base64-encoded string using the [`&base64css`](and-base64css.md) parameter. This needs to be URLComponent encoded first, and then converted to base 64.&#x20;

The [https://invite.vdo.ninja/](https://invite.vdo.ninja/) tool has an option to do these base64 encoding steps under "General Options".

### Customizable director's dock for OBS

Customizable director's dock for OBS example made:\
`&css=minidirector.css`

Example:\
[https://vdo.ninja/?css=minidirector.css\&cleanoutput\&hidesolo\&director](https://vdo.ninja/?css=minidirector.css\&cleanoutput\&hidesolo\&director)

## Related

{% content-ref url="and-base64css.md" %}
[and-base64css.md](and-base64css.md)
{% endcontent-ref %}




---
description: Darkens the website and interface
---

# \&darkmode

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&nightmode`

## Options

Example: `&darkmode=0`

| Value            | Description            |
| ---------------- | ---------------------- |
| (no value given) | enables the dark-mode  |
| `0` \| `false`   | disables the dark-mode |

## Details

Enables the dark-mode stylings of the website.

Conversely, setting [`&lightmode`](and-lightmode.md), `&darkmode=0` or `&darkmode=false` will disable the dark-mode, forcing the light-mode.

The dark-mode will be selected automatically by default if your system is set to dark color mode, so this flag can be used to override that.

## Related

{% content-ref url="and-lightmode.md" %}
[and-lightmode.md](and-lightmode.md)
{% endcontent-ref %}




---
description: Applies an rule-of-thirds grid overlay to the self-preview
---

# \&grid

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&ruler`
* `&thirds`

## Options

Example: `&grid=./media/thirdshead.svg`

<table><thead><tr><th width="215">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>adds a white rule-of-thirds grid overlay</td></tr><tr><td>(encoded URL)</td><td>adds an image as a overlay</td></tr></tbody></table>

## Details

Applies an rule-of-thirds grid overlay to the self-preview video window. This is useful for passively nudging guests to better center themselves while on camera.

{% hint style="warning" %}
As of [v19.0](../../releases/v19/), this only works for guests of a room or of a faux-room. It doesn't yet support basic push/view links, as those don't use the auto-mixer code, which is where this code is currently applied.
{% endhint %}

 (1).png>)

### Changes in Version 22

Added the option to customize the `&grid` effect by passing an image link (can help center guests).

A transparent PNG or an SVG file are the recommended options.

It will stretch to cover the camera preview-area, so probably best to keep things 16:9 aspect if needed.

URL can be URL-encoded, for more complex URLs. Simple URLs might work without.

Technically this can be used as an overlay for other things, but it only works with the self-preview.

Example: [`https://vdo.ninja/?push&grid=./media/thirdshead.svg`](https://vdo.ninja/?push\&grid=./media/thirdshead.svg)

Leave the passed value empty if you wish to have the white basic rule-of-thirds show as default.

{% hint style="info" %}
* As of v22, it now works in non-room mode (basic push links):\
  [https://vdo.ninja/?push\&grid](https://vdo.ninja/?push\&grid)
* You can now also toggle it in the director's room to add it to the guest's link:\
   (1).png>)
{% endhint %}

You can encode your URL here:\
[https://www.urlencoder.org/](https://www.urlencoder.org/)




---
description: Adds a margin around the videos in pixel
---

# \&margin

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Options

Example: `&margin=100`

| Value            | Description         |
| ---------------- | ------------------- |
| (no value given) | margin value = 10px |
| (integer value)  | margin value in px  |

## Details

Adds 10px around the videos for some spacing, by default. It can be customized.\
`https://vdo.ninja/?scene&room=roomname&margin=100`\
 (1) (2) (1).png>)

It's also available as a toggle to the director's room.\
.png>)




---
description: Optional audio meter style type
---

# \&meterstyle

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&director`](../../viewers-settings/director.md))

## Aliases

* `&meter`

## Options

Example: `&meterstyle=3`

<table><thead><tr><th width="218.55474452554745">Value</th><th>Description</th></tr></thead><tbody><tr><td>Default</td><td>a green dot in the right-corner that only shows in the guest / director view</td></tr><tr><td><code>1</code> | (no value given)</td><td>will show the VU-style meter that the director has by default already</td></tr><tr><td><code>2</code></td><td>will show a green-border around the guest's video when they are talking</td></tr><tr><td><code>3</code></td><td>will show a little green dot in the top-right corner when the guest's talking; this is default for the guest's view already</td></tr><tr><td><code>4</code></td><td>no meter is shown, but a data-attribute named <code>data-loudness</code> is applied to the video element. This can be targeted with CSS to do custom styles via OBS browser source or with <a href="css.md"><code>&#x26;css</code></a></td></tr><tr><td><code>5</code></td><td>has the audio-only background image pulse larger in size when that specific guest is speaking</td></tr></tbody></table>

<figure><figcaption></figcaption></figure>

## Details

If you add this to a director's/guest's URL, it will show an optional audio style type, when a guest is talking.

For guests and directors, there is a default meter style that shows a green dot in the top right for when someone is speaking.

<figure><figcaption><p>Default meter style for guests/directors</p></figcaption></figure>

When using any `&meterstyle` effect, I now include a data attribute called `data-speaking` to the video element. It will be either 0, 1, or 2. 0 is quiet, 1 is whispering, and 2 is loud. `&meterstyle=4` includes a fine-grain option already for loudness as an attribute, but for basic CSS needs, this option might be more approachable.

You can use this attribute to use CSS to customize your own effects when someone speaks. You can further target what is CSS used based on a specific guest by using each video's stream ID data attribute as well.

The meter will not appear if audio is not yet playing/active, or is audio-processing is disabled (\&noap). This might be the case with certain mobile devices as well.

### \&meterstyle=2

A common request is a green box around the activer speaker

### .png>)

### \&meterstyle=4

When using `&meterstyle=4` or greater, the background of an audio-only element is transparent now; not black. I also specifically hide the video-control bar when using `&meterstyle=4`, but you can use [`&videocontrols`](../newly-added-parameters/and-videocontrols.md) to add them back in if needed.

### \&meterstyle=5

It can be used in conjunction with [`&bgimage`](and-bgimage.md) to specific a custom background image for the video, which will pulse in size. ie: `&meterstyle=5&bgimage=./media/avatar1.png`

## Related

{% content-ref url="../view-parameters/activespeaker.md" %}
[activespeaker.md](../view-parameters/activespeaker.md)
{% endcontent-ref %}

{% content-ref url="style.md" %}
[style.md](style.md)
{% endcontent-ref %}




---
description: Rounds the edges of videos
---

# \&rounded

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&round`

## Options

Example: `&rounded=100`

<table><thead><tr><th width="246">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>50 px</td></tr><tr><td>(positive integer value)</td><td>the higher the number, the more aggressive the curve</td></tr></tbody></table>

## Details

This is a stylistic effect; it attempts to apply rounded edges to videos (crop-based).

The default value is 50-pixels. You can pass other integer values to customize the amount of curving; the higher the number, the more aggressive the curve.

This works great for solo-video streams where the video fits the window fully, but may not round the edges of videos that do not fit their container area. To compensate for this, using the [`&cover`](../view-parameters/cover.md) command as well can force the video to fit the window, and hence, have the rounded edges applied correctly.\
\
An example of an aggressive rounded effect is with the following parameters: \
`https://vdo.ninja/?view=streamID123&cover&rounded=1000`

.png>)

## Related

{% content-ref url="../view-parameters/cover.md" %}
[cover.md](../view-parameters/cover.md)
{% endcontent-ref %}




---
description: Display labels as a video overlay
---

# \&showlabels

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&showlabel`
* `&sl`

## Options

There are some preset style options, which can be passed to the parameter as a value. You can also choose to just edit the label's style with CSS, as discussed lower on this page.

Example: `&showlabels=ninjablue`

<table><thead><tr><th width="210.9699570815451">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>Generic styled display names</td></tr><tr><td><code>fire</code></td><td>Fire looking display names</td></tr><tr><td><code>ninjablue</code></td><td>VDO.Ninja styled display names</td></tr><tr><td><code>skype</code></td><td>Skype styled display names</td></tr><tr><td><code>teams</code></td><td>Microsoft Teams styled display names</td></tr><tr><td><code>toprounded</code></td><td>Top-center rounded display names</td></tr><tr><td><code>zoom</code></td><td>Zoom styled display names</td></tr><tr><td><code>rounded</code></td><td>Rounded lower-right names; bold</td></tr></tbody></table>

## Details

This parameter will display the user's display name or label on screen, as a text overlay. The label can be set either via the URL using the [`&label`](../../general-settings/label.md) parameter, or the room's director can set it dynamically via the "Add a label" option.

This parameter can be used on guest links, view links, or scene links. It will be sticky to each individual video and not the browser window as a whole.

Underscores "\_" used in label values will be replaced by spaces, allowing for word separation.

HTML5 Emojis 🎈 and some non-Latin characters are supported.

For example: `https://vdo.ninja/?showlabels=fire`\
.png>)

If no preset option is passed, a default generic style is used:\
.png>)

### Font size customization

You can change the font-size without using CSS, using the [`&fontsize`](../view-parameters/fontsize.md) parameter. CSS is also supported though.

Font-size of labels will adjust slightly based on the window size.

### Advanced Customization

CSS of the styles can be set via the OBS browser source stylesheet window.\
The CSS class name you can customize is called `video-label`.

 (1) (1).png>)

You can copy the below code, modifying it as you desire, as a starting point. You'll still need to use `&showlabels` to trigger the labels to display though.

```
.video-label {
	color: red;
  bottom: 2vh;
	left: 50%;
	transform: translateX(-50%);
  background: rgba(0, 0, 0, .8);
	pointer-events:none;
	border-radius: 5px;
	font-size: 0.8em;
}
```

Below is another example, this time we target the video tile class, creating a margin above the video elements. We can then move the display label into that space, creating a label that is not overlaying the video itself, but still attached.

 (1).png>)

```
.tile {
  margin-top: 10vh !important;
  max-height: 90vh!important;
}

.video-label {
	bottom:unset;
	top:0;
	text-align:middle;
	left:unset;
	background:unset;
	text-shadow : 0 0 10px #035;
	font-size: 7vh!important;
}
```

## Related

{% content-ref url="../../general-settings/label.md" %}
[label.md](../../general-settings/label.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-screensharelabel.md" %}
[and-screensharelabel.md](../../newly-added-parameters/and-screensharelabel.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/fontsize.md" %}
[fontsize.md](../view-parameters/fontsize.md)
{% endcontent-ref %}

{% content-ref url="css.md" %}
[css.md](css.md)
{% endcontent-ref %}

{% content-ref url="../setup-parameters/and-labelsuggestion.md" %}
[and-labelsuggestion.md](../setup-parameters/and-labelsuggestion.md)
{% endcontent-ref %}




---
description: Lets you select how audio-only elements are displayed in OBS and for guests
---

# \&style

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&st`

## Options

Example: `&style=2`

<table><thead><tr><th width="233">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>0</code></td><td>shows the audio-control bar with a little person as a background silhouette, if the stream is an audio-only. This lets you control the volume and mute and get some feedback that the stream is present</td></tr><tr><td><code>1</code> | (no value given)</td><td>hides audio-only windows from appearing. The default is for guests to see audio-only boxes for guests that do not have a video feed; the director is excluded</td></tr><tr><td><code>2</code></td><td>just shows an animated audio waveform of the speaker's voice, although I made the quality HD now</td></tr><tr><td><code>3</code></td><td>shows the audio meter, which you can customize using <a href="meterstyle.md"><code>&#x26;meterstyle</code></a>. You can conversely just use <code>&#x26;meterstyle</code> on its own, and mix it with a different style, and it will still work</td></tr><tr><td><code>4</code></td><td>will just show a black background for any audio-only source</td></tr><tr><td><code>5</code></td><td>will show a random color for a background, instead of just black</td></tr><tr><td><code>6</code></td><td>will show the first letter of the guest's display name, in a colored circle, with a black background. If no display name is provided, it will just be a colored circle on a black background</td></tr><tr><td><code>7</code></td><td>will include non-media-based push connections as video elements in a group room. This can include guests that joined without audio/video, directors, or a data-only connection, like maybe MIDI-output source</td></tr></tbody></table>

## Details

`&style` lets you select how media elements are displayed in OBS and for guests; audio-only elements in particular.

Styles are experimental and will undergo change, tweaks, and likely there are more to come.

The default style depends on numerous factors; the intent is to predict the most desirable for a given situation. Manually setting the style will override the default. Defaults may be changed from time to time, based on user feedback.

There is a toggle in the director's room which adds `&st` to the guest's invite link..png>)

## Related

{% content-ref url="meterstyle.md" %}
[meterstyle.md](meterstyle.md)
{% endcontent-ref %}

{% content-ref url="and-bgimage.md" %}
[and-bgimage.md](and-bgimage.md)
{% endcontent-ref %}

{% content-ref url="and-showall.md" %}
[and-showall.md](and-showall.md)
{% endcontent-ref %}




---
description: Disables the Tally Light's visibility for that particular guest
---

# \&tallyoff

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&notally`
* `&disabletally`
* `&to`

## Details

Disables the Tally Light's visibility for that particular guest.

## Related

{% content-ref url="and-obsoff.md" %}
[and-obsoff.md](and-obsoff.md)
{% endcontent-ref %}




---
description: Will make the tally sign larger and colorize the background of the page
---

# \&tally

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

`&tally` will make the tally sign larger and colorize the background of the page, for added emphasis when the feed is added to OBS.

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="tallyoff-1.md" %}
[tallyoff-1.md](tallyoff-1.md)
{% endcontent-ref %}

{% content-ref url="and-obsoff.md" %}
[and-obsoff.md](and-obsoff.md)
{% endcontent-ref %}




---
description: Options for &director URLs
---

# Director Parameters

Parameters specified for the director's control panel; have to be used together with the [`&director`](../../viewers-settings/director.md) parameter.

## Director Only Parameters

<table><thead><tr><th width="306.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../viewers-settings/director.md"><code>&#x26;director</code></a></td><td>Enters a room as the director, instead of a guest and have full control</td></tr><tr><td><a href="../../director-settings/codirector.md"><code>&#x26;codirector</code></a></td><td>Allows assistant directors to have access to the director's room, with a subset of control</td></tr><tr><td><a href="and-roomkey.md"><code>&#x26;roomkey</code></a></td><td>Trusted bypass key for claim-time room admission controls (skip approval and room-cap checks)</td></tr><tr><td><a href="../../newly-added-parameters/and-blindall.md"><code>&#x26;blindall</code></a></td><td>It allows the director 'blinding' all the guests at a time with a new button</td></tr><tr><td><a href="../../director-settings/cleandirector.md"><code>&#x26;cleandirector</code></a></td><td>Hides the invite URL options in the Director's room</td></tr><tr><td><a href="../../newly-added-parameters/and-hidesolo.md"><code>&#x26;hidesolo</code></a></td><td>Lets you hide the solo links from showing</td></tr><tr><td><a href="and-hidecodirectors.md"><code>&#x26;hidecodirectors</code></a></td><td>Hides the co-directors from appearing in the director's room</td></tr><tr><td><a href="../../newly-added-parameters/and-minidirector.md"><code>&#x26;minidirector</code></a></td><td>Default mini director stylesheet</td></tr><tr><td><a href="../../newly-added-parameters/and-orderby.md"><code>&#x26;orderby</code></a></td><td>Orders guest's by their stream ID in the director's room</td></tr><tr><td><a href="../../general-settings/queue.md"><code>&#x26;queue</code></a></td><td>A basic guest queuing system</td></tr><tr><td><a href="../../director-settings/rooms.md"><code>&#x26;rooms</code></a></td><td>Quick director access to a list of rooms for transfering guests</td></tr><tr><td><a href="and-broadcasttransfer.md"><code>&#x26;broadcasttransfer</code></a></td><td>Will let you specify the default for whether to transfer a guest from room to room in broadcast mode or not</td></tr><tr><td><a href="../../viewers-settings/and-showdirector.md"><code>&#x26;showdirector</code></a></td><td>Lets the director perform alongside guests, showing up in scene-view links</td></tr><tr><td><a href="and-slotmode.md"><code>&#x26;slotmode</code></a></td><td>Gives you the possibility to assign slots to the connected guests</td></tr><tr><td><a href="and-previewmode.md"><code>&#x26;previewmode</code></a></td><td>Activates the Preview layout for the director's room by default</td></tr><tr><td><a href="and-novice.md"><code>&#x26;novice</code></a></td><td>Hides some advanced guest options in the director's control center</td></tr><tr><td><a href="and-layouts.md"><code>&#x26;layouts</code></a></td><td>An ordered array of layouts, which can be used to switch between using the API layouts action</td></tr><tr><td><a href="and-maindirectorpassword.md"><code>&#x26;maindirectorpassword</code></a></td><td>Lets you set a pseudo 'master room password' as a director</td></tr></tbody></table>

## Parameters you can also use as a director

<table><thead><tr><th width="255.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../video-bitrate-parameters/totalroombitrate.md"><code>&#x26;totalroombitrate</code></a></td><td>The total bitrate the guests in a room can view video streams with</td></tr><tr><td><a href="../video-bitrate-parameters/limittotalbitrate.md"><code>&#x26;limittotalbitrate</code></a></td><td>Limits the total outbound bitrate</td></tr><tr><td><a href="../../source-settings/and-notify.md"><code>&#x26;notify</code></a></td><td>Audio alerts for raised hands, chat messages and if somebody joins the room</td></tr><tr><td><a href="../../source-settings/and-mutespeaker.md"><code>&#x26;mutespeaker=0</code></a></td><td>Can be used to have the director join unmuted</td></tr><tr><td><a href="../settings-parameters/and-showconnections.md"><code>&#x26;showconnections</code></a></td><td>Displays the total number of p2p connections of a remote stream</td></tr><tr><td><a href="../settings-parameters/and-widget.md"><code>&#x26;widget</code></a></td><td>Will load a side-bar for guests with an IFrame embed, with support for YouTube / Twitch / Social Stream</td></tr></tbody></table>




---
description: >-
  Will let you specify the default for whether to transfer a guest from room to
  room in broadcast mode or not
---

# \&broadcasttransfer

Director Option! ([`&director`](../../viewers-settings/director.md))

## Aliases

* `&bct`

## Details

`&broadcasttransfer` will let you specify the default for whether to transfer a guest from room to room in [broadcast mode](../view-parameters/broadcast.md) or not. Mainly useful for when using [`&rooms`](../../director-settings/rooms.md), since there isn't a transfer menu option when using it, since its more of a hotkey option.

If a director clicks "transfer", there is a checkmark to enable "covert user into broadcast mode when transferred". This URL option enables it by default. It also then is enabled by default when using the quick-transfer feature used by [`&rooms`](../../director-settings/rooms.md).

## Related

{% content-ref url="../view-parameters/broadcast.md" %}
[broadcast.md](../view-parameters/broadcast.md)
{% endcontent-ref %}

{% content-ref url="../../director-settings/rooms.md" %}
[rooms.md](../../director-settings/rooms.md)
{% endcontent-ref %}

{% content-ref url="../../getting-started/rooms/transfer-rooms.md" %}
[transfer-rooms.md](../../getting-started/rooms/transfer-rooms.md)
{% endcontent-ref %}




---
description: Trusted bypass key for claim-time room admission controls in claimed rooms
---

# \&roomkey

Director Option! / Room-Join Option! ([`&director`](../../viewers-settings/director.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&rk`

## Options

Example: `&roomkey=TRUSTED_BYPASS_KEY`

<table><thead><tr><th width="256">Value</th><th>Description</th></tr></thead><tbody><tr><td>(string)</td><td>Must match the Bypass Key set by the claiming director</td></tr></tbody></table>

## Details

`&roomkey` is used with the v29.2+ room admission controls. If a room has been claimed by a director who set a Bypass Key, invite links that include the matching `&roomkey` value can skip:

* director approval waiting state
* room-cap admission checks

Use this for trusted links, such as co-host/co-director or internal scene workflows.

If the key is missing or wrong, normal room admission rules apply.

Bypass-key behavior is tied to the currently connected claiming director. If that director disconnects, the temporary admission state is removed.

## Related

{% content-ref url="../../director-settings/codirector.md" %}
[codirector.md](../../director-settings/codirector.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/queue.md" %}
[queue.md](../../general-settings/queue.md)
{% endcontent-ref %}

{% content-ref url="../../viewers-settings/director.md" %}
[director.md](../../viewers-settings/director.md)
{% endcontent-ref %}




---
description: Hides the co-directors from appearing in the director's room
---

# \&hidecodirectors

Director Option! ([`&director`](../../viewers-settings/director.md))

## Aliases

* `&hidedirector`
* `&hd`

## Details

`&hidecodirectors` will hide the co-directors from appearing in the director's room. You might have a few co-directors join you, but they might be taking up space, so this is a way to prevent that. It simply hides the boxes; they are still there at a code level.

Changed the logic so it stops the video/audio/IFrame/widget data from any director loading.

This is a bit like the opposite of [`&showdirector`](../../viewers-settings/and-showdirector.md), but only viewer side.

Another change is that it works with more than just one codirector hiding another codirector, but can be used with scenes, view links, or guests.

Lastly, this is not like [`&exclude`](../view-parameters/and-exclude.md), as it still allows the data-connection to happen between the two peers, allowing chat and two codirectors to sync their dashboards/commands. Keeping data connections active is important for directors, who rely on them to issue commands, so exclude is a bit to harsh in some cases.

## Related

{% content-ref url="../../director-settings/codirector.md" %}
[codirector.md](../../director-settings/codirector.md)
{% endcontent-ref %}

{% content-ref url="../../viewers-settings/director.md" %}
[director.md](../../viewers-settings/director.md)
{% endcontent-ref %}




---
description: >-
  An ordered array of layouts, which can be used to switch between using the API
  layouts action
---

# \&layouts

Director Option! ([`&director`](../../viewers-settings/director.md))

## Options

Example: `&layouts=[[{"x":0,"y":0,"w":100,"h":100,"slot":0}],[{"x":0,"y":0,"w":100,"h":100,"slot":1}],[{"x":0,"y":0,"w":100,"h":100,"slot":2}],[{"x":0,"y":0,"w":100,"h":100,"slot":3}],[{"x":0,"y":0,"w":50,"h":100,"c":false,"slot":0},{"x":50,"y":0,"w":50,"h":100,"c":false,"slot":1}],[{"x":0,"y":0,"w":100,"h":100,"z":0,"c":false,"slot":1},{"x":70,"y":70,"w":30,"h":30,"z":1,"c":true,"slot":0}],[{"x":0,"y":0,"w":50,"h":50,"c":true,"slot":0},{"x":50,"y":0,"w":50,"h":50,"c":true,"slot":1},{"x":0,"y":50,"w":50,"h":50,"c":true,"slot":2},{"x":50,"y":50,"w":50,"h":50,"c":true,"slot":3}],[{"x":0,"y":16.667,"w":66.667,"h":66.667,"c":true,"slot":0},{"x":66.667,"y":0,"w":33.333,"h":33.333,"c":true,"slot":1},{"x":66.667,"y":33.333,"w":33.333,"h":33.333,"c":true,"slot":2},{"x":66.667,"y":66.667,"w":33.333,"h":33.333,"c":true,"slot":3}]]`

<table><thead><tr><th width="241">Value</th><th>Description</th></tr></thead><tbody><tr><td>[layout1,layout2,...]</td><td>(URL-encoded ordered array)</td></tr></tbody></table>

## Details

`&layouts=[[{xxxxxx}]]` is a URL parameter option, where you can pass a set of different layouts (as a URL-encoded ordered array) to VDO.Ninja.

This is akin to using the [vdo.ninja/mixer](https://vdo.ninja/mixer), to visually set layouts, but instead you are just manually setting all the available layouts directly, bypassing the mixer app.

Once you have set the layouts, the "layout" [API](../../general-settings/api.md) feature becomes a bit more useful, as you can remotely activate any of those layouts with a simple API command.

I documented the 'layout' API option a bit here, but the tl;dr; is that you can either use this API call to set a layout from within the array of layouts that are set, or you can pass a full-fledge layout-object, for on-the-fly custom layouts.

ie: `{action:'layout',value':5}` or `{action:'layout',value':[{xxxx.layout-stuff-here.xxxx]]}`

fyi, the layout and the API in general work with the [vdo.ninja/mixer](https://vdo.ninja/mixer) page, so you can use it to create the layouts, and then manually switch between them via the API. The API is streamdeck-friendly.

{% embed url="https://github.com/steveseguin/Companion-Ninja/blob/main/README.md#custom-layout-switching-" %}

You can assign guests to custom slots when using [`&slotmode`](and-slotmode.md) on the director's URL.

<figure><figcaption></figcaption></figure>

### URL example

[https://vdo.ninja/?director=roomname\&slotmode\&api=xxx\&layouts=\[\[{"x":0,"y":0,"w":100,"h":100,"slot":0}\],\[{"x":0,"y":0,"w":100,"h":100,"slot":1}\],\[{"x":0,"y":0,"w":100,"h":100,"slot":2}\],\[{"x":0,"y":0,"w":100,"h":100,"slot":3}\],\[{"x":0,"y":0,"w":50,"h":100,"c":false,"slot":0},{"x":50,"y":0,"w":50,"h":100,"c":false,"slot":1}\],\[{"x":0,"y":0,"w":100,"h":100,"z":0,"c":false,"slot":1},{"x":70,"y":70,"w":30,"h":30,"z":1,"c":true,"slot":0}\],\[{"x":0,"y":0,"w":50,"h":50,"c":true,"slot":0},{"x":50,"y":0,"w":50,"h":50,"c":true,"slot":1},{"x":0,"y":50,"w":50,"h":50,"c":true,"slot":2},{"x":50,"y":50,"w":50,"h":50,"c":true,"slot":3}\],\[{"x":0,"y":16.667,"w":66.667,"h":66.667,"c":true,"slot":0},{"x":66.667,"y":0,"w":33.333,"h":33.333,"c":true,"slot":1},{"x":66.667,"y":33.333,"w":33.333,"h":33.333,"c":true,"slot":2},{"x":66.667,"y":66.667,"w":33.333,"h":33.333,"c":true,"slot":3}\]\]](https://vdo.ninja/?director=roomname\&slotmode\&api=xxx\&layouts=\[\[\{%22x%22:0,%22y%22:0,%22w%22:100,%22h%22:100,%22slot%22:0}],\[\{%22x%22:0,%22y%22:0,%22w%22:100,%22h%22:100,%22slot%22:1}],\[\{%22x%22:0,%22y%22:0,%22w%22:100,%22h%22:100,%22slot%22:2}],\[\{%22x%22:0,%22y%22:0,%22w%22:100,%22h%22:100,%22slot%22:3}],\[\{%22x%22:0,%22y%22:0,%22w%22:50,%22h%22:100,%22c%22:false,%22slot%22:0},\{%22x%22:50,%22y%22:0,%22w%22:50,%22h%22:100,%22c%22:false,%22slot%22:1}],\[\{%22x%22:0,%22y%22:0,%22w%22:100,%22h%22:100,%22z%22:0,%22c%22:false,%22slot%22:1},\{%22x%22:70,%22y%22:70,%22w%22:30,%22h%22:30,%22z%22:1,%22c%22:true,%22slot%22:0}],\[\{%22x%22:0,%22y%22:0,%22w%22:50,%22h%22:50,%22c%22:true,%22slot%22:0},\{%22x%22:50,%22y%22:0,%22w%22:50,%22h%22:50,%22c%22:true,%22slot%22:1},\{%22x%22:0,%22y%22:50,%22w%22:50,%22h%22:50,%22c%22:true,%22slot%22:2},\{%22x%22:50,%22y%22:50,%22w%22:50,%22h%22:50,%22c%22:true,%22slot%22:3}],\[\{%22x%22:0,%22y%22:16.667,%22w%22:66.667,%22h%22:66.667,%22c%22:true,%22slot%22:0},\{%22x%22:66.667,%22y%22:0,%22w%22:33.333,%22h%22:33.333,%22c%22:true,%22slot%22:1},\{%22x%22:66.667,%22y%22:33.333,%22w%22:33.333,%22h%22:33.333,%22c%22:true,%22slot%22:2},\{%22x%22:66.667,%22y%22:66.667,%22w%22:33.333,%22h%22:33.333,%22c%22:true,%22slot%22:3}]])

`&layouts=[`

Layout1:\
`[{"x":0,"y":0,"w":100,"h":100,"slot":0}],`\
Layout2:\
`[{"x":0,"y":0,"w":100,"h":100,"slot":1}],`\
Layout3:\
`[{"x":0,"y":0,"w":100,"h":100,"slot":2}],`\
Layout4:\
`[{"x":0,"y":0,"w":100,"h":100,"slot":3}],`\
Layout5:\
`[{"x":0,"y":0,"w":50,"h":100,"c":false,"slot":0},{"x":50,"y":0,"w":50,"h":100,"c":false,"slot":1}],`\
Layout6:\
`[{"x":0,"y":0,"w":100,"h":100,"z":0,"c":false,"slot":1},{"x":70,"y":70,"w":30,"h":30,"z":1,"c":true,"slot":0}],`\
Layout7:\
`[{"x":0,"y":0,"w":50,"h":50,"c":true,"slot":0},{"x":50,"y":0,"w":50,"h":50,"c":true,"slot":1},{"x":0,"y":50,"w":50,"h":50,"c":true,"slot":2},{"x":50,"y":50,"w":50,"h":50,"c":true,"slot":3}],`\
Layout8:\
`[{"x":0,"y":16.667,"w":66.667,"h":66.667,"c":true,"slot":0},{"x":66.667,"y":0,"w":33.333,"h":33.333,"c":true,"slot":1},{"x":66.667,"y":33.333,"w":33.333,"h":33.333,"c":true,"slot":2},{"x":66.667,"y":66.667,"w":33.333,"h":33.333,"c":true,"slot":3}]`\
\
`]`

### Streamdeck usage

You need to add [`&api=xxx`](../../general-settings/api.md) to the director's URL to control the layouts via Streamdeck.

<table><thead><tr><th width="398">HTTP Get</th><th>Description</th></tr></thead><tbody><tr><td><code>https://api.vdo.ninja/xxx/layout/0</code></td><td>Disables the layouts -> Auto-mixing</td></tr><tr><td><code>https://api.vdo.ninja/xxx/layout/1</code></td><td>Select Layout 1</td></tr><tr><td><code>https://api.vdo.ninja/xxx/layout/2</code></td><td>Select Layout 2</td></tr><tr><td><code>https://api.vdo.ninja/xxx/layout/[{"x":0,"y":0,"w":50,"h":100,"c":true,"slot":0},{"x":50,"y":0,"w":50,"h":100,"c":false,"slot":1}]</code> *</td><td>Select specified layout</td></tr></tbody></table>

\*If you use the HTTP Get like this, you don't need to add `&layouts` to the director's URL.

Using these URLs change the layout of your scene in OBS. The URL you should use in OBS is the default one:

[https://vdo.ninja/?scene\&room=roomname](https://vdo.ninja/?scene\&room=roomname)

### Excel-based Layout Generator

[https://docs.google.com/spreadsheets/d/1cHBTfni-Os3SAITsXrrNJ3qVCMVjunuW3xugvw1dykw/edit#gid=151839312](https://docs.google.com/spreadsheets/d/1cHBTfni-Os3SAITsXrrNJ3qVCMVjunuW3xugvw1dykw/edit#gid=151839312)\
\
Download it and save it as .xlsx - then you can edit it and create custom layouts for the `&layouts` parameter.

## Related

{% content-ref url="and-slotmode.md" %}
[and-slotmode.md](and-slotmode.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/api.md" %}
[api.md](../../general-settings/api.md)
{% endcontent-ref %}

{% content-ref url="../mixer-scene-parameters/and-layout.md" %}
[and-layout.md](../mixer-scene-parameters/and-layout.md)
{% endcontent-ref %}




---
description: Lets you set a pseudo 'master room password' as a director
---

# \&maindirectorpassword

Director Option! ([`&director`](../../viewers-settings/director.md))

## Aliases

* `&maindirpass`

## Options

Example: `&maindirectorpassword=SomePassword123`

<table><thead><tr><th width="309">Value</th><th>Description</th></tr></thead><tbody><tr><td>(alphanumeric-characters only)</td><td>the password you want to set for the main director</td></tr></tbody></table>

## Details

`&maindirectorpassword` lets you set a pseudo 'master room password' as a director. It helps avoid getting locked out as the director, if someone else tries to claim the director-role first. ie:\
[`https://vdo.ninja/?director=ROOMNAME&maindirectorpassword=MASTERPASS`](https://vdo.ninja/?director=ROOMNAME\&maindirectorpassword=MASTERPASS)

This will add a [`&token`](../settings-parameters/and-token.md) value to the invite/scene links.

 (1) (9).png>)

This token is used by the guests to check a remote database server to see who currently 'owns' the token; it persists though, even if the director is not connected.

When using `&maindirectorpassword` as a director, it tells this database that you are the owner, and it will persist even if you aren't connected to VDO.Ninja. The [`&token`](../settings-parameters/and-token.md) tells the guest to ignore other logic about who the director is, instead using the info provided by the token-lookup to determine whose the director.

I may change or revoke this feature, depending on how testing goes this week, as it's rather experimental.

## Related

{% content-ref url="../setup-parameters/and-password.md" %}
[and-password.md](../setup-parameters/and-password.md)
{% endcontent-ref %}

{% content-ref url="../../director-settings/codirector.md" %}
[codirector.md](../../director-settings/codirector.md)
{% endcontent-ref %}

{% content-ref url="../settings-parameters/and-token.md" %}
[and-token.md](../settings-parameters/and-token.md)
{% endcontent-ref %}




---
description: Hides some advanced guest options in the director's control center
---

# \&novice

Director Option! ([`&director`](../../viewers-settings/director.md))

## Details

`&novice` hides some advanced guest items in the director's control center.

 (2) (1).png>)

## Related

{% content-ref url="../../viewers-settings/director.md" %}
[director.md](../../viewers-settings/director.md)
{% endcontent-ref %}




# \&pausepreview

Director Option! ([`&director`](../../viewers-settings/director.md))

## Aliases

* `&dpp`

## Options

Example: `&pausepreview`

<table><thead><tr><th width="211">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>The guest video previews that a director sees will pause after a period</td></tr></tbody></table>

## Details

Designe for use with the director's control center

After a few seconds, the video of newly joined guests will pause for the director. In most cases, this will also pause the video bitrate too, setting it to zero or near zero.\
\
The director can use buttons available under the video to increase the quality and restart the video if needed.

This approach provides a snapshot and verification that guests who are joining are who they say they are, provides an opportunity for the video quality to stabilize a bit, and yet also reduces the CPU/Network load that a director faces when many multiple guests are joining.

Unlike using `&novideo`, videos can be resumed, but \&novideo may offer even greater resource savings.




---
description: Activates the Preview layout for the director's room by default
---

# \&previewmode

Director Option! ([`&director`](../../viewers-settings/director.md))

## Details

There is a new button in the director's room. It lets you toggle between a Preview layout and the normal Director layout; the Preview layout will mirror what a basic [`&scene=0`](../view-parameters/scene.md) link would look like.

Useful if you want to switch to a guest-like mode as a director, and then switch back as needed to the director's room to make adjustments. To enter this mode by default,`&previewmode` can be used by the director.

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="../view-parameters/scene.md" %}
[scene.md](../view-parameters/scene.md)
{% endcontent-ref %}

{% content-ref url="../../viewers-settings/director.md" %}
[director.md](../../viewers-settings/director.md)
{% endcontent-ref %}




---
description: Gives you the possibility to assign slots to the connected guests
---

# \&slotmode

Director Option! ([`&director`](../../viewers-settings/director.md))

## Details

Adding `&slotmode` to a director's URL gives you the possibility to assign slots to the connected guests. While the layout switching options of the [Video Mixer](../../steves-helper-apps/mixer-app.md) will be missing when doing this as a normal director, you can still specify [`&layout`](../mixer-scene-parameters/and-layout.md) via the URL for multiple scenes that will obey the slot assignments (might interest advanced users or inspire user suggestions).

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="../../steves-helper-apps/mixer-app.md" %}
[mixer-app.md](../../steves-helper-apps/mixer-app.md)
{% endcontent-ref %}

{% content-ref url="../settings-parameters/and-slot.md" %}
[and-slot.md](../settings-parameters/and-slot.md)
{% endcontent-ref %}

{% content-ref url="../mixer-scene-parameters/and-layout.md" %}
[and-layout.md](../mixer-scene-parameters/and-layout.md)
{% endcontent-ref %}

{% content-ref url="../../viewers-settings/director.md" %}
[director.md](../../viewers-settings/director.md)
{% endcontent-ref %}




---
description: Options for guest queuing and approving system
---

# Guest queuing Parameters

## For Director and Guests

<table><thead><tr><th width="306.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../general-settings/queue.md"><code>&#x26;queue</code></a></td><td>A basic guest queuing system</td></tr></tbody></table>

## For Guests only

<table><thead><tr><th width="255.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-screen-alpha.md"><code>&#x26;screen</code></a>*</td><td>Replaces the way <a href="../../general-settings/queue.md"><code>&#x26;queue</code></a> worked before, where the guest can see/hear the director, but not other guests, until activated</td></tr><tr><td><a href="and-hold-alpha.md"><code>&#x26;hold</code></a>*</td><td>Like <a href="../../general-settings/queue.md"><code>&#x26;queue</code></a>, except the guest gets a message telling them they need to wait until approved by the director</td></tr><tr><td><a href="and-holdwithvideo-alpha.md"><code>&#x26;holdwithvideo</code></a>*</td><td>Just like <a href="and-hold-alpha.md"><code>&#x26;hold</code></a>, except the director does see the guest's video and audio before the guest is activated</td></tr><tr><td><a href="../settings-parameters/and-queuetransfer.md"><code>&#x26;queuetransfer</code></a></td><td>Will transfer a guest from one room into another, but once transferred, the guest will be in Queue mode</td></tr></tbody></table>

\*NEW IN VERSION 24




---
description: >-
  Like &queue, except the guest gets a message telling them they need to wait
  until approved by the director
---

# \&hold

Sender-Side Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&queue3`

## Details

`&hold` added, with the alias `&queue3`, which is like [`&queue`](../../general-settings/queue.md), except the guest gets a message telling them they need to wait until approved by the director. They don't see the director until activated, and the director doesn't see the guest's video/audio either - just their control box with any label. Once activated, the director will see the guest's video/audio, and vice versa.

This mode do not apply when you have [`&queue`](../../general-settings/queue.md) also on the director's link, however, rather just when added to the guest-invite link only.

Transferring the guest to another room will also automatically activate the guest. You don't need to press the pink 'activate' button if you just intend to transfer them and don't want to talk to the guest you are screening.

## Related

{% content-ref url="../../general-settings/queue.md" %}
[queue.md](../../general-settings/queue.md)
{% endcontent-ref %}

{% content-ref url="and-holdwithvideo-alpha.md" %}
[and-holdwithvideo-alpha.md](and-holdwithvideo-alpha.md)
{% endcontent-ref %}

{% content-ref url="and-screen-alpha.md" %}
[and-screen-alpha.md](and-screen-alpha.md)
{% endcontent-ref %}




---
description: >-
  Just like &hold, except the director does see the guest's video and audio
  before the guest is activated
---

# \&holdwithvideo

Sender-Side Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&queue4`

## Details

`&holdwithvideo` added, with the alias `&queue4`, which is just like [`&hold`](and-hold-alpha.md), except the director does see the guest's video and audio before the guest is activated. The guest can't see the director until activated, but does get a message telling them they are waiting to be activated.

This mode do not apply when you have [`&queue`](../../general-settings/queue.md) also on the director's link, however, rather just when added to the guest-invite link only.

Transferring the guest to another room will also automatically activate the guest. You don't need to press the pink 'activate' button if you just intend to transfer them and don't want to talk to the guest you are screening.

## Related

{% content-ref url="../../general-settings/queue.md" %}
[queue.md](../../general-settings/queue.md)
{% endcontent-ref %}

{% content-ref url="and-hold-alpha.md" %}
[and-hold-alpha.md](and-hold-alpha.md)
{% endcontent-ref %}

{% content-ref url="and-screen-alpha.md" %}
[and-screen-alpha.md](and-screen-alpha.md)
{% endcontent-ref %}




---
description: >-
  Replaces the way &queue worked before, where the guest can see/hear the
  director, but not other guests, until activated
---

# \&screen

Sender-Side Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&queue2`

## Details

`&screen` now replaces the way [`&queue`](../../general-settings/queue.md) worked before, where the guest can see/hear the director, but not other guests, until activated.

[`&queue`](../../general-settings/queue.md) was changed to not allow the guest to see the director's video, until the director activates the guest with their pink activate-guest button. Otherwise, it's the same as before.

`&queue2` is given the alias `&screen`, intending to imply you can use this mode to screen incoming guests by talking to them, before approving them.

This mode do not apply when you have [`&queue`](../../general-settings/queue.md) also on the director's link, however, rather just when added to the guest-invite link only.

Transferring the guest to another room will also automatically activate the guest. You don't need to press the pink 'activate' button if you just intend to transfer them and don't want to talk to the guest you are screening.

## Related

{% content-ref url="../../general-settings/queue.md" %}
[queue.md](../../general-settings/queue.md)
{% endcontent-ref %}

{% content-ref url="and-hold-alpha.md" %}
[and-hold-alpha.md](and-hold-alpha.md)
{% endcontent-ref %}

{% content-ref url="and-holdwithvideo-alpha.md" %}
[and-holdwithvideo-alpha.md](and-holdwithvideo-alpha.md)
{% endcontent-ref %}




---
description: >-
  Options for the &meshcast parameter like audio filters, bitrate, screen-share,
  codecs etc.
---

# Meshcast Parameters

**Meshcast Parameters** are specific to the [`&meshcast`](../../newly-added-parameters/and-meshcast.md) parameter. They are all parameters for the publisher's side ([`&push`](../../source-settings/push.md)) and have to be used together with [`&meshcast`](../../newly-added-parameters/and-meshcast.md).

## Source side options

<table><thead><tr><th width="307.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../newly-added-parameters/and-meshcast.md"><code>&#x26;meshcast</code></a></td><td>Triggers the service, causing the outbound audio/video stream to be transferred to a hosted server</td></tr><tr><td><a href="and-meshcastaudiobitrate.md"><code>&#x26;meshcastaudiobitrate</code></a></td><td>Option to change outbound audio bitrate of the <code>&#x26;meshcast</code> parameter</td></tr><tr><td><a href="../../meshcast-settings/and-meshcastbitrate.md"><code>&#x26;meshcastbitrate</code></a></td><td>Option to change outbound video bitrate of the <code>&#x26;meshcast</code> parameter</td></tr><tr><td><a href="../../meshcast-settings/and-meshcastcodec.md"><code>&#x26;meshcastcodec</code></a></td><td>Option to change codec of the <code>&#x26;meshcast</code> parameter</td></tr><tr><td><a href="../../meshcast-settings/and-mcscreensharebitrate.md"><code>&#x26;mcscreensharebitrate</code></a></td><td>Option to change outbound screen-share video bitrate of the <code>&#x26;meshcast</code> parameter</td></tr><tr><td><a href="../../meshcast-settings/and-mcscreensharecodec.md"><code>&#x26;mcscreensharecodec</code></a></td><td>Option to change codec of the <code>&#x26;meshcast</code> parameter while screen-sharing</td></tr><tr><td><a href="../upcoming-parameters/and-meshcastscale.md"><code>&#x26;meshcastscale</code></a></td><td>Scales down the Meshcast video output via the URL</td></tr><tr><td><a href="and-meshcastcode.md"><code>&#x26;meshcastcode</code></a></td><td>Lets you specify the Meshcast server to use</td></tr></tbody></table>

## **Viewer side options**

<table><thead><tr><th width="310.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-nomeshcast.md"><code>&#x26;nomeshcast</code></a></td><td>Tells a sender to provide a p2p stream, rather than a Meshcast stream</td></tr></tbody></table>




---
description: Option to change outbound audio bitrate of the &meshcast parameter
---

# \&meshcastaudiobitrate

Meshcast Option / Sender-Side Option! ([`&meshcast`](../../newly-added-parameters/and-meshcast.md), [`&push`](../../source-settings/push.md))

## Aliases

* `&mcaudiobitrate`
* `&mcab`
* `&meshcastab`

## Options

Example: `&meshcastaudiobitrate=128`

<table><thead><tr><th width="273">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer value)</td><td>publishing Meshcast audio bitrate in kbps</td></tr></tbody></table>

## Details

`&meshcastab` controls the outbound audio bitrate of the [`&meshcast`](../../newly-added-parameters/and-meshcast.md) parameter. Without it, it will be a variable bitrate, up to 32-kbps per channel. With it added, it will be CBR, at the specified bitrate.

## Related

{% content-ref url="../../newly-added-parameters/and-meshcast.md" %}
[and-meshcast.md](../../newly-added-parameters/and-meshcast.md)
{% endcontent-ref %}

{% content-ref url="../../meshcast-settings/and-meshcastbitrate.md" %}
[and-meshcastbitrate.md](../../meshcast-settings/and-meshcastbitrate.md)
{% endcontent-ref %}




---
description: Lets you specify the Meshcast server to use
---

# \&meshcastcode

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&mccode`

## Options

Example: `&meshcastcode=usw2`

<table><thead><tr><th width="200">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>Chooses the best server automatically</td></tr><tr><td>(servercode)</td><td>Chooses the selected Meshcast server</td></tr></tbody></table>

Full server list: [https://meshcast.io/servers.json](https://meshcast.io/servers.json)

## Details

`&meshcastcode`lets you specify the Meshcast server to use. This was already possible with just [`&meshcast`](../../newly-added-parameters/and-meshcast.md), but if you wanted to specify audio/video-only modes as well as the server, this new option will let you specify the server another way, allowing both options to work.

ie: [`https://vdo.ninja/?meshcastcode=cae1&meshcast=video`](https://vdo.ninja/?meshcastcode=cae1\&meshcast=video)

You can select the Meshcast server via URL Parameter, if you want low-level control there.

If you don't set it, the best one will be chosen automatically. If the specified one isn't found, the next best is used.

Example: `&meshcastcode=usw2`

<table><thead><tr><th width="200">Value</th><th>Description</th></tr></thead><tbody><tr><td>(servercode)</td><td>Meshcast server</td></tr><tr><td><code>cae1</code></td><td>Canada-East 1</td></tr><tr><td><code>cae2</code></td><td>Canada-East 2</td></tr><tr><td><code>use1</code></td><td>USA-East 1</td></tr><tr><td><code>use2</code></td><td>USA-East 2</td></tr><tr><td><code>usw1</code></td><td>USA-West 1</td></tr><tr><td><code>usw2</code></td><td>USA-West 2</td></tr><tr><td><code>fr1</code></td><td>France</td></tr><tr><td><code>de1</code></td><td>Germany</td></tr><tr><td><code>usc1</code></td><td>Dev-server</td></tr></tbody></table>

Full server list: [https://meshcast.io/servers.json](https://meshcast.io/servers.json)

## Related

{% content-ref url="../../newly-added-parameters/and-meshcast.md" %}
[and-meshcast.md](../../newly-added-parameters/and-meshcast.md)
{% endcontent-ref %}

{% embed url="https://meshcast.io/" %}
https://meshcast.io/
{% endembed %}




---
description: Tells a sender to provide a p2p stream, rather than a Meshcast stream
---

# \&nomeshcast

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Details

`&nomeshcast` is a viewer-side option that tells a sender to provide a p2p stream, rather than a Meshcast stream, if they have [`&meshcast`](../../newly-added-parameters/and-meshcast.md) active. A bit of a niche option, but might be useful if bandwidth or latency is a consideration for a specific viewer, like the director.

## Related

{% content-ref url="../../newly-added-parameters/and-meshcast.md" %}
[and-meshcast.md](../../newly-added-parameters/and-meshcast.md)
{% endcontent-ref %}




---
description: Layout and design for the mixer in rooms/scenes, preload/hidden scene bitrate
---

# Mixer/Scene Parameters

Mixer/Scene Parameters are viewer side options. You can add them to guest's URLs in rooms and scene URLs.

## **Room and Scene options**

You have to add them to [`&scene`](../view-parameters/scene.md) or [`&room`](../../general-settings/room.md) or [`&view`](../view-parameters/view.md) URLs to change the behaviour of the Video Mixer.

<table><thead><tr><th width="150">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-solo.md"><code>&#x26;solo</code></a></td><td>Similar to <a href="../view-parameters/scene.md"><code>&#x26;scene</code></a>, but tells the system to be a solo-link</td></tr><tr><td><a href="../view-parameters/view.md"><code>&#x26;view</code></a></td><td>Defines the stream(s) you are receiving, by their stream IDs</td></tr><tr><td><a href="and-include.md"><code>&#x26;include</code></a></td><td>Includes streams that do not exist in the room</td></tr><tr><td><a href="../view-parameters/and-exclude.md"><code>&#x26;exclude</code></a></td><td>Same concept as <a href="../view-parameters/view.md"><code>&#x26;view</code></a>, except does the opposite</td></tr><tr><td><a href="and-layout.md"><code>&#x26;layout</code></a></td><td>Shows the guest a return feed of the current mixer layout when using the <a href="../../steves-helper-apps/mixer-app.md">Mixer App</a></td></tr><tr><td><a href="../view-parameters/activespeaker.md"><code>&#x26;activespeaker</code></a></td><td>Auto-hides remote guests videos when added, if those guests are not speaking actively</td></tr><tr><td><a href="../../source-settings/order.md"><code>&#x26;order</code></a></td><td>The order priority of a source video when added to the video mixer</td></tr><tr><td><a href="../../newly-added-parameters/and-slots.md"><code>&#x26;slots</code></a></td><td>Will force the auto-mixer to have that number of slots, even if there are more or less videos available to fill them</td></tr><tr><td><a href="and-fakeguests.md"><code>&#x26;fakeguests</code></a></td><td>Creates simulated guest videos</td></tr><tr><td><a href="../view-parameters/randomize.md"><code>&#x26;randomize</code></a></td><td>Random video loading order</td></tr><tr><td><a href="../view-parameters/cover.md"><code>&#x26;cover</code></a></td><td>Has the videos fully "cover" their assigned areas, even if it means cropping the video</td></tr><tr><td><a href="../../newly-added-parameters/and-43.md"><code>&#x26;43</code></a></td><td>Optimizes the video mixer for 4:3 videos</td></tr><tr><td><a href="../view-parameters/and-portrait.md"><code>&#x26;portrait</code></a></td><td>Optimizes the video mixer for 9:16 videos</td></tr><tr><td><a href="../../newly-added-parameters/and-square.md"><code>&#x26;square</code></a></td><td>Optimizes the video mixer for 1:1 videos</td></tr><tr><td><a href="and-forceviewerlandscape.md"><code>&#x26;forceviewerlandscape</code></a>*</td><td>Keeps all incoming videos oriented (rotated) so that the aspect ratio is always above 1</td></tr><tr><td><a href="../view-parameters/animated.md"><code>&#x26;animated</code></a></td><td>Videos in a group scene will slide around the screen when being re-arranged</td></tr><tr><td><a href="../view-parameters/manual.md"><code>&#x26;manual</code></a></td><td>Disables the auto-mixer, allowing for a custom mixer to be used</td></tr><tr><td><a href="and-locked.md"><code>&#x26;locked</code></a></td><td>Will force a the VDO.Ninja's mixer output keep the mixed render contained to a specific aspect-ratio, regardless of the browser's window size</td></tr><tr><td><a href="and-poster.md"><code>&#x26;poster</code></a></td><td>Lets you specify a poster image for videos that have not yet started playing</td></tr><tr><td><a href="and-hideplaybutton.md"><code>&#x26;hideplaybutton</code></a></td><td>Will hide the default big play button that overlays a video when auto play is not allowed</td></tr><tr><td><a href="and-motiondetection-alpha.md"><code>&#x26;motiondetection</code></a>*</td><td>Does a few things when it detects motion in a video</td></tr></tbody></table>

\*NEW IN VERSION 24

## **Only Scene options**

You have to add them to [`&scene`](../view-parameters/scene.md) or [`&view`](../view-parameters/view.md) URLs.

<table><thead><tr><th width="150">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../view-parameters/scene.md"><code>&#x26;scene</code></a></td><td>Defines the link to be treated like a scene</td></tr><tr><td><a href="scenetype.md"><code>&#x26;scenetype</code></a></td><td>Shows only the last added video to a scene</td></tr><tr><td><a href="../../newly-added-parameters/and-autoadd.md"><code>&#x26;autoadd</code></a></td><td>Auto-adds the specified stream IDs to the scene</td></tr><tr><td><a href="../../newly-added-parameters/and-hiddenscenebitrate.md"><code>&#x26;hiddenscenebitrate</code></a></td><td>Can be used to force videos not added yet to a scene to run at the specified bitrate</td></tr><tr><td><a href="../../newly-added-parameters/and-preloadbitrate.md"><code>&#x26;preloadbitrate</code></a></td><td>Can be used to change the pre-load target bitrate for scenes</td></tr><tr><td><a href="../newly-added-parameters/and-waitimage.md"><code>&#x26;waitimage</code></a></td><td>You can add a custom image which shows up while waiting for the <a href="../view-parameters/scene.md"><code>&#x26;scene</code></a> or <a href="../view-parameters/view.md"><code>&#x26;view</code></a> link</td></tr><tr><td><a href="../newly-added-parameters/and-waitmessage.md"><code>&#x26;waitmessage</code></a></td><td>You can add a custom message which shows up while waiting for the <a href="../view-parameters/scene.md"><code>&#x26;scene</code></a> or <a href="../view-parameters/view.md"><code>&#x26;view</code></a> link</td></tr><tr><td><a href="../newly-added-parameters/and-waittimeout.md"><code>&#x26;waittimeout</code></a></td><td>Specifies a delay for <a href="../newly-added-parameters/and-waitimage.md"><code>&#x26;waitimage</code></a> and <a href="../newly-added-parameters/and-waitmessage.md"><code>&#x26;waitmessage</code></a> while waiting for the <a href="../view-parameters/scene.md"><code>&#x26;scene</code></a> or <a href="../view-parameters/view.md"><code>&#x26;view</code></a> link</td></tr></tbody></table>
---
description: Restores a guest's selected scene assignments after reconnecting
---

# \&scenerestore

Director Option! ([`&director`](../../viewers-settings/director.md), [`&room`](../../general-settings/room.md))

## Details

Add `&scenerestore` to the director URL to let the main director restore a guest's manual scene assignment after that guest disconnects and rejoins.

Example:

```
https://vdo.ninja/?director=ROOMNAME&scenerestore
```

This is useful when guests are manually assigned to scene outputs such as `&scene=1`, `&scene=2`, or `&scene=3`, and a guest drops because of a poor connection.

When enabled, the main director creates a temporary restore lease when a guest is placed into a scene. If that guest reconnects with the matching restore token while the lease is still active, the director can reapply the previous scene selection.

The lease auto-renews while the guest remains connected, so long-running sessions continue to be restorable. After a disconnect, or after the last scene action for that guest, the lease expires after 15 minutes. If the director hangs up, disconnects, or otherwise revokes the guest, the lease expires immediately.

`&scenerestore` is opt-in. It does not bypass room authentication, director approval, queue/hold modes, or the normal director trust checks.

## Related

{% content-ref url="../view-parameters/scene.md" %}
[scene.md](../view-parameters/scene.md)
{% endcontent-ref %}

{% content-ref url="scenetype.md" %}
[scenetype.md](scenetype.md)
{% endcontent-ref %}




---
description: This option can be used in conjunction with &activespeaker
---

# \&activespeakerdelay

To understand the effect of setting  \&activespeakerdelay (`activeSpeakerTimeout)` to 2000 in the `activeSpeaker=1` mode, let's analyze the relevant parts of the code:

When `activeSpeaker` is 1 (or 3), the code aims to show only one speaker at a time - the loudest or last-loud speaker. The `activeSpeakerTimeout` affects how quickly the system switches from one active speaker to another. Here's what happens:

1. Without `activeSpeakerTimeout` (or when it's set to 0):
   * The system immediately switches to the new loudest speaker.
   * As soon as a speaker is no longer the loudest, their `defaultSpeaker` status is set to `false` immediately.
2. With `activeSpeakerTimeout` set to 2000 (2 seconds):
   * When a speaker is no longer the loudest, instead of immediately setting their `defaultSpeaker` status to `false`, the system sets a timeout.
   * If the speaker doesn't become the loudest again within 2 seconds, their `defaultSpeaker` status is then set to `false`.

The key difference is in these lines:

```javascript
if (!session.activeSpeakerTimeout) {
    session.rpcs[loudestActive].defaultSpeaker = false;
    changed = true;
} else {
    session.rpcs[loudestActive].defaultSpeaker = setTimeout(
        function (uuid) {
            session.rpcs[uuid].defaultSpeaker = false;
            updateMixer();
        },
        session.activeSpeakerTimeout,
        loudestActive
    );
}
```

This creates a "grace period" of 2 seconds, which has several effects:

1. It prevents rapid switching between speakers if multiple people are speaking with similar volume levels.
2. It allows for brief pauses in speech without immediately switching to another speaker.
3. It creates a smoother transition between speakers, especially in scenarios with multiple active participants.

In essence, setting `activeSpeakerTimeout` to 2000 makes the system more "patient" before switching speakers, which can lead to a more stable and less distracting visual experience for participants in the call, especially in active discussions where speaker dominance might fluctuate rapidly.




---
description: Creates simulated guest videos
---

# \&fakeguests

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&fakefeeds`

## Options

Example: `&fakeguests=7`

<table><thead><tr><th width="200">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer number)</td><td>creates simulated guest videos, based on the value passed to the parameter</td></tr><tr><td>(no value given)</td><td>4 fake guests added</td></tr></tbody></table>

## Details

`&fakeguests=N` creates simulated guest videos, based on the value passed to the parameter, using real-guests where possible. The default value is 4.&#x20;

You can use this feature to help position and visualize what [`&cover`](../view-parameters/cover.md), [`&portrait`](../view-parameters/and-portrait.md), etc. looks like.

This doesn't yet support labels or layouts really, but I welcome feedback. Currently I just threw up a video of me, 16:9, of 500-kbps.

You don't actually need to create a room / scene to play with it.

Try it at: [https://vdo.ninja/?room=xxxxtestxxxx\&scene\&cover\&square\&fakeguests=7](https://vdo.ninja/?room=xxxxtestxxxx\&scene\&cover\&square\&fakeguests=7)

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="../view-parameters/cover.md" %}
[cover.md](../view-parameters/cover.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/scene.md" %}
[scene.md](../view-parameters/scene.md)
{% endcontent-ref %}




---
description: >-
  Keeps all incoming videos oriented (rotated) so that the aspect ratio is
  always above 1
---

# \&forceviewerlandscape (alpha)

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&forceviewerlandscape=90`

<table><thead><tr><th width="294">Value</th><th>Description</th></tr></thead><tbody><tr><td>(value in degrees)</td><td>value, how much the video is rotated in degree</td></tr><tr><td>(no value given)</td><td><code>270</code></td></tr><tr><td><code>180</code></td><td>locked upside down</td></tr></tbody></table>

## Details

`&forceviewerlandscape` keeps all **incoming** videos oriented (rotated) so that the [aspect ratio](../video-parameters/and-aspectratio.md) is always above 1, so effectively, forces landscape mode.

ie: [https://vdo.ninja/?forceviewerlandscape\&view=xxx](https://vdo.ninja/?forceviewerlandscape\&view=xxx)

This normally shouldn't be needed, as the sender side should control the orientation, but the native app seems to auto rotate back to portrait when the phone is locked. Until that is fixed, this can work around the issue I think, by rotating the video when it detects its been rotated.

The parameter can take a value, the default is `270`, which is how much the video is rotated. You might want to also use `90`, or in the case you want it to be locked upside down, you can technically pass `180` I guess?

## Related

{% content-ref url="../video-parameters/and-aspectratio.md" %}
[and-aspectratio.md](../video-parameters/and-aspectratio.md)
{% endcontent-ref %}

{% content-ref url="../mobile-parameters/and-forcelandscape.md" %}
[and-forcelandscape.md](../mobile-parameters/and-forcelandscape.md)
{% endcontent-ref %}




---
description: >-
  Will hide the default big play button that overlays a video when auto play is
  not allowed
---

# \&hideplaybutton

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&hpb`

## Details

`&hideplaybutton` will hide the default big play button that overlays a video when auto play is not allowed. This option is useful when you want to perhaps include your own playbutton as part of the poster image.

Example of the command:

```
https://vdo.ninja/?view=YbFmisR&poster=./media/bg_sample.webp&hideplaybutton
```

## Related

{% content-ref url="and-poster.md" %}
[and-poster.md](and-poster.md)
{% endcontent-ref %}




---
description: Includes streams that do not exist in the room
---

# \&include

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&include=StreamID`

| Value       | Description                                                         |
| ----------- | ------------------------------------------------------------------- |
| (stream ID) | stream ID of a publisher outside of a room with a matching password |

## Details

`&include`, which is like [`&view`](../view-parameters/view.md), except it's for including streams that do not exist in the room you are in, assuming those streams are not in another room and have matching passwords. So, useful for adding basic push-streams that you might want to be in multiple rooms at the same time, but not actually be locked to any room. ([`&view`](../view-parameters/view.md), conversely, is pretty exclusive; that or nothing.)

## Related

{% content-ref url="../view-parameters/view.md" %}
[view.md](../view-parameters/view.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/and-exclude.md" %}
[and-exclude.md](../view-parameters/and-exclude.md)
{% endcontent-ref %}




---
description: >-
  Shows the guest a return feed of the current mixer layout when using the Mixer
  App
---

# \&layout

Viewer-Side Option! ([`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md))

## Details

Adding `&layout` to a guest link shows the guest a return feed of the current mixer layout when using the [Mixer App](../../steves-helper-apps/mixer-app.md).

## Related

{% content-ref url="../../steves-helper-apps/mixer-app.md" %}
[mixer-app.md](../../steves-helper-apps/mixer-app.md)
{% endcontent-ref %}

{% content-ref url="../director-parameters/and-layouts.md" %}
[and-layouts.md](../director-parameters/and-layouts.md)
{% endcontent-ref %}




---
description: >-
  Will force a the VDO.Ninja's mixer output keep the mixed render contained to a
  specific aspect-ratio, regardless of the browser's window size
---

# \&locked

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md))

## Options

Example: `&locked=portrait`

<table><thead><tr><th width="294">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>landscape</code> | (no value given)</td><td>16:9 aspect ratio</td></tr><tr><td><code>portrait</code></td><td>9:16 aspect ratio</td></tr><tr><td><code>square</code></td><td>1:1 aspect ratio</td></tr><tr><td><code>1.77777</code></td><td>aspect ratio</td></tr></tbody></table>

## Details

`&locked` will force a the VDO.Ninja's mixer output keep the mixed render contained to a specific aspect-ratio, regardless of the browser's window size. (as seen in photo)\
.png>).png>)

You'll get black bars (or whatever the background color is) as padding on the sides to force the inner video elements into the desired aspect ratio

When using `&locked`, the default aspect ratio is 16:9, but you can pass a floating point value for different aspect ratios, or use `landscape` (instead of `1.77777`) / `portrait` / `square` as presets if needed.

Padding is centered, so the rendered video will be in the center of the screen. (tho using [`&widget`](../settings-parameters/and-widget.md) mode might break things though).

This `&locked` option is added to the [Mixer App](../../steves-helper-apps/mixer-app.md)'s WHIP/**Twitch publishing output option**, so regardless of window size, you'll get a 16:9 video render.

## Related

{% content-ref url="../design-parameters/and-structure.md" %}
[and-structure.md](../design-parameters/and-structure.md)
{% endcontent-ref %}

{% content-ref url="../video-parameters/and-aspectratio.md" %}
[and-aspectratio.md](../video-parameters/and-aspectratio.md)
{% endcontent-ref %}




---
description: Does a few things when it detects motion in a video
---

# \&motiondetection

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&motionswitch`

## Options

Example: `&motiondetection=40`

<table><thead><tr><th width="294">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code> to <code>64</code></td><td>sensitivity of the motion detection trigger as a value</td></tr><tr><td>(no value given)</td><td>sensitivity <code>15</code> of the motion detection trigger</td></tr></tbody></table>

## Details

`&motiondetection` does a few things when it detects motion in a video (viewer-side).

It will feature highlight the specific video where movement is detected, if more than one video is included in the mix. Using a custom [`&layout`](and-layout.md) will disable this feature though, and use the layout instead.

It will also trigger an IFrame API event, which might be useful if you want to use VDO.Ninja as a security camera; you could script things to auto-record the video or log data events.

It will also switch to itself in OBS as a scene, which might be how this will be mainly used. (you need to have the OBS browser source's page permission set to high to allow this to actually work)

You can adjust the sensitivity of the motion detection trigger as a value; the default I think is 15, but it can be between 1 and 64 I think.

## Related

{% content-ref url="../view-parameters/activespeaker.md" %}
[activespeaker.md](../view-parameters/activespeaker.md)
{% endcontent-ref %}




---
description: Lets you specify a poster image for videos that have not yet started playing
---

# \&poster

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&poster=./media/bg_sample.webp`

| Value         | Description                                                    |
| ------------- | -------------------------------------------------------------- |
| (encoded URL) | takes an encoded URL, pointing to a CORS-accessible image file |

## Details

`&poster` lets you specify a poster image for videos that have not yet started playing (using the built-in HTML poster attribute). This flag takes an encoded URL, pointing to a CORS-accessible image file.

Example of the command:

```
https://vdo.ninja/?view=YbFmisR&poster=./media/bg_sample.webp&hideplaybutton
```

## Related

{% content-ref url="and-hideplaybutton.md" %}
[and-hideplaybutton.md](and-hideplaybutton.md)
{% endcontent-ref %}




# &scenelinkcodec

#### **Description**

Appends a codec parameter to scene invite links generated by the director, allowing codec preference to be set for all guests joining through those links.

#### **Director-Side Option**

This parameter is primarily designed for iframe API usage to control codec selection for scene participants.

#### **Usage**

* **`&scenelinkcodec=h264`** - Adds `&codec=h264` to scene links
* **`&scenelinkcodec=vp8`** - Adds `&codec=vp8` to scene links
* **`&scenelinkcodec=vp9`** - Adds `&codec=vp9` to scene links
* **`&scenelinkcodec=av1`** - Adds `&codec=av1` to scene links

#### **Examples**

```
https://vdo.ninja/?room=roomname&director&scenelinkcodec=h264
https://vdo.ninja/?room=roomname&director&scenelinkcodec=vp9
```

#### **Details**

* Automatically appends `&codec=` parameter to generated scene links
* Affects all scene invite links created by the director
* Codec name is automatically converted to lowercase
* Intended primarily for iframe API implementations
* Does not affect existing connections, only new invites

#### **Technical Implementation**

When set, the parameter:
1. Stores the codec preference as `&codec=value`
2. Appends this to any scene invite URLs generated
3. Ensures consistent codec usage across all scene participants

#### **Use Cases**

* Forcing specific codec for compatibility reasons
* Ensuring consistent codec across all participants
* Automated scene management via iframe API
* Testing different codecs across sessions

#### **Notes**

* This is a niche parameter mainly for advanced/API usage
* The specified codec must be supported by participants' browsers
* Final codec negotiation still depends on browser capabilities
* Consider bandwidth and CPU implications of codec choice

#### **Related Parameters**

* [`&codec`](../view-parameters/codec.md) - Sets codec for individual connections
* [`&scene`](../view-parameters/scene.md) - Specifies scene to view
* [`&director`](../../viewers-settings/director.md) - Enables director mode
* [`&preferaudiocodec`](../audio-parameters/and-preferaudiocodec.md) - Sets preferred audio codec




---
description: Similar to &scene, but tells the system to be a solo-link
---

# \&solo

Viewer-Side Option! ([`&room`](../../general-settings/room.md))

## Details

`&solo` is used to bring a solo-link of a guest in a room into OBS Studio.\
[https://vdo.ninja/?view=streamid1\&room=roomname\&solo](https://vdo.ninja/?view=streamid1\&room=roomname\&solo)

This tells the system to only view `streamid1` in the specified room. `&solo` and [`&scene`](../view-parameters/scene.md) also tells the system not to be a publisher, but a viewer.

This parameter behaves just as [`&scene`](../view-parameters/scene.md). The only difference is, that the system does not apply custom 'layouts' to `&solo` links.

Links updates in the director's room from Version 22 onwards.

 (3) (1) (1).png>)

### Alternative using \&optimize=0&#x20;

If using a normal manual scene, such as \&scene=3, you can add [\&optimize=0](and-solo.md#alternative-using-and-optimize-0) to the scene URL to enable a mode that is similar to \&solo. It's one of a few different ways to have permanent generic scene links that you can place specific guests into with varying stream IDs. There's also slots, however \&optimize=0 is tweaked for low CPU and network usage, at the cost of a slight added delay in adding a guest to the scene

## Related

{% content-ref url="../video-bitrate-parameters/optimize.md" %}
[optimize.md](../video-bitrate-parameters/optimize.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/scene.md" %}
[scene.md](../view-parameters/scene.md)
{% endcontent-ref %}




---
description: >-
  Enables viewing a specific slot from a scene link when the director is using
  &slotmode
---

# \&viewslot

The `&viewslot` parameter enables viewing a specific slot from a scene link when the director is using `&slotmode`. This creates a single-video view of whatever is assigned to that slot number.

## Usage

Basic syntax for viewing a specific slot:\
\
`/?scene&viewslot=1&room=ROOMNAME`

## Key Features

The `&viewslot` parameter provides single-video viewing of slot assignments with these characteristics:

* Only shows content from the specified slot number
* Dynamically updates when directors change slot assignments
* Optimizes performance by only loading the visible video stream
* Disables layouts and auto-mixing functionality
* Requires director to be using `&slotmode`

## Performance Optimization

By default, only the visible video stream is connected to reduce CPU and network load. Two parameters control this behavior:

```
&nohiddensceneoptimization    # Prevents optimization of hidden elements
&hiddenscenebitrate=VALUE     # Sets custom bitrate for hidden videos (default: 0)
```

## Related Parameters

#### Slot Assignment (`&slot`)

Guests can specify their preferred slot assignment:

```
&slot=N    # N is the desired slot number
```

)

### Fixed Slot Count (`&slots`)

Forces a specific number of slots in the auto-mixer:

```
&slots=N    # N is the desired number of slots
```

### Slot Mode (`&slotmode`)

Director parameter enabling slot assignment functionality:

```
&slotmode    # Enables slot management for directors
```




---
description: Shows only the last added video to a scene
---

# \&scenetype

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md))

## Aliases

* `&type`

## Options

Example: `&scenetype=2`

<table><thead><tr><th width="200">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code></td><td>just shows the last guest that was added in the scene, but doesn't mute the previous guests</td></tr><tr><td><code>2</code></td><td>just shows the last guest that was added in the scene</td></tr><tr><td><code>3</code></td><td>the general idea is it will only show the video that is in a particular ordered position (default, position = 1), rather than all the videos in the scene</td></tr></tbody></table>

## Details

You can change the behaviour of scenes a bit with this parameter.

`&scenetype` can be set to `1` or `2`, which overrides the default scene state.

Scene state of 1 and 2 will only show the last video added to a group scene. `&scenetype=2` will mute the other videos, while `&scenetype=1` will not mute previously added videos.

`&scenetype=3` - Usage is like this: `&scene&room=roomname&scenetype=3&order=1` , where [`&order=N`](../../source-settings/order.md) is optional. This feature isn't set in stone yet, but the general idea is it will only show the video that is in a particular ordered position (default, position = 1), rather than all the videos in the scene. When someone leaves, the spots are recalculated. The order that the positions are based on is calculated via alphanumeric sorting of connection IDs, though I wish to improve this to be probably sync with the director's order. Anyways, this feature was a result of a user request.

This URL parameter option is a bit of a hack currently and may be replaced in the future.

This parameter is added to scene view links.

## Related

{% content-ref url="../view-parameters/scene.md" %}
[scene.md](../view-parameters/scene.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/order.md" %}
[order.md](../../source-settings/order.md)
{% endcontent-ref %}




---
description: Options to specify push links and guest invite links for mobile phones
---

# Mobile Parameters

## Source side options

All these options are for push links and guest invite links in a room ([`&push`](../../source-settings/push.md) / [`&room`](../../general-settings/room.md))

<table><thead><tr><th width="228">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-facing.md"><code>&#x26;facing</code></a></td><td>Lets you specify either the front or rear facing camera as the default camera</td></tr><tr><td><a href="and-forcelandscape.md"><code>&#x26;forcelandscape</code></a></td><td>Forces the video output to landscape mode, regardless of how the phone is rotated</td></tr><tr><td><a href="and-forceportrait.md"><code>&#x26;forceportrait</code></a></td><td>Forces the video output to portrait mode, regardless of how the phone is rotated</td></tr><tr><td><a href="and-forceios.md"><code>&#x26;forceios</code></a></td><td>Forces iOS devices to publish video to this room</td></tr><tr><td><a href="and-notios.md"><code>&#x26;notios</code></a></td><td>Just tells the system that its not an iOS device, or iPad, even if it is</td></tr><tr><td><a href="../upcoming-parameters/and-flagship.md"><code>&#x26;flagship</code></a></td><td>Will optimize the mobile experience for more capable smartphones</td></tr><tr><td><a href="../upcoming-parameters/and-mobile.md"><code>&#x26;mobile</code></a></td><td>Optimizes a guest/push link for a mobile device to help reduce CPU issues</td></tr><tr><td><a href="../upcoming-parameters/and-notmobile.md"><code>&#x26;notmobile</code></a></td><td>Optimizes a guest/push link for a mobile device to improve video quality</td></tr><tr><td><a href="and-app.md"><code>&#x26;app</code></a></td><td>Loads the site into an "app mode" and allows you to load a new URL via the website itself</td></tr></tbody></table>




---
description: >-
  Loads the site into an "app mode" and allows you to load a new URL via the
  website itself
---

# \&app

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

`&app` loads the site into an "**app mode**" and allows you to load a new URL via the website itself.

This parameter is enabled in the mobile native app's new website-mode option by default (the screen share option is also hidden).

 (8).png>)




---
description: Lets you specify either the front or rear facing camera as the default camera
---

# \&facing

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&facing=rear`

<table><thead><tr><th width="305">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>rear</code> | <code>environment</code> | <code>back</code></td><td>rear-facing camera</td></tr><tr><td><code>front</code> | <code>user</code></td><td>front-facing camera</td></tr></tbody></table>

## Details

The `&facing` setting lets you specify either the front or rear facing camera as the default camera. Passing one of `rear`, `environment`, `back`, `front`, and `user` are required to specify whether to select back or front.\
\
Example usage:[`https://vdo.ninja/?webcam&facing=rear`](https://vdo.ninja/?webcam\&facing=rear)\
\
`&facing` takes priority over [`&videodevice`](../../source-settings/videodevice.md), but it will fail to [`&videodevice`](../../source-settings/videodevice.md) or the default behaviour if the rear/front camera can't be selected automatically. If there are multiple rear or front cameras, it will use the first one. [`&videodevice=0`](../../source-settings/videodevice.md) will disable the video outright.

.png>)

## Related

{% content-ref url="and-forcelandscape.md" %}
[and-forcelandscape.md](and-forcelandscape.md)
{% endcontent-ref %}

{% content-ref url="and-forceportrait.md" %}
[and-forceportrait.md](and-forceportrait.md)
{% endcontent-ref %}




---
description: Forces iOS devices to publish video to this room
---

# \&forceios

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

By default, iOS devices do not publish video to other guests in a group room.

{% hint style="danger" %}
iOS devices can publish **THREE (3)** video streams at any one time, before things explode.
{% endhint %}

## Related

{% content-ref url="and-notios.md" %}
[and-notios.md](and-notios.md)
{% endcontent-ref %}




---
description: >-
  Forces the video output to landscape mode, regardless of how the phone is
  rotated
---

# \&forcelandscape

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&forcedlandscape`
* `&fl`

## Details

Forces the video output to landscape mode (16:9), regardless of how the phone is rotated.

You add this flag to the sender's side, and it applies to the sender and the viewers of that video stream. There is a short sub-second delay that it takes to counter-act any system-flipping. It can be used in conjunction with [`&rotate`](../design-parameters/and-rotate.md), if you need to do a 180 or something also.

## Related

{% content-ref url="and-forceportrait.md" %}
[and-forceportrait.md](and-forceportrait.md)
{% endcontent-ref %}

{% content-ref url="../mixer-scene-parameters/and-forceviewerlandscape.md" %}
[and-forceviewerlandscape.md](../mixer-scene-parameters/and-forceviewerlandscape.md)
{% endcontent-ref %}




---
description: >-
  Forces the video output to portrait mode, regardless of how the phone is
  rotated
---

# \&forceportrait

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&forcedportrait`
* `&fp`

## Details

Forces the video output to portrait mode (9:16), regardless of how the phone is rotated.

You add this flag to the sender's side, and it applies to the sender and the viewers of that video stream. There is a short sub-second delay that it takes to counter-act any system-flipping. It can be used in conjunction with [`&rotate`](../design-parameters/and-rotate.md), if you need to do a 180 or something also.

## Related

{% content-ref url="and-forcelandscape.md" %}
[and-forcelandscape.md](and-forcelandscape.md)
{% endcontent-ref %}




---
description: Just tells the system that its not an iOS device, or iPad, even if it is
---

# \&notios

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

`&notios`, as in "not iOS", just tells the system that it's not an iOS device, or iPad, even if it is. This might change the behavior of the phone in certain ways, mainly for the purposes of debugging.

## Related

{% content-ref url="and-forceios.md" %}
[and-forceios.md](and-forceios.md)
{% endcontent-ref %}




---
description: Recently added to VDO.Ninja
---

# New Parameters in Version 24

These parameters are all on production in [v24](../releases/v24.md) of VDO.Ninja

<table><thead><tr><th width="316">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="design-parameters/and-pipall-alpha.md"><code>&#x26;pipall</code></a></td><td>New floating picture in picture mode, so you can pop out the entire video mix as a pinned window overlay</td></tr><tr><td><a href="design-parameters/and-pipme-alpha.md"><code>&#x26;pipme</code></a></td><td>Will cause your self-video preview window to pop out into its own picture in picture</td></tr><tr><td><a href="design-parameters/and-nomirror-alpha.md"><code>&#x26;nomirror</code></a></td><td>Disables the default mirror state of the video preview for a guest</td></tr><tr><td><a href="setup-parameters/and-hangupmessage-alpha.md"><code>&#x26;hangupmessage</code></a></td><td>Option for a custom hang-up message</td></tr><tr><td><a href="setup-parameters/and-humb64-alpha.md"><code>&#x26;humb64</code></a></td><td>The same as <a href="setup-parameters/and-hangupmessage-alpha.md"><code>&#x26;hangupmessage</code></a>, except this takes an input as a base64 encoded string</td></tr><tr><td><a href="setup-parameters/and-welcomeb64-alpha.md"><code>&#x26;welcomeb64</code></a></td><td>The same as <a href="../newly-added-parameters/and-welcome.md"><code>&#x26;welcome</code></a>, except this takes an input as a base64 encoded string</td></tr><tr><td><a href="whip-parameters/and-whipoutscale-alpha.md"><code>&#x26;whipoutscale</code></a></td><td>Scales down the WHIP video output via the URL</td></tr><tr><td><a href="whip-parameters/and-whipoutscreensharecodec-alpha.md"><code>&#x26;whipoutscreensharecodec</code></a></td><td>Option to change codec of the WHIP while screen-sharing</td></tr><tr><td><a href="whip-parameters/and-whipoutscreensharebitrate-alpha.md"><code>&#x26;whipoutscreensharebitrate</code></a></td><td>Option to change outbound screen-share video bitrate of WHIP</td></tr><tr><td><a href="whip-parameters/and-cftoken-alpha.md"><code>&#x26;cftoken</code></a></td><td>Accepts the special token without needing to specify the cloudflare.vdo.ninja part if using <a href="whip-parameters/and-whipout.md"><code>&#x26;whipout</code></a> instead</td></tr><tr><td><a href="settings-parameters/and-clock24-alpha.md"><code>&#x26;clock24</code></a></td><td>The same as <a href="settings-parameters/and-clock.md"><code>&#x26;clock</code></a> option, except it uses 24-hour time for the display</td></tr><tr><td><a href="mixer-scene-parameters/and-motiondetection-alpha.md"><code>&#x26;motiondetection</code></a></td><td>Does a few things when it detects motion in a video</td></tr><tr><td><a href="mixer-scene-parameters/and-forceviewerlandscape.md"><code>&#x26;forceviewerlandscape</code></a></td><td>Keeps all incoming videos oriented (rotated) so that the aspect ratio is always above 1</td></tr><tr><td><a href="guest-queuing-parameters/and-screen-alpha.md"><code>&#x26;screen</code></a></td><td>Replaces the way <a href="../general-settings/queue.md"><code>&#x26;queue</code></a> worked before, where the guest can see/hear the director, but not other guests, until activated</td></tr><tr><td><a href="guest-queuing-parameters/and-hold-alpha.md"><code>&#x26;hold</code></a></td><td>Like <a href="../general-settings/queue.md"><code>&#x26;queue</code></a>, except the guest gets a message telling them they need to wait until approved by the director</td></tr><tr><td><a href="guest-queuing-parameters/and-holdwithvideo-alpha.md"><code>&#x26;holdwithvideo</code></a></td><td>Just like <a href="guest-queuing-parameters/and-hold-alpha.md"><code>&#x26;hold</code></a>, except the director does see the guest's video and audio before the guest is activated</td></tr><tr><td><a href="settings-parameters/and-nocaptionlabels.md"><code>&#x26;nocaptionlabels</code></a></td><td>Disables showing the names when using the <a href="settings-parameters/and-closedcaptions.md"><code>&#x26;closedcaptions</code></a> feature</td></tr><tr><td><a href="video-parameters/and-largepreview.md"><code>&#x26;largepreview</code></a></td><td>Will disable the mini-preview functionality</td></tr><tr><td><a href="video-parameters/and-nodirectorvideo.md"><code>&#x26;nodirectorvideo</code></a></td><td>Disables all video playback from room directors</td></tr><tr><td><a href="audio-parameters/and-nodirectoraudio.md"><code>&#x26;nodirectoraudio</code></a></td><td>Disables all audio playback from room directors</td></tr><tr><td><a href="settings-parameters/and-retransmit.md"><code>&#x26;retransmit</code></a></td><td>Will relay the incoming 'chunked' media stream to others connected to you, without transcoding</td></tr><tr><td><a href="recording-parameters/and-recordmotion.md"><code>&#x26;recordmotion</code></a></td><td>Takes a video snapshot and saves it to disk whenever there is motion detected in a video</td></tr><tr><td><a href="whip-parameters/and-svc.md"><code>&#x26;svc</code></a></td><td>Useful for publishing to WHIP broadcast servers that support scalable video modes</td></tr><tr><td><a href="setup-parameters/and-e2ee.md"><code>e2ee</code></a></td><td>Support for something called "end to end encryption" using "insertable streams"</td></tr><tr><td><a href="camera-parameters/and-whitebalance.md"><code>&#x26;whitebalance</code></a></td><td>Lets you manually pre-set the white balance of the camera/webcam</td></tr><tr><td><a href="camera-parameters/and-exposure.md"><code>&#x26;exposure</code></a></td><td>Lets you manually pre-set the exposure of the camera/webcam</td></tr><tr><td><a href="camera-parameters/and-saturation.md"><code>&#x26;saturation</code></a></td><td>Lets you manually pre-set the saturation of the camera/webcam</td></tr><tr><td><a href="camera-parameters/and-sharpness.md"><code>&#x26;sharpness</code></a></td><td>Lets you manually pre-set the sharpness of the camera/webcam</td></tr><tr><td><a href="camera-parameters/and-contrast.md"><code>&#x26;contrast</code></a></td><td>Lets you manually pre-set the contrast of the camera/webcam</td></tr><tr><td><a href="camera-parameters/and-brightness.md"><code>&#x26;brightness</code></a></td><td>Lets you manually pre-set the brightness of the camera/webcam</td></tr><tr><td><a href="buttons-and-control-bar-parameters/and-hands-1.md"><code>&#x26;forcecontrols</code></a></td><td>Will try to keep the video controls visible, even if your mouse isn't hovering over the video</td></tr></tbody></table>




# &chunkedbuffer

**Also known as:** `&sendingbuffer`

#### **Description**

Sets the buffer size in milliseconds for chunked media transmission mode, controlling latency vs reliability trade-off.

#### **Sender-Side Option**

This parameter configures the buffering behavior when using chunked transmission mode for improved reliability.

#### **Usage**

* **`&chunkedbuffer=5000`** - 5 second buffer (default)
* **`&chunkedbuffer=2000`** - 2 second buffer (lower latency)
* **`&chunkedbuffer=10000`** - 10 second buffer (more reliable)
* **`&sendingbuffer=3000`** - Alias usage

#### **Examples**

```
https://vdo.ninja/?push=streamID&chunked&chunkedbuffer=3000
https://vdo.ninja/?push=streamID&chunked&sendingbuffer=5000
https://vdo.ninja/?room=roomname&chunked&chunkedbuffer=2000
```

#### **Details**

* Only applies when using [`&chunked`](and-chunked.md) mode
* Value in milliseconds (default: 5000ms)
* Controls how much data is buffered before sending
* Higher values improve reliability on poor connections
* Lower values reduce latency but may cause issues

#### **Buffer Size Guidelines**

* **1000-2000ms**: Low latency, good networks
* **3000-5000ms**: Balanced (default range)
* **5000-10000ms**: Poor networks, high reliability
* **10000ms+**: Extreme conditions

#### **How It Works**

1. Media is encoded into chunks
2. Chunks are buffered for specified duration
3. Buffer allows for retransmission if needed
4. Larger buffer = more retry opportunities

#### **Trade-offs**

**Small Buffer (1-2 seconds):**
- ✅ Lower latency
- ✅ More real-time
- ❌ Less reliable on poor networks
- ❌ May drop frames

**Large Buffer (5-10 seconds):**
- ✅ Very reliable
- ✅ Handles packet loss well
- ❌ Higher latency
- ❌ Less real-time interaction

#### **Use Cases**

* Streaming over cellular networks
* International broadcasts
* Unreliable internet connections
* Recording important content
* One-way broadcasts (higher buffer acceptable)

#### **Notes**

* Requires [`&chunked`](and-chunked.md) to be enabled
* Affects sender-side behavior only
* Memory usage increases with buffer size
* Consider your use case when setting

#### **Related Parameters**

* [`&chunked`](and-chunked.md) - Enables chunked transmission mode
* [`&buffer`](../view-parameters/buffer.md) - Viewer-side buffer control
* [`&nochunk`](../settings-parameters/and-nochunked.md) - Disables chunked mode
* [`&retransmit`](../settings-parameters/and-retransmit.md) - Relay chunked streams




---
description: Shows the video control bar
---

# \&videocontrols

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&controls`

## Options

Example: `&videocontrols=false`

| Value                   | Description                 |
| ----------------------- | --------------------------- |
| (no value given)        | Shows the video control bar |
| `0` \| `false` \| `off` | Hides the video control bar |

## Details

`&videocontrols` will show the video control bar (provides access to full screen on mobile). You can also show the control bar with `Right-Click` -> `Show control bar`.

{% hint style="warning" %}
This is not the same control bar as the user control bar. Also, be sure to not accidentally unmute yourself -- echo feedback galore.
{% endhint %}

 (1).png>)

## Related

{% content-ref url="../buttons-and-control-bar-parameters/and-hands-1.md" %}
[and-hands-1.md](../buttons-and-control-bar-parameters/and-hands-1.md)
{% endcontent-ref %}

{% content-ref url="../settings-parameters/and-nocontrols.md" %}
[and-nocontrols.md](../settings-parameters/and-nocontrols.md)
{% endcontent-ref %}

{% content-ref url="../../parameters-only-on-beta/and-autohide.md" %}
[and-autohide.md](../../parameters-only-on-beta/and-autohide.md)
{% endcontent-ref %}




---
description: >-
  You can add a custom image which shows up while waiting for the &scene or
  &view link
---

# \&waitimage

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&view`](../view-parameters/view.md))

## Options

Example: `&waitimage=https%3A%2F%2Fvdo.ninja%2Fmedia%2Flogo_cropped.png`

| Value         | Description              |
| ------------- | ------------------------ |
| (encoded URL) | Specifies a custom image |

## Details

This is for when waiting for the [`&scene`](../view-parameters/scene.md) or [`&view`](../view-parameters/view.md) link to load. You can add a custom image which shows up while waiting for the [`&scene`](../view-parameters/scene.md) or [`&view`](../view-parameters/view.md) link.

Example:\
[`https://vdo.ninja/?view=streamid&waitmessage=hello&waittimeout=0&waitimage=https%3A%2F%2Fvdo.ninja%2Fmedia%2Flogo_cropped.png`](https://vdo.ninja/?view=streamid\&waitmessage=hello\&waittimeout=0\&waitimage=https%3A%2F%2Fvdo.ninja%2Fmedia%2Flogo\_cropped.png)

It fits to the screen, and [`&cover`](../view-parameters/cover.md) will have it 'cover' the screen.

When using `&waitimage`, the specified 'waiting to connect' image will appear after all connections end.

It overrides [`&cleanoutput`](../design-parameters/cleanoutput.md).

You can encode the URL here:\
[https://www.urlencoder.org/](https://www.urlencoder.org/)

## Related

{% content-ref url="and-waitmessage.md" %}
[and-waitmessage.md](and-waitmessage.md)
{% endcontent-ref %}

{% content-ref url="and-waittimeout.md" %}
[and-waittimeout.md](and-waittimeout.md)
{% endcontent-ref %}

{% content-ref url="../design-parameters/and-bgimage.md" %}
[and-bgimage.md](../design-parameters/and-bgimage.md)
{% endcontent-ref %}

{% content-ref url="../design-parameters/and-background.md" %}
[and-background.md](../design-parameters/and-background.md)
{% endcontent-ref %}




---
description: >-
  You can add a custom message which shows up while waiting for the &scene or
  &view link
---

# \&waitmessage

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&view`](../view-parameters/view.md))

## Options

Example: `&waitmessage=hello`

| Value    | Description         |
| -------- | ------------------- |
| (string) | Specifies a message |

## Details

This is for when waiting for the [`&scene`](../view-parameters/scene.md) or [`&view`](../view-parameters/view.md) link to load. You can add a custom message which shows up while waiting for the [`&scene`](../view-parameters/scene.md) or [`&view`](../view-parameters/view.md) link.

Example:\
[`https://vdo.ninja/?view=streamid&waitmessage=hello&waittimeout=0&waitimage=https%3A%2F%2Fvdo.ninja%2Fmedia%2Flogo_cropped.png`](https://vdo.ninja/?view=streamid\&waitmessage=hello\&waittimeout=0\&waitimage=https%3A%2F%2Fvdo.ninja%2Fmedia%2Flogo\_cropped.png)

It overrides [`&cleanoutput`](../design-parameters/cleanoutput.md).

## Related

{% content-ref url="and-waitimage.md" %}
[and-waitimage.md](and-waitimage.md)
{% endcontent-ref %}

{% content-ref url="and-waittimeout.md" %}
[and-waittimeout.md](and-waittimeout.md)
{% endcontent-ref %}




---
description: >-
  Specifies a delay for &waitimage and &waitmessage while waiting for the &scene
  or &view link
---

# \&waittimeout

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&view`](../view-parameters/view.md))

## Options

Example: `&waittimeout=3000`

| Value           | Description |
| --------------- | ----------- |
| (integer value) | Delay in ms |

## Details

This is for when waiting for the [`&scene`](../view-parameters/scene.md) or [`&view`](../view-parameters/view.md) link to load. It specifies a delay for [`&waitimage`](and-waitimage.md) and [`&waitmessage`](and-waitmessage.md) while waiting for the [`&scene`](../view-parameters/scene.md) or [`&view`](../view-parameters/view.md) link.

Example:\
[`https://vdo.ninja/?view=streamid&waitmessage=hello&waittimeout=0&waitimage=https%3A%2F%2Fvdo.ninja%2Fmedia%2Flogo_cropped.png`](https://vdo.ninja/?view=streamid\&waitmessage=hello\&waittimeout=0\&waitimage=https%3A%2F%2Fvdo.ninja%2Fmedia%2Flogo\_cropped.png)

It overrides [`&cleanoutput`](../design-parameters/cleanoutput.md).

## Related

{% content-ref url="and-waitimage.md" %}
[and-waitimage.md](and-waitimage.md)
{% endcontent-ref %}

{% content-ref url="and-waitmessage.md" %}
[and-waitmessage.md](and-waitmessage.md)
{% endcontent-ref %}




---
description: >-
  If the total bitrate drops below the specified bitrate, the viewer will
  auto-hide the audio and video for that stream
---

# \&bitratecutoff

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&bitcut`

## Options

Example: `&bitratecutoff=500`

| Value            | Description                   |
| ---------------- | ----------------------------- |
| (no value given) | video cuts off under 300-kbps |
| (integer value)  | cut off bitrate in kbps       |

## Details

`&bitratecutoff` is a viewer-side parameter. If the total bitrate drops below the specified bitrate (default value of 300), the viewer will auto-hide the audio and video for that stream. It will un-hide once the average bitrate returns above 300-kbps.

{% hint style="info" %}
There is a 3-second delay in calculating the average bitrate. Won't work with viewers that are Firefox/Safari; just Chrome/Chromium, so OBS, vMix, Electron Capture, Chrome. This is because Firefox/Safari lack the stats in VDO.Ninja needed to trigger this.
{% endhint %}

When using `&bitratecutoff` on a room scene, it won't trigger due to a director being in the room with no video, unless they are using [`&showdirector`](../../viewers-settings/and-showdirector.md).

## Related

{% content-ref url="../settings-parameters/and-cutscene.md" %}
[and-cutscene.md](../settings-parameters/and-cutscene.md)
{% endcontent-ref %}

{% content-ref url="and-statsinterval.md" %}
[and-statsinterval.md](and-statsinterval.md)
{% endcontent-ref %}




---
description: >-
  Lets you change the default stats update interval from 3-seconds to something
  else
---

# \&statsinterval

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&statsinterval=1500`

| Value            | Description                     |
| ---------------- | ------------------------------- |
| (no value given) | stats update interval = 3000-ms |
| (integer value)  | stats update interval in ms     |

## Details

`&statsinterval` lets you change the default stats update interval from 3-seconds to something else. Changing it to 1-second or 10-seconds might suit your needs better when using [`&bitratecutoff`](and-bitratecutoff.md), or if you just want frequent updates. Changing the stats interval will impact the auto-keyframe fix feature, potentially breaking it, but this won't be an issue with OBS 27.2 and onwards.

## Related

{% content-ref url="and-bitratecutoff.md" %}
[and-bitratecutoff.md](and-bitratecutoff.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/and-stats.md" %}
[and-stats.md](../../general-settings/and-stats.md)
{% endcontent-ref %}




---
description: Options to specify recordings with VDO.Ninja
---

# Recording Parameters

<table><thead><tr><th width="247.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-record.md"><code>&#x26;record</code></a></td><td>Record functionality for guests</td></tr><tr><td><a href="and-autorecord.md"><code>&#x26;autorecord</code></a></td><td>Records the local video and the remote video(s) automatically on their initial load</td></tr><tr><td><a href="and-autorecordlocal.md"><code>&#x26;autorecordlocal</code></a></td><td>Records just the local video automatically on their initial load</td></tr><tr><td><a href="and-autorecordremote.md"><code>&#x26;autorecordremote</code></a></td><td>Records just the remote video(s) automatically on their initial load</td></tr><tr><td><a href="and-recordcodec.md"><code>&#x26;recordcodec</code></a></td><td>Lets you set the video recording codec</td></tr><tr><td><a href="and-pcm.md"><code>&#x26;pcm</code></a></td><td>PCM audio recordings</td></tr><tr><td><a href="and-recordmotion.md"><code>&#x26;recordmotion</code></a>*</td><td>Takes a video snapshot and saves it to disk whenever there is motion detected in a video</td></tr><tr><td><a href="../../newly-added-parameters/and-chunked.md"><code>&#x26;chunked</code></a></td><td>Does not use webRTC's video streaming protocols; rather it uses a custom-made protocol</td></tr></tbody></table>

\*NEW IN [VERSION 24](../../releases/v24.md)




---
description: >-
  Records the local video and the remote video(s) automatically on their initial
  load
---

# \&autorecord

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Options

Example: `&autorecord=1500`

<table><thead><tr><th width="187">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>0</code></td><td>No video recorded; audio tentatively recorded as 32bit PCM lossless.</td></tr><tr><td>(negative integer)</td><td>No video recorded; audio recorded as {integer} kbps OPUS file. eg: -120 - Audio only at 120 kbps.</td></tr><tr><td>(positive integer)</td><td>Recorded video bitrate in kbps.</td></tr></tbody></table>

## Details

`&autorecord` will record the local and remote videos automatically on their initial load. This applies to the director, guest, scenes, and whatever really.

You can stop/restart recordings as needed via the right-click menu per each video for now, until I can design a nicer UI for managing multi-recording state at least.

You can pass the default recording bitrate as a value to the parameter, like you might if using [`&record`](and-record.md).

### Update in [v23](../../releases/v23.md)

There are buttons in the room settings of the director to start/stop _all_ recordings; both remote/local.

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="and-record.md" %}
[and-record.md](and-record.md)
{% endcontent-ref %}

{% content-ref url="and-autorecordlocal.md" %}
[and-autorecordlocal.md](and-autorecordlocal.md)
{% endcontent-ref %}

{% content-ref url="and-autorecordremote.md" %}
[and-autorecordremote.md](and-autorecordremote.md)
{% endcontent-ref %}




---
description: Records just the local video automatically on their initial load
---

# \&autorecordlocal

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Options

Example: `&autorecordlocal=2000`

<table><thead><tr><th width="209">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>0</code></td><td>No video recorded; audio tentatively recorded as 32bit PCM lossless.</td></tr><tr><td>(negative integer)</td><td>No video recorded; audio recorded as {integer} kbps OPUS file. eg: -120 - Audio only at 120 kbps.</td></tr><tr><td>(positive integer)</td><td>Recorded video bitrate in kbps.</td></tr></tbody></table>

## Details

`&autorecordlocal` will record the local video automatically on their initial load. This applies to the director, guest, scenes, and whatever really.

You can stop/restart recordings as needed via the right-click menu per each video for now, until I can design a nicer UI for managing multi-recording state at least.

You can pass the default recording bitrate as a value to the parameter, like you might if using [`&record`](and-record.md).

### Update in [v23](../../releases/v23.md)

There are buttons in the room settings of the director to start/stop _all_ recordings; both remote/local.

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="and-record.md" %}
[and-record.md](and-record.md)
{% endcontent-ref %}

{% content-ref url="and-autorecord.md" %}
[and-autorecord.md](and-autorecord.md)
{% endcontent-ref %}

{% content-ref url="and-autorecordremote.md" %}
[and-autorecordremote.md](and-autorecordremote.md)
{% endcontent-ref %}




---
description: Records just the remote video(s) automatically on their initial load
---

# \&autorecordremote

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Options

Example: `&autorecordremote=1500`

<table><thead><tr><th width="190">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>0</code></td><td>No video recorded; audio tentatively recorded as 32bit PCM lossless.</td></tr><tr><td>(negative integer)</td><td>No video recorded; audio recorded as {integer} kbps OPUS file. Eg: <code>-120</code> - Audio only at 120 kbps.</td></tr><tr><td>(positive integer)</td><td>Recorded video bitrate in kbps.</td></tr></tbody></table>

## Details

`&autorecordremote` will record the remote video(s) automatically on their initial load. This applies to the director, guest, scenes, and whatever really.

You can stop/restart recordings as needed via the right-click menu per each video for now, until I can design a nicer UI for managing multi-recording state at least.

You can pass the default recording bitrate as a value to the parameter, like you might if using [`&record`](and-record.md).

### Update in [v23](../../releases/v23.md)

There are buttons in the room settings of the director to start/stop _all_ recordings; both remote/local.

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="and-record.md" %}
[and-record.md](and-record.md)
{% endcontent-ref %}

{% content-ref url="and-autorecord.md" %}
[and-autorecord.md](and-autorecord.md)
{% endcontent-ref %}

{% content-ref url="and-autorecordlocal.md" %}
[and-autorecordlocal.md](and-autorecordlocal.md)
{% endcontent-ref %}




---
description: PCM audio recordings
---

# \&pcm

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

Video recordings will be saved as Video + PCM audio format.

### Converting and playing back WebM-PCM

WebM is a universal container of sorts when used within a Chromium browser, but it doesn't always work well for VLC or popular video editors. FFmpeg can be used to convert to other formats though, including MP4 and WAV, typically without transcoding.

To make converting from WebM to other formats easier, a version of FFmpeg is hosted within VDO.Ninja for this. It can be located here at [https://vdo.ninja/convert](https://vdo.ninja/convert), with several of the most common conversion options ready to go, such as WebM-PCM to WAV-PCM.

Due to memory limits and other browser limitations, this FFmpeg tool can only process files under about 2-gigabytes in size. For larger files, you may need to download and use a desktop version of [FFmpeg](https://ffmpeg.org/download.html) instead.

FFmpeg command lines are provided if you choose to run FFmpeg yourself locally, but if that is still to complicated, you can grab [Handbrake ](https://handbrake.fr/)for free; it's a GUI-based option that is fairly accessible.

## Related

{% content-ref url="and-record.md" %}
[and-record.md](and-record.md)
{% endcontent-ref %}




---
description: Record functionality for guests
---

# \&record

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&record=1000`

<table><thead><tr><th width="195">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>0</code></td><td>No video recorded; audio tentatively recorded as 32bit PCM lossless</td></tr><tr><td>(negative integer)</td><td>No video recorded; audio recorded as {integer} kbps OPUS file. Eg: -120 - Audio only at 120 kbps</td></tr><tr><td>(positive integer)</td><td>Recorded video bitrate in kbps</td></tr><tr><td><code>false</code> | <code>off</code></td><td>Will disable the user from being able to record a video. Buttons for recording are hidden/deleted and the recording function is disabled when used; so the director won't even be able to trigger it remotely</td></tr></tbody></table>

## Details

### Recorded file properties

**`File format`**` ``- WebM.` &#x20;

**`File Codec:`**` ``H264 or VP8 for video; OPUS or PCM for audio.` &#x20;

Usually up to the browser.

Default bitrate will record at around 4000 kbps, but it will still prompt still for value if not set.

The Director of a room will be notified if a user is recording and they can start/stop the recording.\
The Director of a room can trigger the record function remotely, even if the \&record parameter has not been added.

The video/audio will be saved in real-time to the guest's local download folder.

Do not force-close the browser or turn off the computer while it is recording; you may lose the file or have a partial capture.

The recording should stop automatically when the guest hangs-ups manually. I try my best to do the same when the browser is closed, but it's best to still purposefully stop recording first.

It will automatically capture with stereo audio and echo cancellation off, if available.

You can use [https://isolated.vdo.ninja/convert](https://isolated.vdo.ninja/convert) to convert from WebM file formats to OPUS or WAV file formats, **without transcoding and without downloads**. [More about converting from WebM to MP4 or WAV here](and-record.md#converting-and-playing-back-webm).

### Recording as the director

When recording as the director, the button and option to record each guest is available by default. It's hidden behind Advanced controls. You have the option to record locally, to your own disk, or record remotely, directly to the remote guest's local storage.

When recording to the guest's local storage, quality should be near pristine, given as its not being sent via the Internet first. Recording locally, the video may have dynamic resolutions and varying quality, due to the low latency transmission. ([`&chunked`](../../newly-added-parameters/and-chunked.md)-mode excepted)

Anyone can also access the recording options via right-clicking a video. This option is available as of VDO.Ninja [v22](../../releases/v22.md).

 (1) (1).png>) (1).png>)

### Bitrate Thresholds

| Threshold      | Inbound Audio | Recorded audio |
| -------------- | ------------- | -------------- |
| 4000           | 128 kpbs      | 128 kpbs       |
| 2500           | 80 kbps       | 128 kpbs       |
| Less than 2500 | 32 kbps       | 32 kbps        |

### When using [`&chunked`](../../newly-added-parameters/and-chunked.md) mode

When the sender of a stream is using the `&chunked` mode, recording their video will save the inbound video directly to disk without transcoding. Not needing to transcode the saved video in the browser is only possible with the `&chunked` mode. Of course, you also don't have the option to increase the bitrate or change codecs when using this mode; at least not as the viewer.

The chunked mode (as of June 2022) is still a maturing feature. Please report any issues and provide feedback.

### Converting and playing back WebM

WebM is a universal container of sorts when used within a Chromium browser, but it doesn't always work well for VLC or popular video editors. FFmpeg can be used to convert to other formats though, including MP4 and WAV, typically without transcoding.

To make converting from WebM to other formats easier, a version of FFmpeg is hosted within VDO.Ninja for this. It can be located here at [https://vdo.ninja/convert](https://vdo.ninja/convert), with several of the most common conversion options ready to go, such as WebM-PCM to WAV-PCM.

Due to memory limits and other browser limitations, this FFmpeg tool can only process files under about 2-gigabytes in size. For larger files, you may need to download and use a desktop version of [FFmpeg](https://ffmpeg.org/download.html) instead.

FFmpeg command lines are provided if you choose to run FFmpeg yourself locally, but if that is still to complicated, you can grab [Handbrake ](https://handbrake.fr/)for free; it's a GUI-based option that is fairly accessible.

Lastly, sometimes a video recorded by VDO.Ninja will have a variable resolution or/and frame rate, which can cause problems with some video editors. For example, the quality might be stuck low, or it might freeze after a few seconds. In these cases, you may need to transcode the video to a fixed resolution and frame rate using FFmpeg (or Handbrake) first, before using.. Transcoding is very slow in the browser, so I'd recommend you download Handbrake or FFmpeg for this task.

{% embed url="https://vdo.ninja/convert" %}
FFmpeg in the browser; up to 4-gb file sizes
{% endembed %}

### Please note:

{% hint style="info" %}
When recording with PCM, ([`&pcm`](and-pcm.md)) the inbound audio bitrate will be at 256-kbps. (regardless of video bitrate)
{% endhint %}

{% hint style="warning" %}
* If recording with an Nvidia/AMD graphics card installed on your computer, ensure your drivers are up to date or try recording with VP8-codec instead. Hardware-encoding might reduce CPU load, but it can also result in discolored video if the driver is buggy.
* Safari browsers and iOS devices may struggle with media recording.
* Enabling Safari's _MediaRecorder_ under &#x45;_&#x78;perimental webKit Features_ may be needed. As well, users may be asked to download a file once the recording ends, for the webM media file to be saved correctly to disk.
{% endhint %}

## Related

{% content-ref url="and-recordcodec.md" %}
[and-recordcodec.md](and-recordcodec.md)
{% endcontent-ref %}

{% content-ref url="and-autorecord.md" %}
[and-autorecord.md](and-autorecord.md)
{% endcontent-ref %}

{% content-ref url="and-pcm.md" %}
[and-pcm.md](and-pcm.md)
{% endcontent-ref %}




---
description: Lets you set the video recording codec
---

# \&recordcodec

Sender-Side Option / Director Option! ([`&push`](../../source-settings/push.md), [`&director`](../../viewers-settings/director.md))

## Aliases

* `&rc`

## Options

Example: `&recordcodec=h264`

<table><thead><tr><th width="139">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>h264</code></td><td>request the h264 codec </td></tr><tr><td><code>vp8</code></td><td>request the VP8 codec </td></tr><tr><td><code>vp9</code></td><td>request the VP9 codec</td></tr><tr><td><code>av1</code></td><td>request the AV1 codec</td></tr></tbody></table>

## Details

Adding `&recordcodec` to a source or director link lets you set the video recording codec (saving to disk mode; aka [`&record`](and-record.md)). The container format is still WebM, and not all codecs are going to be supported, but things will fail back to vp8 if not supported. Main reason for this is because vp8 on chrome for android kinda stinks, so at least you have an option to tinker with things now.

As a guest or source side don't forget to add [`&record`](and-record.md) to the URL to get the record button.

## Related

{% content-ref url="and-record.md" %}
[and-record.md](and-record.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/codec.md" %}
[codec.md](../view-parameters/codec.md)
{% endcontent-ref %}

{% content-ref url="and-pcm.md" %}
[and-pcm.md](and-pcm.md)
{% endcontent-ref %}




---
description: >-
  Takes a video snapshot and saves it to disk whenever there is motion detected
  in a video
---

# \&recordmotion

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&motionrecord`

## Options

Example: `&recordmotion=15`

<table><thead><tr><th width="195">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer value)</td><td>will control the sensitivity of the motion capture</td></tr></tbody></table>

## Details

`&recordmotion` takes a video snapshot and saves it to disk as a PNG file whenever there is motion detected in a video.

* Auto saves (to download folder) one photo per second, max.
* It can take values, such as `&recordmotion=15`, which will control the sensitivity of the motion capture
* It's primarily designed for the sender-side, but I think it should work if a viewer also
* I don't think this will work within OBS, so Chrome/Chromium is recommended instead
* I guess the point of this is to allow for basic security camera operation, but also as a source of inspiration for other ideas
* File name of the saved file contains the timestamp




# &splitrecording

#### **Description**

Enables automatic splitting of browser-based recordings into multiple file segments to prevent data loss and enable incremental saving.

#### **Sender-Side Option**

When recording locally in the browser (using [`&record`](and-record.md)), this parameter splits the recording into multiple files at specified intervals.

#### **Usage**

* **`&splitrecording`** - Splits recordings every 5 minutes (default)
* **`&splitrecording=10`** - Splits recordings every 10 minutes
* **`&splitrecording=1`** - Splits recordings every 1 minute

#### **Examples**

```
https://vdo.ninja/?push=streamID&record&splitrecording
https://vdo.ninja/?push=streamID&record&splitrecording=15
```

#### **Details**

* Each file segment is approximately 30MB at 720p for 5 minutes of recording
* Files are saved with numbered suffixes (e.g., `recording.webm`, `recording.webm_1`, `recording.webm_2`)
* Only the first file contains the media header information
* Segments must be concatenated to create a playable video file
* If battery reaches 2% on mobile/laptop, recording automatically saves and starts a new segment

#### **File Concatenation**

To combine the segments into a single playable file:

**Windows Command Prompt:**
```bash
copy /b recording.webm + recording.webm_1 + recording.webm_2 output.webm
```

**FFmpeg (cross-platform):**
```bash
ffmpeg -i "concat:recording.webm|recording.webm_1|recording.webm_2" -c copy output.webm
```

#### **Notes**

* Helps prevent complete data loss if the browser crashes
* Enables cloud upload of recording chunks while still recording
* Minimum value is 1 minute
* Feature requires Chrome/Chromium-based browsers for battery detection

#### **Related Parameters**

* [`&record`](and-record.md) - Enables local recording
* [`&autorecord`](and-autorecord.md) - Automatically starts recording




---
description: Labels, audio filters, type, bitrate, quality etc.
---

# Screen-share Parameters

Screen-share Parameters are separated in [general options](./#general-options), [source side](./#source-side-options) (push) options and [viewer side](./#viewer-side-options) (view) options.

## General options

You can add them to both, source ([`&push`](../../source-settings/push.md)) and viewer ([`&view`](../view-parameters/view.md) or [`&scene`](../view-parameters/scene.md)) sides.

<table><thead><tr><th width="150">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../newly-added-parameters/and-screensharestereo.md"><code>&#x26;screensharestereo</code></a></td><td>Sets the audio mode for screen-shares to stereo and changes default audio settings to improve audio quality</td></tr></tbody></table>

## Source side options

You can add them to both, source ([`&push`](../../source-settings/push.md)) and viewer ([`&view`](../view-parameters/view.md) or [`&scene`](../view-parameters/scene.md)) sides.

<table><thead><tr><th width="150">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../source-settings/screenshare.md"><code>&#x26;screenshare</code></a></td><td>Disables camera-sharing as an option</td></tr><tr><td><a href="../../newly-added-parameters/and-screenshare2.md"><code>&#x26;screenshare2</code></a></td><td>Will show the "Share your Screen" button before asking the user to select screenshare options</td></tr><tr><td><a href="../../newly-added-parameters/and-screenshareaec.md"><code>&#x26;screenshareaec</code></a></td><td>Turns automatic echo-cancellation filter for screen-shares ON or OFF</td></tr><tr><td><a href="../../newly-added-parameters/and-screenshareautogain.md"><code>&#x26;screenshareautogain</code></a></td><td>Turns audio auto-normalization filter for screen-shares ON or OFF</td></tr><tr><td><a href="../../source-settings/cursor.md"><code>&#x26;screensharecursor</code></a></td><td>Attempts to show the mouse cursor on screen shares</td></tr><tr><td><a href="../../newly-added-parameters/and-screensharedenoise.md"><code>&#x26;screensharedenoise</code></a></td><td>Turns audio noise reduction filter for screen-shares ON or OFF</td></tr><tr><td><a href="../../source-settings/screensharefps.md"><code>&#x26;screensharefps</code></a></td><td>Set a target FPS for your screenshare (secondary stream)</td></tr><tr><td><a href="../../newly-added-parameters/and-screensharehide.md"><code>&#x26;screensharehide</code></a></td><td>Hides the local screen-share sub-window that appears when screen sharing in a room</td></tr><tr><td><a href="../../source-settings/screenshareid.md"><code>&#x26;screenshareid</code></a></td><td>Pre-sets the screenshare stream id for a screen share if its a secondary stream</td></tr><tr><td><a href="../../newly-added-parameters/and-screensharelabel.md"><code>&#x26;screensharelabel</code></a></td><td>The screen-share of the guest will have the same label as the guest</td></tr><tr><td><a href="../../source-settings/screensharequality.md"><code>&#x26;screensharequality</code></a></td><td>Set a custom screenshare quality</td></tr><tr><td><a href="and-screensharecontenthint.md"><code>&#x26;screensharecontenthint</code></a></td><td><code>=motion</code> prioritizes screen-share frame rate; <code>=detail</code> prioritizes screen-share resolution</td></tr><tr><td><a href="and-screenshareaspectratio.md"><code>&#x26;screenshareaspectrati</code></a></td><td>Changes the screen-share aspect ratio on the publisher side</td></tr><tr><td><a href="../../newly-added-parameters/and-screensharestereo.md"><code>&#x26;screensharestereo</code></a></td><td>Sets the audio mode for screen-shares to stereo and changes default audio settings to improve audio quality</td></tr><tr><td><a href="../../newly-added-parameters/and-screensharetype.md"><code>&#x26;screensharetype</code></a></td><td>Defines how webcam and screenshare of a guest in a room interacts which each other</td></tr><tr><td><a href="and-smallshare.md"><code>&#x26;smallshare</code></a></td><td>Makes the screen share behave like a webcam share</td></tr><tr><td><a href="../../newly-added-parameters/and-screensharevideoonly.md"><code>&#x26;screensharevideoonly</code></a></td><td>Lets you disable the option to select audio when screen sharing</td></tr><tr><td><a href="../settings-parameters/and-screensharebutton.md"><code>&#x26;screensharebutton</code></a></td><td>Forces the screen-share button to appear for guests</td></tr><tr><td><a href="and-suppresslocalaudio.md"><code>&#x26;suppresslocalaudio</code></a></td><td>Will disable local audio playback of a Chrome tab while screen-sharing it</td></tr><tr><td><a href="and-prefercurrenttab.md"><code>&#x26;prefercurrenttab</code></a></td><td>Will have the current tab as the default screen-share source</td></tr><tr><td><a href="and-selfbrowsersurface.md"><code>&#x26;selfbrowsersurface</code></a></td><td>Excludes the current tab as a screen-share source option</td></tr><tr><td><a href="and-systemaudio.md"><code>&#x26;systemaudio</code></a></td><td>Excludes the system-audio as an audio source when display sharing</td></tr><tr><td><a href="and-displaysurface.md"><code>&#x26;displaysurface</code></a></td><td>Will pre-select display-share, rather than tab-share, when screen-sharing</td></tr></tbody></table>

## **Viewer side options**

You have to add them to the viewer side ([`&view`](../view-parameters/view.md) or [`&scene`](../view-parameters/scene.md)).

<table><thead><tr><th width="150">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../newly-added-parameters/and-screensharebitrate.md"><code>&#x26;screensharebitrate</code></a></td><td>Lets you manually set the video bitrate for screen-shares</td></tr><tr><td><a href="and-sharperscreen.md"><code>&#x26;sharperscreen</code></a></td><td>Sets <a href="../view-parameters/scale.md"><code>&#x26;scale=100</code></a>, but only for screen-shares</td></tr><tr><td><a href="../../parameters-only-on-beta/and-sspaused.md"><code>&#x26;sspaused</code></a></td><td>Starts any screen-share paused</td></tr></tbody></table>




---
description: Will pre-select display-share, rather than tab-share, when screen-sharing
---

# \&displaysurface

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&displaysurface=monitor`

<table><thead><tr><th width="280">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>monitor</code></td><td>Will pre-select "display-share"</td></tr><tr><td><code>browser</code></td><td>Will pre-select "tab-share"</td></tr><tr><td><code>window</code></td><td>Will pre-select "window-share"</td></tr></tbody></table>

## Details

`&displaysurface` will pre-select "display-share", rather than tab-share, when screen-sharing. You can pass `monitor`, `browser`, or `window` as options to customize this though.

 (1) (3).png>)

For more details on these new features see here:\
[https://developer.chrome.com/docs/web-platform/screen-sharing-controls/](https://developer.chrome.com/docs/web-platform/screen-sharing-controls/)\
(Chrome/chromium-browsers only)

## Related

{% content-ref url="../../source-settings/screenshare.md" %}
[screenshare.md](../../source-settings/screenshare.md)
{% endcontent-ref %}




---
description: Will have the current tab as the default screen-share source
---

# \&prefercurrenttab

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

`&prefercurrenttab` will have the current tab as the default screen-share source.

For more details on these new features see here:\
[https://developer.chrome.com/docs/web-platform/screen-sharing-controls/](https://developer.chrome.com/docs/web-platform/screen-sharing-controls/)\
(Chrome/chromium-browsers only)

## Related

{% content-ref url="../../source-settings/screenshare.md" %}
[screenshare.md](../../source-settings/screenshare.md)
{% endcontent-ref %}




---
description: Changes the screen-share aspect ratio on the publisher side
---

# \&screenshareaspectratio

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&ssar`

## Options

Example: `&screenshareaspectratio=landscape`

<table><thead><tr><th width="192">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>overrides <a href="../video-parameters/and-aspectratio.md"><code>&#x26;aspectratio</code></a> and sets the screen-share to the default aspect ratio</td></tr><tr><td>(decimal number)</td><td>sets the screen-share aspect ratio</td></tr><tr><td><code>landscape</code></td><td>screen-share aspect ratio of 16:9 (1.777777)</td></tr><tr><td><code>portrait</code></td><td>screen-share aspect ratio of 9:16 (0.5625)</td></tr><tr><td><code>square</code></td><td>screen-share aspect ratio of 1:1 (1)</td></tr><tr><td><code>1.33333</code></td><td>screen-share aspect ratio of 4:3</td></tr></tbody></table>

## Details

`&screenshareaspectratio` sets the aspect ratio for screen-shares on the publisher side.

[`&aspectratio`](../video-parameters/and-aspectratio.md) works with screen-shares, so you can force crop an incoming screen-share to be a certain aspect ratio. If `&screenshareaspectratio` is used it will apply to just screen-shares. If `&screenshareaspectratio` does not have a value passed, it's assumed to be set as "default", which overrides [`&aspectratio`](../video-parameters/and-aspectratio.md) option, if used also.

## Related

{% content-ref url="../video-parameters/and-aspectratio.md" %}
[and-aspectratio.md](../video-parameters/and-aspectratio.md)
{% endcontent-ref %}




---
description: >-
  =motion prioritizes screen-share frame rate; =detail prioritizes screen-share
  resolution
---

# \&screensharecontenthint

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&sscontenthint`
* `&screensharecontenttype`
* `&sscontent`
* `&sshint`

## Options

Example: `&screensharecontenthint=detail`

<table><thead><tr><th width="177">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>detail</code></td><td>will prioritize <strong>screen-share resolution</strong> over frame rate</td></tr><tr><td><code>motion</code></td><td>will prioritize <strong>screen-share frame rate</strong> over resolution</td></tr></tbody></table>

#### Additional value options

Depending on browser and version, there may be additional values you can pass, such as `text`. Please see the following link for possible options that your browser may offer:

[https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/contentHint](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/contentHint)

## Details

`&screensharecontenthint` can customize how you want VDO.Ninja to balance screen-share resolution vs screen-share frame rate, specifically when bitrate or CPU is insufficient to offer both at the same time.

The two options are `detail` or `motion`. Screen-shares generally tend towards `detail` by default, and camera sources are tend towards `motion` by default. `detail` will try to prioritize resolution over frame rate, so the frame rate may drop a lot used. `motion` will try to maximize frame rate, but may drop the resolution a lot. There's no way to force both on as there's no magic bullet if your CPU or network cannot keep up.

For more information on how to lock or maximize the resolution of a video feed, please see the following guide:

{% content-ref url="../../guides/how-do-i-lock-the-resolution.md" %}
[how-do-i-lock-the-resolution.md](../../guides/how-do-i-lock-the-resolution.md)
{% endcontent-ref %}

There is [`&contenthint`](../video-parameters/and-contenthint.md) if you want the parameter to affect all kinds of video sources. You can also use both, `&screensharecontenthint` will override [`&contenthint`](../video-parameters/and-contenthint.md) for just screen-shares if set also.

{% hint style="info" %}
If using [`&codec=vp9`](../view-parameters/codec.md) on the viewer side, the frame rate may drop as low as even 5-fps.
{% endhint %}

{% hint style="warning" %}
This parameter has been tested on Chrome, but other browsers may vary in behavior. Safari seems to just ignore things, for example.
{% endhint %}

## Related

{% content-ref url="../video-parameters/and-contenthint.md" %}
[and-contenthint.md](../video-parameters/and-contenthint.md)
{% endcontent-ref %}




---
description: Excludes the current tab as a screen-share source option
---

# \&selfbrowsersurface

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&selfbrowsersurface=include` or `&selfbrowsersurface=exclude`

<table><thead><tr><th width="196">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td><strong>Excludes</strong> the current tab as a screen-share source option</td></tr><tr><td><code>include</code></td><td>In<strong>cludes</strong> the current tab as a screen-share source option</td></tr><tr><td><code>exclude</code></td><td><strong>Excludes</strong> the current tab as a screen-share source option</td></tr></tbody></table>

## Details

`&selfbrowsersurface` excludes the current tab as a screen-share source option. You can pass `include` or `exclude` as a value to control this though.

For more details on these new features see here:\
[https://developer.chrome.com/docs/web-platform/screen-sharing-controls/](https://developer.chrome.com/docs/web-platform/screen-sharing-controls/)\
(Chrome/chromium-browsers only)

## Related

{% content-ref url="../../source-settings/screenshare.md" %}
[screenshare.md](../../source-settings/screenshare.md)
{% endcontent-ref %}




---
description: Sets &scale=100, but only for screen-shares
---

# \&sharperscreen

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Details

As an alternative to [`&sharper`](../video-parameters/and-sharper.md), I've also added `&sharperscreen`, which sets [`&scale=100`](../view-parameters/scale.md), but _only_ for screen-shares (virtual cameras not included). This is probably even more efficient than [`&scale=100`](../view-parameters/scale.md) or [`&sharper`](../video-parameters/and-sharper.md), and it's designed for when screen-sharing a lot of text. Text looks a bit soft when streaming video at 1:1 pixel resolution.

It's recommended to only use these parameters within the context of a scene link, and not on guest links, due to the higher CPU / bandwidth it may use.

## Related

{% content-ref url="../video-parameters/and-sharper.md" %}
[and-sharper.md](../video-parameters/and-sharper.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/dpi.md" %}
[dpi.md](../view-parameters/dpi.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/scale.md" %}
[scale.md](../view-parameters/scale.md)
{% endcontent-ref %}




---
description: Makes the screen share behave like a webcam share
---

# \&smallshare

Sender-Side Option! ([`&push`](../../source-settings/push.md))\
Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&solo`](../mixer-scene-parameters/and-solo.md)) \*on alpha

## Details

`&smallshare` makes the screen share behave like a webcam share. ie: not larger in size vs other windows, for the publisher or the viewers. This is a push-side parameter. This is useful if a VR guests screen sharing an app of themselves, versus using a virtual camera. It can also be useful for gaming, where a larger screen share might bog down the system of the sender more than needed.

Layout if using `&smallshare`:\
.png>)

Layout if NOT using `&smallshare`:\
 (1).png>)

### Update on [v23](../../releases/v23.md)

`&smallshare` will work on the scene-side now also, which disables the automixer's larger screen-share layout, and instead just uses an equal-sized video layout for all videos.

## Related

{% content-ref url="../../source-settings/screenshare.md" %}
[screenshare.md](../../source-settings/screenshare.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-screensharetype.md" %}
[and-screensharetype.md](../../newly-added-parameters/and-screensharetype.md)
{% endcontent-ref %}




---
description: Will disable local audio playback of a Chrome tab while screen-sharing it
---

# \&suppresslocalaudio

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

`&suppresslocalaudio` will disable local audio playback of a Chrome tab while screen-sharing it. This can be used with the new [WHIP](../whip-parameters/and-whip.md) output of VDO.Ninja to publish a VDO.Ninja scene directly to Twitch, without having to deal with any audio feedback issues while having that scene tab open.

For more details on these new features see here:\
[https://developer.chrome.com/docs/web-platform/screen-sharing-controls/](https://developer.chrome.com/docs/web-platform/screen-sharing-controls/)\
(Chrome/chromium-browsers only)

## Related

{% content-ref url="../whip-parameters/and-whip.md" %}
[and-whip.md](../whip-parameters/and-whip.md)
{% endcontent-ref %}




---
description: Excludes the system-audio as an audio source when display sharing
---

# \&systemaudio

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

`&systemaudio` excludes the system-audio as an audio source when display sharing. Tab audio is still available though. (can help prevent accidental audio feedback loops)

For more details on these new features see here:\
[https://developer.chrome.com/docs/web-platform/screen-sharing-controls/](https://developer.chrome.com/docs/web-platform/screen-sharing-controls/)\
(Chrome/chromium-browsers only)

## Related

{% content-ref url="../../source-settings/screenshare.md" %}
[screenshare.md](../../source-settings/screenshare.md)
{% endcontent-ref %}




# &insertablestreams

**Also known as:** `&is`

#### **Description**

Enables insertable streams for custom media processing, allowing manipulation of encoded media frames before transmission or playback.

#### **General Option**

This parameter activates the insertable streams API, enabling advanced media processing capabilities.

#### **Usage**

* **`&insertablestreams`** - Enable insertable streams
* **`&insertablestreams=custom`** - Enable with custom identifier
* **`&is`** - Short alias

#### **Examples**

```
https://vdo.ninja/?push=streamID&insertablestreams
https://vdo.ninja/?view=streamID&is
https://vdo.ninja/?room=roomname&insertablestreams=myprocessor
```

#### **Technical Details**

* Enables WebRTC Insertable Streams API
* Allows frame-level media manipulation
* Can process both audio and video
* Used for custom encryption, effects, or analysis
* Required for certain advanced features

#### **Common Uses**

1. **Custom Encryption**: Implement end-to-end encryption
2. **Media Effects**: Apply custom video/audio processing
3. **Analytics**: Analyze media frames in real-time
4. **Watermarking**: Add watermarks to video streams
5. **Transcoding**: Custom codec implementations

#### **How It Works**

1. Intercepts encoded media frames
2. Allows JavaScript processing
3. Can modify or analyze frames
4. Re-inserts processed frames
5. Transparent to WebRTC pipeline

#### **Browser Support**

* **Chrome/Edge**: Full support (v86+)
* **Firefox**: Experimental support
* **Safari**: Limited support
* **Mobile**: Varies by platform

#### **Performance Considerations**

* Adds processing overhead
* May increase CPU usage
* Can impact latency
* Memory usage depends on processing

#### **Security Notes**

* Allows deep media access
* Use with trusted code only
* Can break E2EE if misused
* Verify processing integrity

#### **Related Parameters**

* [`&e2ee`](../setup-parameters/and-e2ee.md) - End-to-end encryption
* [`&password`](../setup-parameters/and-password.md) - Encryption password
* [`&secure`](../../source-settings/secure.md) - Security mode
* [`&privacy`](../turn-and-stun-parameters/and-privacy.md) - Privacy enhancements




---
description: >-
  Language, save cookies, remote access, chat widget, chunked mode, raise hands,
  notify, transcription, closed captions
---

# Settings Parameters

They are separated in three groups: [general options](./#general-options) (push and view), [source side](./#source-side-options) (push) options and [viewer side](./#viewer-side-options) (view) options.

## General Options

You can use them for publisher, viewer and director URLs.

<table><thead><tr><th width="267.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-language.md"><code>&#x26;language</code></a></td><td>Sets the interface language</td></tr><tr><td><a href="../../general-settings/remote.md"><code>&#x26;remote</code></a></td><td>Allows remote operation of the zoom and focus, and access to statistics</td></tr><tr><td><a href="and-controlobs.md"><code>&#x26;controlobs</code></a></td><td>The ability for VDO.Ninja to Remotely Control OBS Studio while streaming/directing</td></tr><tr><td><a href="and-allowedscenes.md"><code>&#x26;allowedscenes</code></a></td><td>Option to filter which OBS scenes a remote guest has access to controlling when using <a href="and-controlobs.md"><code>&#x26;controlobs</code></a></td></tr><tr><td><a href="../../general-settings/and-stats.md"><code>&#x26;stats</code></a></td><td>Shows the connection/media stats window by default</td></tr><tr><td><a href="../../general-settings/sticky.md"><code>&#x26;sticky</code></a></td><td>Allows a user to save and then later restore their streaming session settings</td></tr><tr><td><a href="and-clearstorage.md"><code>&#x26;clearstorage</code></a></td><td>Will clear all the saved user preferences for all sessions</td></tr><tr><td><a href="and-disablehotkeys.md"><code>&#x26;disablehotkeys</code></a></td><td>Disables hotkeys (like <code>CRTL + M</code>)</td></tr><tr><td><a href="../../source-settings/showlist.md"><code>&#x26;showlist</code></a></td><td>Shows list of hidden guests</td></tr><tr><td><a href="and-nopush.md"><code>&#x26;nopush</code></a></td><td>Blocks outbound publishing connections</td></tr><tr><td><a href="and-hidehome.md"><code>&#x26;hidehome</code></a></td><td>Hides the VDO.Ninja homepage and many links that lead to it</td></tr><tr><td><a href="and-hidetranslate.md"><code>&#x26;hidetranslate</code></a></td><td>Hides the option to translate VDO.Ninja</td></tr><tr><td><a href="and-clock.md"><code>&#x26;clock</code></a></td><td>Shows the current time</td></tr><tr><td><a href="and-clock24-alpha.md"><code>&#x26;clock24</code></a>*</td><td>The same as <a href="and-clock.md"><code>&#x26;clock</code></a> option, except it uses 24-hour time for the display</td></tr><tr><td><a href="and-timer.md"><code>&#x26;timer</code></a></td><td>Positions the countdown timer</td></tr><tr><td><a href="and-powerpoint.md"><code>&#x26;powerpoint</code></a></td><td>Adds a built-in basic controller to control PowerPoint</td></tr><tr><td><a href="and-widget.md"><code>&#x26;widget</code></a></td><td>Will load a side-bar with an IFrame embed, with support for YouTube / Twitch / Social Stream</td></tr><tr><td><a href="and-token.md"><code>&#x26;token</code></a></td><td>A token for invite/scene links to determine whose the director of a room</td></tr></tbody></table>

\*NEW IN [VERSION 24](../../releases/v24.md)

## Source Side Options

**Source Settings**, which are settings specific to publishing. The parameters can be added to a publishing link, like for example a guest, a director or just a basic push link.

<table><thead><tr><th width="235.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../source-settings/transcribe.md"><code>&#x26;transcribe</code></a></td><td>Enables transcription and closed captioning</td></tr><tr><td><a href="../../newly-added-parameters/and-signalmeter.md"><code>&#x26;signalmeter</code></a></td><td>Visualizes the packet loss of a guest</td></tr><tr><td><a href="and-batterymeter.md"><code>&#x26;batterymeter</code></a></td><td>Shows the battery meter for guests that are on devices with a battery that's draining/charging</td></tr><tr><td><a href="../../source-settings/consent.md"><code>&#x26;consent</code></a></td><td>Will ask the user for content to remote change their camera or microphone</td></tr><tr><td><a href="and-prompt.md"><code>&#x26;prompt</code></a></td><td>Another security option, for those concerned about random spying of their streams</td></tr><tr><td><a href="../../source-settings/and-hands.md"><code>&#x26;hands</code></a></td><td>Enables a "Raise Hand" button for guests</td></tr><tr><td><a href="../../source-settings/and-notify.md"><code>&#x26;notify</code></a></td><td>Audio alerts for raised hands, chat messages and if somebody joins the room</td></tr><tr><td><a href="../../source-settings/r2d2.md"><code>&#x26;r2d2</code></a></td><td>Easter egg <a href="../../source-settings/and-notify.md"><code>&#x26;notify</code></a> sound</td></tr><tr><td><a href="../../source-settings/directorchat.md"><code>&#x26;directorchat</code></a></td><td>Message ONLY the director</td></tr><tr><td><a href="../../source-settings/and-maxconnections.md"><code>&#x26;maxconnections</code></a></td><td>Limits total of view and push connections</td></tr><tr><td><a href="../../source-settings/and-maxviewers.md"><code>&#x26;maxviewers</code></a></td><td>Limits the number of viewers allowed</td></tr><tr><td><a href="../../newly-added-parameters/and-chunked.md"><code>&#x26;chunked</code></a></td><td>Does not use webRTC's video streaming protocols; rather it uses a custom-made protocol</td></tr><tr><td><a href="and-retransmit.md"><code>&#x26;retransmit</code></a>*</td><td>Will relay the incoming 'chunked' media stream to others connected to you, without transcoding</td></tr><tr><td><a href="../../newly-added-parameters/and-rampuptime.md"><code>&#x26;rampuptime</code></a></td><td>When a guest connects, this tries to load video from that guest for a few seconds, even if not yet added to a scene</td></tr><tr><td><a href="../../source-settings/sensor.md"><code>&#x26;sensor</code></a></td><td>Access device sensor data at given rate</td></tr><tr><td><a href="and-sensorfilter.md"><code>&#x26;sensorfilter</code></a></td><td>An option to explicitly list what <a href="../../source-settings/sensor.md"><code>&#x26;sensor</code></a> data you want to capture and transmit</td></tr><tr><td><a href="and-postimage.md"><code>&#x26;postimage</code></a></td><td>Post a snapshot of your local camera to a HTTPS/POST URL</td></tr><tr><td><a href="and-postinterval.md"><code>&#x26;postinterval</code></a></td><td>Time interval in seconds for <a href="and-postimage.md"><code>&#x26;postimage</code></a></td></tr><tr><td><a href="and-slot.md"><code>&#x26;slot</code></a></td><td>Tells the director which slot the guest should prefer to be in</td></tr></tbody></table>

\*NEW IN [VERSION 24](../../releases/v24.md)

## Viewer Side Options

**Viewer's Settings**, which are aspects that are controllable by the viewer's side. These parameters are mostly added to [`&room`](../../general-settings/room.md) (viewing other guests), [`&view`](../view-parameters/view.md) and [`&scene`](../view-parameters/scene.md) or [`&solo`](../mixer-scene-parameters/and-solo.md) links, but some of them can also be added to the director's URL.

<table><thead><tr><th width="244.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-closedcaptions.md"><code>&#x26;closedcaptions</code></a></td><td>Enables displaying of closed captioning text</td></tr><tr><td><a href="and-nocaptionlabels.md"><code>&#x26;nocaptionlabels</code></a>*</td><td>Disables showing the names when using the <a href="and-closedcaptions.md"><code>&#x26;closedcaptions</code></a> feature</td></tr><tr><td><a href="../view-parameters/enhance.md"><code>&#x26;enhance</code></a></td><td>Tells the remote source that you would like them to prioritize the audio stream over other streams</td></tr><tr><td><a href="../parameters-only-on-beta/and-bitratecutoff.md"><code>&#x26;bitratecutoff</code></a></td><td>If the total bitrate drops below the specified bitrate, the viewer will auto-hide the audio and video for that stream</td></tr><tr><td><a href="and-cutscene.md"><code>&#x26;cutscene</code></a></td><td>Specifies an OBS cut scene to switch to when the bitrate drops below a threshold</td></tr><tr><td><a href="../parameters-only-on-beta/and-statsinterval.md"><code>&#x26;statsinterval</code></a></td><td>Lets you change the default stats update interval from 3-seconds to something else</td></tr><tr><td><a href="../view-parameters/keyframerate.md"><code>&#x26;keyframerate</code></a></td><td>This tells the remote publishers to send keyframes at a specified rate</td></tr><tr><td><a href="../view-parameters/and-maxpublishers.md"><code>&#x26;maxpublishers</code></a></td><td>Limits the number of remote peer connections that are publishers</td></tr><tr><td><a href="and-showconnections.md"><code>&#x26;showconnections</code></a></td><td>Displays the total number of p2p connections of a remote stream</td></tr><tr><td><a href="../view-parameters/and-obsfix.md"><code>&#x26;obsfix</code></a></td><td>Disables or adjusts the sensitivity of the VP8/VP9 Codec packet loss 'fix' for OBS</td></tr><tr><td><a href="../view-parameters/streamlabs.md"><code>&#x26;streamlabs</code></a></td><td>Tells VDO.Ninja to not block VDO.Ninja from attempting to run when using Streamlabs for MacOS</td></tr><tr><td><a href="and-getfaces.md"><code>&#x26;getfaces</code></a></td><td>Will request a continuous stream of face bounding boxes</td></tr><tr><td><a href="and-nochunked.md"><code>&#x26;nochunked</code></a></td><td>Will ignore the chunked version and use the low-latency version</td></tr></tbody></table>

\*NEW IN [VERSION 24](../../releases/v24.md)




---
description: >-
  Option to filter which OBS scenes a remote guest has access to controlling
  when using &controlobs
---

# \&allowedscenes

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Options

Example: `&allowedscenes=Scene1,Scene2`

<table><thead><tr><th width="345">Value</th><th>Description</th></tr></thead><tbody><tr><td>(comma separated OBS scene names)</td><td>filter which OBS scenes a remote guest has access to controlling when using <a href="and-controlobs.md"><code>&#x26;controlobs</code></a></td></tr></tbody></table>

## Details

`&allowedscenes` filters which OBS scenes a remote guest has access to controlling when using [`&controlobs`](and-controlobs.md). Uses CSV to split up the scenes (avoid special characters in your scene names if there are issues)

Example: `vdo.ninja/?view=StreamID&remote&allowedscenes=Scene1,Scene2`

{% hint style="info" %}
If you don't want a user to have the ability to start/stop a stream, set the OBS page permissions to level 4, instead of 5. It'll disable the start/stop buttons for the user if they don't have those permissions.
{% endhint %}

## Related

{% content-ref url="and-controlobs.md" %}
[and-controlobs.md](and-controlobs.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/remote.md" %}
[remote.md](../../general-settings/remote.md)
{% endcontent-ref %}




---
description: >-
  Shows the battery meter for guests that are on devices with a battery that's
  draining/charging
---

# \&batterymeter

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&batterymeter=0`

| Value                | Description                    |
| -------------------- | ------------------------------ |
| (no value given)     | Adds a battery-meter per guest |
| `0` \| `no` \| `off` | Disables the battery-meter     |

## Details

Curtesy of @Yong.\
Notes:\
[https://github.com/steveseguin/vdo.ninja/pull/1078#issuecomment-1627799535](https://github.com/steveseguin/vdo.ninja/pull/1078#issuecomment-1627799535)

It's the same concept of [`&signalmeter`](../../newly-added-parameters/and-signalmeter.md), except shows the battery meter for guests that are on devices with a battery that's draining/charging.

Shows blinking warning if under 25% battery life.

The battery meter was already available by default as the director, but now it can be enabled as a guest, etc.

Also supports disabling the meter with `&batterymeter=0`.

## Related

{% content-ref url="../../newly-added-parameters/and-signalmeter.md" %}
[and-signalmeter.md](../../newly-added-parameters/and-signalmeter.md)
{% endcontent-ref %}




# &blackoutmode

**Also known as:** `&blackout`, `&bo`, `&bom`

#### **Description**

Enables blackout mode, which hides all videos and mutes all audio for privacy or emergency situations.

#### **General Option**

This parameter activates or shows the blackout mode button, allowing quick privacy control during streams.

#### **Usage**

* **`&blackoutmode`** - Shows the blackout button
* **`&blackoutmode=1`** - Shows button and activates blackout immediately
* **`&blackout`** - Alias for blackoutmode
* **`&bo`** - Short alias
* **`&bom`** - Short alias

#### **Examples**

```
https://vdo.ninja/?room=roomname&blackoutmode
https://vdo.ninja/?push=streamID&blackoutmode=1
https://vdo.ninja/?director&room=roomname&bo
```

#### **Visual Example**

When activated:
- All video feeds become black
- All audio is muted
- A clear indicator shows blackout is active
- Can be toggled on/off with the button

#### **Details**

* Shows a prominent blackout button in the interface
* When activated, immediately blacks out all video
* Mutes all audio inputs and outputs
* Useful for emergency privacy situations
* State can be toggled by clicking the button

#### **Use Cases**

* Emergency privacy protection
* Quick mute during unexpected interruptions
* Studio blackouts between takes
* Privacy during sensitive discussions
* Technical issue masking

#### **Notes**

* Affects both incoming and outgoing streams
* Blackout state is local (not synchronized across participants)
* Quick toggle for immediate privacy
* Visual indicator prevents accidental activation

#### **Related Parameters**

* [`&mute`](../../source-settings/and-mute.md) - Mutes audio only
* [`&videomute`](../../source-settings/and-videomute.md) - Mutes video only
* [`&privacy`](../../turn-and-stun-parameters/and-privacy.md) - Enhanced privacy mode
* [`&hidemenu`](../design-parameters/and-hidemenu.md) - Hides interface elements




---
description: Will clear all the saved user preferences for all sessions
---

# \&clearstorage

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&clear`

## Details

`&clearstorage` will clear all the saved user preferences for all sessions, including [`&sticky`](../../general-settings/sticky.md)'d data, director settings, any camera and microphone settings, and probably a couple other small things. This also includes the "default" saved stated of camera settings before adjusted.

I also added a button to manually do this via the User menu settings.\

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="../../general-settings/sticky.md" %}
[sticky.md](../../general-settings/sticky.md)
{% endcontent-ref %}




---
description: Shows the current time
---

# \&clock

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md), [`&director`](../../viewers-settings/director.md))

## Options

Example: `&clock=5` or `&clock=false`

<table><thead><tr><th width="232">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code> - <code>9</code></td><td>Shows the current time as in the graphic below. Each option specifies where the clock will appear on the screen</td></tr><tr><td><code>9</code> | (no value given)</td><td>Shows the current time in the lower right</td></tr><tr><td><code>false</code></td><td>Will force-disable the clock from being remotely triggerable</td></tr></tbody></table>

 (10).png>)

## Details

`&clock` shows the current time in the lower right; this can be applied to pretty much all link types.

<figure><figcaption></figcaption></figure>

The director has a button that lets them enable the clock for everyone in the room (via the director's room settings button).

<figure><figcaption></figcaption></figure>

`&clock=false` or [`&cleanoutput`](../design-parameters/cleanoutput.md) will force-disable the clock from being remotely triggerable.

The director will see the clock also; it will just be a bit smaller on screen.

 (1) (1) (3).png>)

## Related

{% content-ref url="and-clock24-alpha.md" %}
[and-clock24-alpha.md](and-clock24-alpha.md)
{% endcontent-ref %}

{% content-ref url="and-timer.md" %}
[and-timer.md](and-timer.md)
{% endcontent-ref %}




---
description: The same as &clock option, except it uses 24-hour time for the display
---

# \&clock24

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md), [`&director`](../../viewers-settings/director.md))

## Options

Example: `&clock24=5`

<table><thead><tr><th width="232">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code> - <code>9</code></td><td>Shows the current time as in the graphic below. Each option specifies where the clock will appear on the screen</td></tr><tr><td><code>9</code> | (no value given)</td><td>Shows the current time in the lower right</td></tr><tr><td><code>false</code></td><td>Will force-disable the clock from being remotely triggerable</td></tr></tbody></table>

 (10).png>)

## Details

`&clock24` is the same as the existing [`&clock`](and-clock.md) option, (which shows a clock) except it uses 24-hour time for the display (vs. am/pm).\
 (1).png>)

If the director uses `&clock24` on their URL, and then enables the room clock, it will be 24-hour time for all guests, matching the director's settings.

Shows the current time in the lower right; this can be applied to pretty much all link types.

The director has a button that lets them enable the clock for everyone in the room (via the director's room settings button).

The director will see the clock also; it will just be a bit smaller on screen.

## Related

{% content-ref url="and-clock.md" %}
[and-clock.md](and-clock.md)
{% endcontent-ref %}

{% content-ref url="and-timer.md" %}
[and-timer.md](and-timer.md)
{% endcontent-ref %}




---
description: Enables displaying of closed captioning text
---

# \&closedcaptions

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&captions`
* `&cc`

## Details

This command will display the incoming transcribed text-data as an overlay. You will need to use this on the VIEW link, while also using the [`&transcribe`](../../source-settings/transcribe.md) command on the PUSH link.

See video for a walk-thru:

{% embed url="https://www.youtube.com/embed/3eo85WAXeuk" %}

Overlay text data is pulled from the source with [`&transcribe`](../../source-settings/transcribe.md) added.

[`&fontsize={percent}`](../view-parameters/fontsize.md) can be used to adjust the overlay font-size. 100% is default;

Use can use [`&css=somecssfile.css`](../design-parameters/css.md) to further customize the CSS style, or do so in the OBS Browser source style sheet area. You can also set the CSS via a base64 encoded string in the URL, via the [`&base64css`](../design-parameters/css.md) parameter.\
\
An example of a custom stylesheet for OBS that changes the font-family of the overlay text is the is the following:

```
body {
  background-color: rgba(0, 0, 0, 0); margin: 0px auto; overflow: hidden;
}

@font-face {
  font-family: 'opendyslexic';
	src: url('https://vdo.ninja/examples/OpenDyslexic-Regular.otf');
	font-style: normal;
	font-weight: normal;
} 

#overlayMsgs {
	font-family: "opendyslexic", opendyslexic, serif;
}
```

Another example of limiting the captioning-text to only use a fixed height of space when used as an overlay to OBS browser source. Just replace the OBS browser style with this code snippet instead:

```
body { background-color: rgba(0, 0, 0, 0); margin: 0px auto; overflow: hidden; }

#overlayMsgs{
    overflow: auto!important;
    display: flex!important;
    flex-direction: column-reverse!important;
    height: 240px!important;
}

#overlayMsgs span {
    text-align: left!important;
}
```

If not using OBS, you can still add the above CSS via the URL using the [`&base64css`](../design-parameters/and-base64css.md) parameter. For example, instead of the above CSS, you can append the following to the URL:

`&base64css=I292ZXJsYXlNc2dzew0KICAgIG92ZXJmbG93OiBhdXRvIWltcG9ydGFudDsNCiAgICBkaXNwbGF5OiBmbGV4IWltcG9ydGFudDsNCiAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uLXJldmVyc2UhaW1wb3J0YW50Ow0KICAgIGhlaWdodDogMjQwcHghaW1wb3J0YW50Ow0KfQ0KDQojb3ZlcmxheU1zZ3Mgc3BhbiB7DQogICAgdGV4dC1hbGlnbjogbGVmdCFpbXBvcnRhbnQ7DQp9`

Feedback and user requests are welcomed.

### Example links and  Resources

[https://vdo.ninja/?transcribe](https://vdo.ninja/?transcribe)\
[https://vdo.ninja/?view=abc123\&closedcaptions](https://vdo.ninja/?view=abc123\&closedcaptions)\
[https://meyerweb.com/eric/tools/dencoder/](https://meyerweb.com/eric/tools/dencoder/)\
[https://vdo.ninja/examples/rainbow.css](https://vdo.ninja/examples/rainbow.css)\
[https://vdo.ninja/?css=https%3A%2F%2Fvdo.ninja%2Fexamples%2Frainbow.css](https://vdo.ninja/?css=https%3A%2F%2Fvdo.ninja%2Fexamples%2Frainbow.css)

## Related

{% content-ref url="../design-parameters/css.md" %}
[css.md](../design-parameters/css.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/transcribe.md" %}
[transcribe.md](../../source-settings/transcribe.md)
{% endcontent-ref %}




---
description: Forces the user control bar to be in its own dedicated space
---

# \&controlbarspace

Sender-Side Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md))

## Details

`&controlbarspace` forces the bottom control bar to be in its own dedicated space, regardless of screen size.

<figure><figcaption><p>The control bar is not overlapping the video feed</p></figcaption></figure>

## Related

{% content-ref url="../../parameters-only-on-beta/and-autohide.md" %}
[and-autohide.md](../../parameters-only-on-beta/and-autohide.md)
{% endcontent-ref %}




---
description: >-
  The ability for VDO.Ninja to Remotely Control OBS Studio while
  streaming/directing
---

# \&controlobs

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&obscontrols`
* `&remoteobs`
* `&obsremote`
* `&obs`

## Options

Example: `&controlobs=0`

<table><thead><tr><th width="227">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td><a data-mention href="and-controlobs.md#remotely-control-obs-studio">#remotely-control-obs-studio</a></td></tr><tr><td><code>0</code> | <code>false</code> | <code>off</code></td><td><a href="and-controlobs.md#disabling-or-hiding-the-controls">will hide the control option on the sender side, regardless of the OBS browser source page permissions</a></td></tr></tbody></table>

## Remotely Control OBS Studio

Added the ability for VDO.Ninja to **Remotely Control OBS Studio** while streaming/directing. It may be useful for [IRL streaming](https://restream.io/blog/irl-streaming-ultimate-guide/)?

The menu button to control OBS auto-shows in the director's view or push-mode, if OBS Studio is set to give VDO.Ninja "full" permissions.

.png>)

The menu button can also be added manually, for even guests, using `&controlobs`. [`&obsoff`](../design-parameters/and-obsoff.md) can be used to set permissions to fully off (also disables tally light and scene optimizations tho) when added to the OBS browser source link.

The OBS instance still needs [`&remote=optional-passcode-here`](../../general-settings/remote.md) added to the URL for remote commands to work. If [`&remote`](../../general-settings/remote.md) is left blank, it gives anyone permissions to control it. If a value is passed to [`&remote`](../../general-settings/remote.md), the sender needs to have a matching [`&remote` ](../../general-settings/remote.md)value or they need to manually enter the passcode in the pop up control menu.

.png>)

If the OBS browser source has its permissions set to something other than full (lower than level 5), the control menu will still show what info it has -- current scene, recording/streaming state, etc; depending on level. The lower the level, the less info is available to show. It can't remotely change anything though.

It supports multiple OBS instances and will label them according to the [`&label=xxx`](../../general-settings/label.md) value set on the scene/view link, or whatever the unique connection ID is.

## How to set it up (example)

1\. Add a browser source to OBS Studio with this URL:\
`https://vdo.ninja/?view=streamid12345&remote&controlobs`

2\. Give page permissions to the browser source (Full access to OBS) like on the image below\
.png>)

3\. Open this Push Link: [https://vdo.ninja/?push=streamid12345\&wc\&as\&controlobs\&remote](https://vdo.ninja/?push=streamid12345\&wc\&as\&controlobs\&remote)

4\. Click on this button\
.png>)

5\. Control OBS Studio remotely via VDO.Ninja

### Disabling or hiding the controls

Setting `&controlobs=0` or to `false`/`off`, will hide the control option on the sender side, regardless of the OBS browser source page permissions.

As well, setting the OBS browser source to low or no page permissions will also not show the controls, which is how it is by default.  You can force show the controls of course, but they won't work if the browser source doesn't have the right permissions.

## Related

{% content-ref url="../../general-settings/remote.md" %}
[remote.md](../../general-settings/remote.md)
{% endcontent-ref %}

{% content-ref url="and-cutscene.md" %}
[and-cutscene.md](and-cutscene.md)
{% endcontent-ref %}

{% content-ref url="../design-parameters/and-obsoff.md" %}
[and-obsoff.md](../design-parameters/and-obsoff.md)
{% endcontent-ref %}

{% content-ref url="and-allowedscenes.md" %}
[and-allowedscenes.md](and-allowedscenes.md)
{% endcontent-ref %}




---
description: >-
  Specifies an OBS cut scene to switch to when the bitrate drops below a
  threshold
---

# \&cutscene

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&lowbitratescene`

## Options

Example: `&cutscene=ObsSceneName`

| Value            | Description               |
| ---------------- | ------------------------- |
| (OBS scene name) | The name of the OBS scene |

## Details

You can use the IRL-related command called `&cutscene` to specify an OBS cut scene to switch to when the bitrate drops below a threshold and return to the original scene when the bitrate recovers. (assuming the cut scene is active; it won't switch back from a scene that isn't the cut away scene)

The default bitrate threshold is 300-kbps, but you can use the existing [`&bitratecutoff=N`](../parameters-only-on-beta/and-bitratecutoff.md) option to specify a custom one. Using `&cutscene` with [`&bitratecutoff`](../parameters-only-on-beta/and-bitratecutoff.md) will override the behaviour of [`&bitratecutoff`](../parameters-only-on-beta/and-bitratecutoff.md)'s other features. It won't start triggering until the bitrate has hit at least the threshold once. to use:

```
https://vdo.ninja/?push=XXX
https://vdo.ninja/?view=XXX&controlobs&bitratecutoff=300&cutscene=FML&remote
```

You can of course use this with [`&controlobs`](and-controlobs.md)[`&remote`](../../general-settings/remote.md), to have the publisher change the scenes dynamically, and see what the current OBS scene is (if still connected).

{% hint style="warning" %}
Note that the OBS browser source needs the permissions to be set to high, to give VDO.Ninja permissions to change scenes.
{% endhint %}

{% hint style="warning" %}
Do not set the OBS browser source to "Shutdown" when not visible, as this will prevent things from being able to switch back.
{% endhint %}

When using `&cutscene` on a room scene, it won't trigger due to a director being in the room with no video, unless they are using [`&showdirector`](../../viewers-settings/and-showdirector.md). `&cutscene` wasn't intended really for a group scene; just a solo link or view link, but this fix makes it at more usable with a group scene.

## Related

{% content-ref url="../parameters-only-on-beta/and-bitratecutoff.md" %}
[and-bitratecutoff.md](../parameters-only-on-beta/and-bitratecutoff.md)
{% endcontent-ref %}

{% content-ref url="and-controlobs.md" %}
[and-controlobs.md](and-controlobs.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/remote.md" %}
[remote.md](../../general-settings/remote.md)
{% endcontent-ref %}




# &debug

#### **Description**

Enables verbose debug logging to browser console and optionally streams logs to a WebSocket server.

#### **General Option**

This parameter activates detailed logging for troubleshooting connection issues and debugging problems.

#### **Usage**

* **`&debug`** - Enable debug logging to console and auto-save on exit
* **`&debug=ws://server.com:port`** - Stream logs to WebSocket server
* **`&debug=wss://secure-server.com`** - Stream logs to secure WebSocket

#### **Examples**

```
https://vdo.ninja/?room=roomname&debug
https://vdo.ninja/?push=streamID&debug
https://vdo.ninja/?view=streamID&debug=ws://localhost:8080
```

#### **Details**

* Outputs verbose logs to browser's developer console
* Attempts to auto-save logs to disk when page closes
* Can stream logs in real-time to WebSocket endpoint
* Auto-save may not work in OBS browser sources
* Logs include connection states, errors, and performance data

#### **Log Contents**

* WebRTC connection states
* ICE candidate information
* Media track events
* Error messages
* Performance metrics
* Network quality data
* API calls and responses

#### **WebSocket Streaming**

When using `&debug=websocketserver`:
* Logs stream in real-time
* Requires custom WebSocket server
* Useful for remote debugging
* Can monitor multiple sessions

#### **Accessing Logs**

1. **Browser Console**: Press F12 → Console tab
2. **Auto-saved File**: Downloads on page close (Chrome only)
3. **WebSocket Stream**: Real-time on your server

#### **Use Cases**

* Troubleshooting connection failures
* Analyzing performance issues
* Remote support and debugging
* Development and testing
* Network diagnostics

#### **Notes**

* Generates significant console output
* May impact performance slightly
* Sensitive information may be logged
* Best used temporarily for troubleshooting
* Log files can become large quickly

#### **Related Parameters**

* [`&stats`](../../general-settings/and-stats.md) - Shows connection statistics overlay
* [`&showconnections`](and-showconnections.md) - Displays connection info
* [`&getdetailedstate`](../../guides/api-commands/getdetailedstate.md) - API for connection state




---
description: Disables hotkeys (like CRTL + M)
---

# \&disablehotkeys

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Details

`&disablehotkeys` disables hotkeys (like `CRTL + M`).

## Related

{% content-ref url="../../guides/hotkey-support/" %}
[hotkey-support](../../guides/hotkey-support/)
{% endcontent-ref %}




---
description: Adds a full-screen button to the control bar
---

# \&fullscreenbutton

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&fsb`

## Details

`&fullscreenbutton` adds a full-screen button to the control bar. It essentially just mimics F11, with added support for detecting the Escape button to exit full screen.

 (6).png>)

Also while using `&fullscreenbutton`, the previous little 'full window' button in the top-right of videos (if in a group room) will also auto-F11 and isolate that video, rather than just isolate the video.

You can still right-click and select "full-window" on any video to isolate it without going full screen, if you need that.

You can test by opening two such guest links:\
[https://vdo.ninja/?fsb\&room=test123123123\&webcam\&autostart](https://vdo.ninja/?fsb\&room=test123123123\&webcam\&autostart)

Ultimately I'd like to override the native video full screen button with this behaviour, when `&fullscreenbutton` is used, but I'm still working on that aspect.

### Update in [v23](../../releases/v23.md)

`&fullscreenbutton` is improved, so that even when there is a single video on the page, it will show. It also shows more reliably, without needing to move the mouse around a bit to re-show the button after going full screen. Lastly, when used, it now hides the native full-screen button, so users have to use it.

Unlike the native full screen button, this full screen mode alternative keeps the chat and control bar overlays visible (like press F11). Since this is probably the preferred way most users will want to full screen to work, I may make it the default mode at some point, after some more testing/feedback. (not supported on iOS/iPhone tho)

Testing at [https://vdo.ninja/?fullscreenbutton](https://vdo.ninja/?fullscreenbutton) (join a room as a guest to trigger)

## Related

{% content-ref url="../../source-settings/fullscreen.md" %}
[fullscreen.md](../../source-settings/fullscreen.md)
{% endcontent-ref %}




---
description: Will request a continuous stream of face bounding boxes
---

# \&getfaces

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&pushfaces`

## Details

`&getfaces` on the viewer link will request a continuous stream of face bounding boxes, for all inbound videos and all faces contained within. The data is transmitted to the parent IFRAME, and this data can be used for moving the IFrame window around, if you wish to make your own custom face-tracker or whatever else.

{% hint style="warning" %}
`&getfaces` requires the use of the Chromium experimental face detection API, as I'm using the built-in browser face-tracking model for this. You can enable the API flag here: `chrome://flags/#enable-experimental-web-platform-features`\
My hope is that this feature will eventually be enabled by default within Chromium, as loading a large ML model to do face detection otherwise is a bit heavy; you may need to enable this within the OBS CLI if wishing to use it there?
{% endhint %}




---
description: Hides the VDO.Ninja homepage and many links that lead to it
---

# \&hidehome

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md), [`&director`](../../viewers-settings/director.md))

## Details

`&hidehome` hides the VDO.Ninja homepage and many links that lead to it. You can also enable at a code level with `session.hidehome=true;`, which is useful if doing a self-deployment, where you don't want anyone to stumble onto the site and start using it. You'll still be able to join push links and create rooms via URL parameters, but that's about it.

## Related

{% content-ref url="../design-parameters/and-hidemenu.md" %}
[and-hidemenu.md](../design-parameters/and-hidemenu.md)
{% endcontent-ref %}

{% content-ref url="../design-parameters/and-hideheader.md" %}
[and-hideheader.md](../design-parameters/and-hideheader.md)
{% endcontent-ref %}




---
description: Hides the option to translate VDO.Ninja
---

# \&hidetranslate

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Details

`&hidetranslate` hides the button at the bottom right of VDO.Ninja to select a different language. If you want to change the language via URL you can use [`&language`](and-language.md).

 (3) (1).png>)

## Related

{% content-ref url="and-language.md" %}
[and-language.md](and-language.md)
{% endcontent-ref %}




---
description: Sets the interface language
---

# \&language

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&ln`

## Options

Example: `&language=fr`

<table><thead><tr><th width="241">Value</th><th>Language</th></tr></thead><tbody><tr><td><code>cn</code></td><td>Chinese</td></tr><tr><td><code>cs</code></td><td>Czech</td></tr><tr><td><code>de</code></td><td>German</td></tr><tr><td><code>en</code></td><td>English (default if <code>&#x26;ln</code> not present)</td></tr><tr><td><code>es</code></td><td>Spanish</td></tr><tr><td><code>eu</code></td><td>Basque</td></tr><tr><td><code>fr</code></td><td>French</td></tr><tr><td><code>it</code></td><td>Italian</td></tr><tr><td><code>ja</code></td><td>Japanese</td></tr><tr><td><code>nl</code></td><td>Dutch</td></tr><tr><td><code>pig</code></td><td>Pig Latin</td></tr><tr><td><code>pt</code></td><td>Portuguese</td></tr><tr><td><code>ru</code></td><td>Russian</td></tr><tr><td><code>tr</code></td><td>Turkish</td></tr><tr><td><code>uk</code></td><td>Ukrainian</td></tr><tr><td>(no value given)</td><td>Less verbose interface</td></tr></tbody></table>

## Details

You can [contribute new or update existing translations](https://github.com/steveseguin/obsninja/tree/master/translations).

You can also change the language of VDO.Ninja dynamically on the bottom right.\
 (2).png>)

## Related

{% content-ref url="and-hidetranslate.md" %}
[and-hidetranslate.md](and-hidetranslate.md)
{% endcontent-ref %}




# &morescenes

#### **Description**

Adds additional numbered scene buttons beyond the default 8 scenes in the director's control room.

#### **Director-Side Option**

This parameter extends the number of scene selection buttons available to the director.

#### **Usage**

* **`&morescenes=12`** - Shows 12 scene buttons (1-12)
* **`&morescenes=16`** - Shows 16 scene buttons (1-16)
* **`&morescenes=20`** - Shows 20 scene buttons (1-20)

#### **Examples**

```
https://vdo.ninja/?room=roomname&director&morescenes=12
https://vdo.ninja/?room=roomname&director&morescenes=16
```

#### **Details**

* Default without parameter: 8 scene buttons
* Minimum value: 9 (values below 9 are set to 8)
* Maximum practical limit depends on screen size and UI layout
* Scene buttons appear in the director's control interface
* Each scene can have different guests/layouts assigned

#### **Visual Example**

When `&morescenes=12` is used, the director will see:

 (1) (1) (1) (1) (1) (1) (1).png>)

#### **Notes**

* Useful for productions with many different scene configurations
* Additional scenes can be accessed via keyboard shortcuts
* Scene configurations are saved per room

#### **Related Parameters**

* [`&scene`](../../advanced-settings/view-parameters/scene.md) - Specifies which scene to view
* [`&director`](../../viewers-settings/director.md) - Enables director mode
* [`&layouts`](../director-parameters/and-layouts.md) - Pre-configures scene layouts




---
description: Disables showing the names when using the &closedcaptions feature
---

# \&nocaptionlabels

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&nocaptionlabel`
* `&nocclabels`
* `&nocclabel`

## Details

`&nocclabels` disables showing the names when using the [`&closedcaptions`](and-closedcaptions.md) feature, as you might want to only show labels on the video themselves, and not in the transcription text.

## Related

{% content-ref url="and-closedcaptions.md" %}
[and-closedcaptions.md](and-closedcaptions.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/label.md" %}
[label.md](../../general-settings/label.md)
{% endcontent-ref %}




---
description: Will ignore the chunked version and use the low-latency version
---

# \&nochunked

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&nochunk`

## Details

If a VDO.Ninja guest has [`&chunked`](../../newly-added-parameters/and-chunked.md) added, the viewer or another guest can use `&nochunked` to ignore the chunked version, and use the low-latency version. In this way, guests in a room can still use the low latency streams to chat, but publish chunked video to OBS for (delayed) high quality video.

## Related

{% content-ref url="../../newly-added-parameters/and-chunked.md" %}
[and-chunked.md](../../newly-added-parameters/and-chunked.md)
{% endcontent-ref %}




---
description: Will force hide the video control bar
---

# \&nocontrols

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&controls=0`

## Details

`&nocontrols` will force hide the video control bar. You can also hide the control bar with `Right-Click` -> `Hide control bar`.

{% hint style="warning" %}
This is not the same control bar as the user control bar. Also, be sure to not accidentally unmute yourself -- echo feedback galore.
{% endhint %}

This is the video control bar:\

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="../newly-added-parameters/and-videocontrols.md" %}
[and-videocontrols.md](../newly-added-parameters/and-videocontrols.md)
{% endcontent-ref %}




# &nofullscreenbutton

**Also known as:** `&nofsb`

#### **Description**

Hides the full-window button that appears in the top-right corner of videos in group rooms.

#### **General Option**

This parameter removes the small expand/full-window button that typically appears when hovering over videos.

#### **Usage**

* **`&nofullscreenbutton`** - Hides the full-window button
* **`&nofsb`** - Short alias for the parameter

#### **Examples**

```
https://vdo.ninja/?room=roomname&nofullscreenbutton
https://vdo.ninja/?view=streamID&nofsb
https://vdo.ninja/?scene=1&room=roomname&nofullscreenbutton
```

#### **Visual Example**

Without the parameter: The button appears on hover
With the parameter: No button appears

#### **Details**

* Only affects the corner button, not other fullscreen methods
* Users can still double-click videos to go full-window
* F11 and other fullscreen shortcuts still work
* Useful for kiosk modes or simplified interfaces

#### **Notes**

* Helps create cleaner interfaces for public displays
* Reduces accidental clicks in touchscreen environments
* Does not affect the fullscreen button in the control bar (if enabled with [`&fullscreenbutton`](and-fullscreenbutton.md))

#### **Related Parameters**

* [`&fullscreenbutton`](and-fullscreenbutton.md) - Adds F11 fullscreen button to control bar
* [`&nocontrols`](and-nocontrols.md) - Hides all control buttons
* [`&hidemenu`](../design-parameters/and-hidemenu.md) - Hides the menu button




---
description: Hides the hang-up button
---

# \&nohangupbutton

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&nohub`

## Details

This option hides the hang-up button, so it can't be accidentally clicked.

.png>)

## Related

{% content-ref url="../../viewers-settings/nomicbutton.md" %}
[nomicbutton.md](../../viewers-settings/nomicbutton.md)
{% endcontent-ref %}

{% content-ref url="../../viewers-settings/and-novideobutton.md" %}
[and-novideobutton.md](../../viewers-settings/and-novideobutton.md)
{% endcontent-ref %}




---
description: Blocks outbound publishing connections
---

# \&nopush

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&noseed`
* `&viewonly`
* `&viewmode`

## Details

To help avoid some types of connections showing up when using [`&showall`](../design-parameters/and-showall.md), I've also added a `&nopush` mode, which blocks outbound publishing connections. This acts a bit like a `&scene=1` link, so unless [`&showall`](../design-parameters/and-showall.md) is added, you'll need to use the IFRAME API to show/hide videos in it.

## Related

{% content-ref url="../design-parameters/and-showall.md" %}
[and-showall.md](../design-parameters/and-showall.md)
{% endcontent-ref %}




---
description: Post a snapshot of your local camera to a HTTPS/POST URL
---

# \&postimage

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&postimage=https%3A%2F%2Ftemp.vdo.ninja%2F`

| Value                             | Description     |
| --------------------------------- | --------------- |
| `https%3A%2F%2Ftemp.vdo.ninja%2F` | URL-encoded URL |

## Details

Added an option to post a snapshot of your local camera to a HTTPS/POST URL (blob/jpeg).

`https://vdo.ninja/?postimage=URL_TO_POST_IMAGE_TO_AS_BLOCK&postinterval=INTERVAL_IN_SEC`

So, for example:

[`https://vdo.ninja/?postimage=https%3A%2F%2Ftemp.vdo.ninja%2F&postinterval=30&push&wc`](https://vdo.ninja/?postimage=https%3A%2F%2Ftemp.vdo.ninja%2F\&postinterval=30\&push\&wc)\
posts to a sample test server I have up. The URL is URL encoded, but not always necessary. If posting to my test server, the image can be accessed at `https://temp.vdo.ninja/images/STREAMID.jpg`.\
There's caching enabled mind you, so you'll want to post-fix the current timestamp to the URL to disable that per request.

For example: [`https://temp.vdo.ninja/images/yiMkpMg.jpg?t=3412341234`](https://temp.vdo.ninja/images/yiMkpMg.jpg?t=3412341234)&#x20;

This feature could be useful to checking out a stream before actually connecting to it, as that's my intent with it, but it is also something you can use with Octoprint, where you need an IP camera jpeg source as input.

## Related

{% content-ref url="and-postinterval.md" %}
[and-postinterval.md](and-postinterval.md)
{% endcontent-ref %}

{% content-ref url="../video-parameters/and-slideshow.md" %}
[and-slideshow.md](../video-parameters/and-slideshow.md)
{% endcontent-ref %}




---
description: Time interval in seconds for &postimage
---

# \&postinterval

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&postinterval=20`

| Value   | Description     |
| ------- | --------------- |
| (value) | time in seconds |

## Details

Added an option to post a snapshot of your local camera to a HTTPS/POST URL (blob/jpeg).

`https://vdo.ninja/?postimage=URL_TO_POST_IMAGE_TO_AS_BLOCK&postinterval=INTERVAL_IN_SEC`

So, for example:

[`https://vdo.ninja/?postimage=https%3A%2F%2Ftemp.vdo.ninja%2F&postinterval=30&push=testID1&wc`](https://vdo.ninja/?postimage=https%3A%2F%2Ftemp.vdo.ninja%2F\&postinterval=30\&push=testID1\&wc)\
posts to a sample test server I have up. The URL is URL encoded, but not always necessary. If posting to my test server, the image can be accessed at `https://temp.vdo.ninja/images/STREAMID.jpg`.\
There's caching enabled mind you, so you'll want to post-fix the current timestamp to the URL to disable that per request.

For example: [`https://temp.vdo.ninja/images/yiMkpMg.jpg?t=3412341234`](https://temp.vdo.ninja/images/yiMkpMg.jpg?t=3412341234)&#x20;

This feature could be useful to checking out a stream before actually connecting to it, as that's my intent with it, but it is also something you can use with Octoprint, where you need an IP camera jpeg source as input.

## Related

{% content-ref url="and-postimage.md" %}
[and-postimage.md](and-postimage.md)
{% endcontent-ref %}




---
description: Adds a built-in basic controller to control PowerPoint
---

# \&powerpoint

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&slides`
* `&pptcontrols`
* `&ppt`

## Details

Adds a built-in basic controller to control PowerPoint.

<div align="left">

<figure><figcaption></figcaption></figure>

</div>

Detailed information on how to control PowerPoint remotely:

{% content-ref url="../../guides/how-to-control-powerpoint-remotely-with-vdo.ninja.md" %}
[how-to-control-powerpoint-remotely-with-vdo.ninja.md](../../guides/how-to-control-powerpoint-remotely-with-vdo.ninja.md)
{% endcontent-ref %}

## Related

{% content-ref url="../../guides/how-to-control-powerpoint-remotely-with-vdo.ninja.md" %}
[how-to-control-powerpoint-remotely-with-vdo.ninja.md](../../guides/how-to-control-powerpoint-remotely-with-vdo.ninja.md)
{% endcontent-ref %}




---
description: >-
  Another security option, for those concerned about random spying of their
  streams
---

# \&prompt

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&approve`
* `&validate`

## Details

After a new peer viewer connection is established, but before the video/audio streams start getting sent to that new viewer, a prompt will appear asking the publisher if they wish to send their stream to that viewer. If they say no, the remote viewer is disconnected and no video/audio is sent to them. If they have [`&label=xxx`](../../general-settings/label.md) added to their view link, that label will appear as the display name. Otherwise, if no label is available, a random ID representing that connection is shown.

There's nothing stopping a disconnected viewer from re-joining and re-asking, causing some grief, and spoofing an identify isn't too hard, but it gives you some control and warning to block unexpected viewers.

In the future, I can add this control to the director, rather than just the senders, and add additional ways to check identities. For now though, it's a start.

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="../setup-parameters/and-password.md" %}
[and-password.md](../setup-parameters/and-password.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-hash.md" %}
[and-hash.md](../../newly-added-parameters/and-hash.md)
{% endcontent-ref %}




---
description: >-
  Will transfer a guest from one room into another, but once transferred, the
  guest will be in Queue mode
---

# \&queuetransfer

Sender-Side Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&qt`

## Details

`&queuetransfer` will transfer a guest from one room into another, but one transferred, the guest will be in Queue mode. So they won't share their video with anyone by the [director](../../viewers-settings/director.md).

## Related

{% content-ref url="../../general-settings/queue.md" %}
[queue.md](../../general-settings/queue.md)
{% endcontent-ref %}




---
description: >-
  Will relay the incoming 'chunked' media stream to others connected to you,
  without transcoding
---

# \&retransmit

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

Added a new experimental option called `&retransmit`; it will relay the incoming '[chunked](../../newly-added-parameters/and-chunked.md)' media stream to others connected to you, without transcoding. In a way, this enables a form of peer to peer to peer broadcasting.\
\
\-- It only works with incoming [`&chunked`](../../newly-added-parameters/and-chunked.md) data streams, however trying to forward more than one chunked stream will break things currently.\
\-- It will disable your own mic/camera from being streamed; when `&retransmit` is used it configures itself as a viewer in a sense.\
\-- Chunked mode has a default play out buffer delay of about 1-second still, but that buffer time does not get passed down to the relayed viewer. There is still some transmission delay that gets introduced though, but it can be very low latency on a series of good computers/network.

### Example p2p2p setup:

```
https://vdo.ninja/?chunked&push=PUBLISHER123
```

This is the source. Notice they are publishing in chunked mode.

```
https://vdo.ninja/?view=PUBLISHER123&retransmit&push=RESTREAMER123
```

This person is both viewing the video, but also relaying.

```
https://vdo.ninja/?view=RESTREAMER123
```

This person is viewing the stream from the relayed chunked stream; p2p2p. They don't know they are getting a relayed stream.

{% hint style="info" %}
This feature is just for fun at the moment. It's does not do automatic p2p2p broadcasting, as you still need to manually customize who sees what, and chunked mode isn't compatible with all browsers/devices yet.
{% endhint %}

## Related

{% content-ref url="../../newly-added-parameters/and-chunked.md" %}
[and-chunked.md](../../newly-added-parameters/and-chunked.md)
{% endcontent-ref %}




---
description: Forces the screen-share button to appear for guests
---

# \&screensharebutton

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&ssb`

## Details

Forces the screen-share button to appear for guests.

The screen share button will show even if they are on an incompatible device, using [`&nosettings`](../../source-settings/and-nosettings.md), or using [`&webcam`](../../source-settings/and-webcam.md).

 (2).png>)

## Related

{% content-ref url="../../source-settings/screenshare.md" %}
[screenshare.md](../../source-settings/screenshare.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-nosettings.md" %}
[and-nosettings.md](../../source-settings/and-nosettings.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-webcam.md" %}
[and-webcam.md](../../source-settings/and-webcam.md)
{% endcontent-ref %}




---
description: >-
  An option to explicitly list what &sensor data you want to capture and
  transmit
---

# \&sensorfilter

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&sensorsfilter`
* `&filtersensor`
* `&filtersensors`

## Options

Example: `&sensorfilter=gyro`

<table><thead><tr><th width="232">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>gyro</code></td><td>gyroscopic</td></tr><tr><td><code>lin</code></td><td>-</td></tr><tr><td><code>acc</code></td><td>accelerometer</td></tr><tr><td><code>mag</code></td><td>magnetometer</td></tr><tr><td><code>pos</code></td><td>-</td></tr><tr><td><code>ori</code></td><td>-</td></tr></tbody></table>

## Details

Added a new option to explicitly list what sensor data you want to capture and transmit, when using [`&sensor`](../../source-settings/sensor.md)`&sensorfilter=gyro,lin,acc,mag,pos,ori`. For the above demo, you can use `&sensorfilter=pos,lin` to just send the data you need, reducing the load on the phone/network.

## Related

{% content-ref url="../../source-settings/sensor.md" %}
[sensor.md](../../source-settings/sensor.md)
{% endcontent-ref %}




---
description: Displays the total number of p2p connections of a remote stream
---

# \&showconnections

Viewer-Side Option! / Director Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md), [`&director`](../../viewers-settings/director.md))

## Details

`&showconnections` will display the total number of p2p connections of a remote stream. Works with the director's room and the automixer. Might help give comfort over privacy/security during a stream.

Total number of p2p remote connections (viewers) of a stream source will also appear in the stats menu, even without `&showconnections`. Could be useful for debugging CPU/bandwidth issues.

Connections may represent video/audio streams, or just a data-connection. Meshcast-hosted streams might not be accounted for, depending on how the viewer is connecting.

 (4) (1).png>)

## Related

{% content-ref url="../../source-settings/and-maxconnections.md" %}
[and-maxconnections.md](../../source-settings/and-maxconnections.md)
{% endcontent-ref %}




---
description: Tells the director which slot the guest should prefer to be in
---

# \&slot

Sender-Side Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&slot=4`

| Value           | Description                          |
| --------------- | ------------------------------------ |
| (integer value) | the slot guest should be assigned to |

## Details

`&slot=N` is a guest side property (sender side). It just tells the director ([Mixer App](../../steves-helper-apps/mixer-app.md) / [`&slotmode`](../director-parameters/and-slotmode.md)) which slot the guest should prefer to be in, if slots are being auto-assigned. If the desired slot is already taken, then that guest will then not be assign a slot. If the guest was assigned a slot by the [director](../../viewers-settings/director.md), refreshing will keep the assign slot, and the URL-specified slot preference will be ignored.

## Related

{% content-ref url="../director-parameters/and-slotmode.md" %}
[and-slotmode.md](../director-parameters/and-slotmode.md)
{% endcontent-ref %}

{% content-ref url="../../steves-helper-apps/mixer-app.md" %}
[mixer-app.md](../../steves-helper-apps/mixer-app.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-slots.md" %}
[and-slots.md](../../newly-added-parameters/and-slots.md)
{% endcontent-ref %}




---
description: Positions the countdown timer
---

# \&timer

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md), [`&director`](../../viewers-settings/director.md))

## Options

Example: `&timer=5`

<table><thead><tr><th width="232">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code> - <code>9</code></td><td>Shows the current countdown timer as in the graphic below. Each option specifies where the countdown timer will appear on the screen</td></tr><tr><td><code>2</code> | (no value given)</td><td>Shows the countdown timer in the top center</td></tr></tbody></table>

 (5).png>)

## Details

`&timer=N` can be used to position where the countdown timer is positioned on a guest's window. Default is still center top but a value of 1 to 9 can be be passed to change positions.

You can enable the countdown as a director via the room settings.\
 (4) (1).png>)

The director has a button that lets them also enable a global count-down timer. Holding `CTRL + click` will let the director pause the timer. If someone joins the room or reloads, the timer will also be reloaded, in sync. Button also in the room settings menu.

This count down timer is the same concept as the per-guest timer the director already has, and will actually conflict with it if both are used, since it uses the same state/variable to keep track of time remaining.

The director will see the global count down timer also; it will just be a bit smaller on screen.

## Related

{% content-ref url="and-clock.md" %}
[and-clock.md](and-clock.md)
{% endcontent-ref %}




---
description: A token for invite/scene links to determine whose the director of a room
---

# \&token

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Options

Example: `&token=5eb5e63ee4d9ba06`

<table><thead><tr><th width="306">Value</th><th>Description</th></tr></thead><tbody><tr><td>(alphanumeric-characters only)</td><td>a token for invite/scene links to determine whose the director of a room</td></tr></tbody></table>

## Details

When using [`&maindirectorpassword`](../director-parameters/and-maindirectorpassword.md) as a director, it will add `&token=xxx` to the invite/scene links.

 (1) (9).png>)

This token is used by the guests to check a remote database server to see who currently 'owns' the token; it persists though, even if the director is not connected.

When using [`&maindirectorpassword`](../director-parameters/and-maindirectorpassword.md) as a director, it tells this database that you are the owner, and it will persist even if you aren't connected to VDO.Ninja. The `&token` tells the guest to ignore other logic about who the director is, instead using the info provided by the token-lookup to determine whose the director.

I may change or revoke this feature, depending on how testing goes this week, as it's rather experimental.

## Related

{% content-ref url="../director-parameters/and-maindirectorpassword.md" %}
[and-maindirectorpassword.md](../director-parameters/and-maindirectorpassword.md)
{% endcontent-ref %}




---
description: >-
  Will load a side-bar with an IFrame embed, with support for YouTube / Twitch /
  Social Stream
---

# \&widget

General Option! / Director Option! ([`&director`](../../viewers-settings/director.md), [`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Options

Example: `&widget=https%3A%2F%2Fwww.youtube.com%2Flive_chat%3Fis_popout%3D1%26v%3DORBwkXsUNEs`

<table><thead><tr><th width="208">Value</th><th>Description</th></tr></thead><tbody><tr><td>(URLComponent-encoded URL value)</td><td>load a side-bar with that page as an IFRAME embed</td></tr></tbody></table>

## Details

`&widget` lets you pass a URLComponent-encoded URL value. It will load a side-bar with that page as an IFrame embed, with support for YouTube/Twitch specifically added.

This was designed for Twitch / YouTube / [Social Stream chat](../../steves-helper-apps/social-stream-ninja/), but could in theory work with any CORS-friendly site, such as a third-party web tool.

The director of a room also has the option to enable/disable the widget function for everyone in the room via the room settings menu.

You can encode the URL here:\
[https://www.urlencoder.org/](https://www.urlencoder.org/)

### Changing the width of the widget sidebar

**\&widgetwidth** can be used to set the width of the widget sidebar, as a percentile value.

* eg: `&widgetwidth=30`
* the max width is 50%, with the default already at 25%

### Considerations

* not all domains allow themselves to be embedded into VDO.Ninja
* you cannot use \&css or \&js in conjunction with \&widget, for security purposes

<figure><figcaption></figcaption></figure>

If the director uses `&widget`, it will auto sync that with all guests as they connect. I'll try to find ways to make it easier to resize/minimize in the future.

{% hint style="warning" %}
Widgets and IFrames will fail to load if inserting custom CSS into VDO.Ninja using \&css or \&base64css.  This is done for user security in mind.
{% endhint %}

## Related

{% content-ref url="../../general-settings/chatbutton.md" %}
[chatbutton.md](../../general-settings/chatbutton.md)
{% endcontent-ref %}

{% content-ref url="../../steves-helper-apps/social-stream-ninja/" %}
[social-stream-ninja](../../steves-helper-apps/social-stream-ninja/)
{% endcontent-ref %}




---
description: >-
  Stream ID, create a room, password, labels, groups, devices, auto-start,
  welcoming guests, sharing a website/file
---

# Setup Parameters

They are separated in two groups: [general options](./#general-options) (push and view) and [source side](./#source-side-options) (push) options.

## General options

You can add them to both, source ([`&push`](../../source-settings/push.md)) and viewer ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md) or [`&solo`](../mixer-scene-parameters/and-solo.md)) sides.

<table><thead><tr><th width="234.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../source-settings/push.md"><code>&#x26;push</code></a></td><td>The stream ID that you are publishing with will be the defined value</td></tr><tr><td><a href="../../general-settings/room.md"><code>&#x26;room</code></a></td><td>Sets a room ID for the session to join</td></tr><tr><td><a href="and-password.md"><code>&#x26;password</code></a></td><td>Sets a password to view a stream or to join a room</td></tr><tr><td><a href="../../newly-added-parameters/and-hash.md"><code>&#x26;hash</code></a></td><td>Checks the password</td></tr><tr><td><a href="and-e2ee.md"><code>&#x26;e2ee</code></a>*</td><td>Support for something called "end to end encryption" using "insertable streams"</td></tr><tr><td><a href="../../general-settings/label.md"><code>&#x26;label</code></a></td><td>Sets a display name label</td></tr><tr><td><a href="and-labelsuggestion.md"><code>&#x26;labelsuggestion</code></a></td><td>The same as <a href="../../general-settings/label.md"><code>&#x26;label</code></a>, except it asks the user still for a user name</td></tr><tr><td><a href="and-permaid.md"><code>&#x26;permaid</code></a></td><td>Will save that stream ID to local storage and reuse it every time <code>&#x26;permaid</code> is used without a stream ID</td></tr><tr><td><a href="../../general-settings/and-group.md"><code>&#x26;group</code></a></td><td>Puts guests into sub-groups, so they only see others in the same group</td></tr><tr><td><a href="../../general-settings/and-groupaudio.md"><code>&#x26;groupaudio</code></a></td><td>Tells the system to not filter out audio streams when using <a href="../../general-settings/and-group.md"><code>&#x26;group</code></a></td></tr><tr><td><a href="and-groupview.md"><code>&#x26;groupview</code></a></td><td>The same as <a href="../../general-settings/and-group.md"><code>&#x26;group</code></a>, except it lets you see those groups without actually needing to join them with your mic/camera</td></tr><tr><td><a href="../../newly-added-parameters/and-datamode.md"><code>&#x26;datamode</code></a></td><td>Combines a bunch of flags together; no video, no audio, GUI, etc.</td></tr><tr><td><a href="and-audiooutput.md"><code>&#x26;audiooutput</code></a></td><td>Like <a href="../view-parameters/and-sink.md"><code>&#x26;sink</code></a>, but selects the audio output device</td></tr><tr><td><a href="../view-parameters/and-sink.md"><code>&#x26;sink</code></a></td><td>Outputs the audio to the specified audio output device, rather than the default</td></tr></tbody></table>

\*NEW IN [VERSION 24](../../releases/v24.md)

## Source side options

You have to add them to the source side ([`&push`](../../source-settings/push.md)).

<table><thead><tr><th width="150">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../../source-settings/audiodevice.md"><code>&#x26;audiodevice</code></a></td><td>Pre-configures the selected audio device</td></tr><tr><td><a href="../../source-settings/videodevice.md"><code>&#x26;videodevice</code></a></td><td>Pre-configures the selected video device</td></tr><tr><td><a href="../../newly-added-parameters/and-vdo.md"><code>&#x26;vdo</code></a></td><td>Like <a href="../../source-settings/videodevice.md"><code>&#x26;videodevice</code></a> for selecting a default video device, but you can still choose to change the camera</td></tr><tr><td><a href="../../source-settings/and-device.md"><code>&#x26;device</code></a></td><td>Same as <a href="../../source-settings/audiodevice.md"><code>&#x26;audiodevice</code></a> or <a href="../../source-settings/videodevice.md"><code>&#x26;videodevice</code></a>, but applies to both</td></tr><tr><td><a href="../../source-settings/miconly.md"><code>&#x26;miconly</code></a></td><td>Share audio-only; no video publishing allowed</td></tr><tr><td><a href="and-miconlyoption-alpha.md"><code>&#x26;miconlyoption</code></a></td><td>A mic only button shows if a guest joining a room</td></tr><tr><td><a href="../../newly-added-parameters/and-safemode.md"><code>&#x26;safemode</code></a></td><td>Tries to load the camera/audio with as little possible complexity as possible</td></tr><tr><td><a href="../../source-settings/and-autostart.md"><code>&#x26;autostart</code></a></td><td>Skips the camera/audio device or screenshare selection</td></tr><tr><td><a href="../../source-settings/easyexit.md"><code>&#x26;easyexit</code></a></td><td>Won't ask the user to confirm that they wish to exit or leave the page</td></tr><tr><td><a href="../../source-settings/and-webcam.md"><code>&#x26;webcam</code></a></td><td>Disables screen-sharing as an option</td></tr><tr><td><a href="../../newly-added-parameters/and-webcam2.md"><code>&#x26;webcam2</code></a></td><td>Will show the "Share your Camera" button before asking the user to select camera options</td></tr><tr><td><a href="../../source-settings/screenshare.md"><code>&#x26;screenshare</code></a></td><td>Disables camera-sharing as an option</td></tr><tr><td><a href="../../newly-added-parameters/and-screenshare2.md"><code>&#x26;screenshare2</code></a></td><td>Will show the "Share your Screen" button before asking the user to select screenshare options</td></tr><tr><td><a href="../../source-settings/and-website.md"><code>&#x26;website</code></a></td><td>Only shares a website with viewers</td></tr><tr><td><a href="../../source-settings/and-fileshare.md"><code>&#x26;fileshare</code></a></td><td>Allows the user to select a video or audio file as a source for streaming</td></tr><tr><td><a href="../../source-settings/intro.md"><code>&#x26;intro</code></a></td><td>When combined with the either <a href="../../source-settings/and-webcam.md"><code>&#x26;webcam</code></a> or <a href="../../source-settings/screenshare.md"><code>&#x26;screenshare</code></a>, this option won't auto-load the camera/mic selection page</td></tr><tr><td><a href="../../newly-added-parameters/and-host.md"><code>&#x26;host</code></a></td><td>Shows a pop up to invite more guests to the room</td></tr><tr><td><a href="../../general-settings/tips.md"><code>&#x26;tips</code></a></td><td>Shows a help-screen on the guest joining</td></tr><tr><td><a href="../../newly-added-parameters/and-welcome.md"><code>&#x26;welcome</code></a></td><td>Adds a message the guest will see when joining the room</td></tr><tr><td><a href="and-welcomeb64-alpha.md"><code>&#x26;welcomeb64</code></a>*</td><td>The same as <a href="../../newly-added-parameters/and-welcome.md"><code>&#x26;welcome</code></a>, except this takes an input as a base64 encoded string</td></tr><tr><td><a href="and-welcomeimage.md"><code>&#x26;welcomeimage</code></a></td><td>Lets you specify an image that appears for a few seconds once a guest joins</td></tr><tr><td><a href="and-hangupmessage-alpha.md"><code>&#x26;hangupmessage</code></a>*</td><td>Option for a custom hang-up message</td></tr><tr><td><a href="and-humb64-alpha.md"><code>&#x26;humb64</code></a>*</td><td>The same as <a href="and-hangupmessage-alpha.md"><code>&#x26;hangupmessage</code></a>, except this takes an input as a base64 encoded string</td></tr><tr><td><a href="and-groupmode.md"><code>&#x26;groupmode</code></a></td><td>Added to the URL, when not assigned to a group, you don't hear or see anything</td></tr></tbody></table>

\*NEW IN VERSION 24




---
description: Secure Public Stream Publishing
---

# \&audience

The `&audience` parameter in VDO.Ninja enables secure public stream publishing, ideal for website [embedding (using Iframes)](../../guides/iframe-api-documentation.md) while preventing unauthorized publishing.

### Key Features

* Publishers get a unique publishing token, separate from the stream ID
* Viewers use a different audience token to access the stream
* Publishing requires both stream ID and publishing token
* Maintains compatibility with existing code structure

### Example Usage:

```
# Publisher Link:
https://vdo.ninja/?audience=12345abcPublishingToken&push=JkYwyxy

# Viewer Link:
https://vdo.ninja/?audience=HrDrNy3jiA50QzlU&view=JkYwyxy
```

### Technical Details

* Works with single streams only (not compatible with rooms)
* Password functionality remains mostly intact
* Public audience link appears in header unless `&cleanoutput` is used
* New publishers will establish new P2P connections while maintaining existing ones

### Security Notes

* Keep publishing tokens private and unique
* P2P connections may expose public IP addresses
* Exercise caution with untrusted sources due to potential zero-day exploits
* System automatically identifies roles based on `&view` and `&push` parameters




---
description: Like &sink, but selects the default audio output device
---

# \&audiooutput

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&outputdevice`
* `&od`

## Options

Example: `&audiooutput=Cable_Input`

<table><thead><tr><th width="186">Value</th><th>Description</th></tr></thead><tbody><tr><td>(string value)</td><td>partial string that matches the device's label/name</td></tr><tr><td><code>Cable_Input</code></td><td>will match against "CABLE Input" (VB-Audio Virtual Cable). Use any other string to match against other device names.</td></tr><tr><td>(no value given)</td><td>hides the option to change the output device, including under the settings cog</td></tr></tbody></table>

## Details

`&audiooutput` lets you set the default audio output device, based on its name.

Matches on "string contains", so a partial string of the device name is enough. Use lower case, with underscores replacing special characters or spaces.

[`&sink`](../view-parameters/and-sink.md) takes priority, if used, and [`&sink`](../view-parameters/and-sink.md) is more strict in matching.  While `&audiooutput` matches on the device name, `&sink` matches on the device ID.

`&audiooutput=labelname` is consistent across domains / cookie sessions, while [`&sink=deviceid`](../view-parameters/and-sink.md) isn't.

If the parameter's value is left blank, it hides the option to change the output device, including under the settings cog.

{% hint style="info" %}
Visit [vdo.ninja/devices](https://vdo.ninja/devices) to find the available device IDs and device names on your system.

Device IDs are specific to VDO.Ninja's domain, while device names are not.

This web-based tool will also auto-create links for you, just by clicking on the respective device.
{% endhint %}

You can change the audio output device dynamically via the settings menu.\
.png>)

In Version 22 of VDO.Ninja you can change the audio output device of each video feed individually via `Right-Click -> Audio Destination` on the video feed.\
.png>)

### Electron Capture

You can specify an audio output device via the Electron Capture app's command line using this URL parameter  (when used in conjunction with VDO.Ninja).\
\
Example: \
\
`electron.exe --url="https://vdo.ninja/?view=guest1&outputdevice=mixer_usb"`

## Related

{% content-ref url="../view-parameters/and-sink.md" %}
[and-sink.md](../view-parameters/and-sink.md)
{% endcontent-ref %}




---
description: >-
  Support for something called "end to end encryption" using "insertable
  streams"
---

# \&e2ee

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&director`](../../viewers-settings/director.md))

## Details

There is support for something called "end to end encryption" using "insertable streams" to VDO.Ninja. To use, **add** `&e2ee` **to both the viewer and sender side links**. Can be used in conjunction with [`&password`](and-password.md) to specify a cipher.

More technical details about it:

* VDO.Ninja is already end to end encrypted by default (in peer to peer mode), so this isn't anything of much value to most users.
* In p2p mode, this will double up the encryption on the video/audio stream, which might be useful if your system was compromised by a state actor.
* Uses the browser's built-in AES algo, but there is dedicated JS file for the encryption logic, so you can custom-code to use your own encryption I guess.
* Does NOT work with [Meshcast](../../newly-added-parameters/and-meshcast.md), as I don't have insertable streams working server-side there yet, so there is no E2EE with Meshcast still.
* It can be used with compatible [WHIP/WHEP](../../steves-helper-apps/whip-and-whep-tooling.md) services, but most WHIP/WHEP services won't support insertable streams. Still, some do, and that's probably the main reason why I bothered to add this all in.
* The default crypto key used will be hard coded, public, and not secure, but if you provide a [`&password`](and-password.md) it will use that as the secure cipher phrase instead.
* The encoder and decoder algo will fail-safely, rather than fail-securely; I can change this if needed, but it allows for broader peer compatibility and user friendliness. I have more work to do on visually indicating the state of this all, and to allow for more customization, but I'll wait on that until there is more feedback I guess.
* Not all browsers support this, so in those cases, it may fail safely, if possible; otherwise it will just fail completely.

## Related

{% content-ref url="and-password.md" %}
[and-password.md](and-password.md)
{% endcontent-ref %}




---
description: Added to the URL, when not assigned to a group, you don't hear or see anything
---

# \&groupmode

Sender-Side Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md))

## Details

`&groupmode` changes the way [groups](../../general-settings/and-group.md) work when not in a group.

With `&groupmode` added to your URL, when not assigned to a group, you don't hear or see anything. This also goes for remote participants who are not in a group - you will not see or hear them if they are not in a group, even if you also are not in a group.

The default normally with VDO.Ninja is that if not in a group, you see and hear everyone. This remains true if not using `&groupmode`, even if others in the room are. Others may not be able to see or hear you though, if they have `&groupmode` enabled, and you haven't picked a group. So, `&groupmode` only impacts the local user, and will not impact remote connections.

The [Comms app](../../steves-helper-apps/comms.md) uses `&groupmode` by default.

## Related

{% content-ref url="../../general-settings/and-group.md" %}
[and-group.md](../../general-settings/and-group.md)
{% endcontent-ref %}

{% content-ref url="and-groupview.md" %}
[and-groupview.md](and-groupview.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/and-groupaudio.md" %}
[and-groupaudio.md](../../general-settings/and-groupaudio.md)
{% endcontent-ref %}




---
description: >-
  The same as &group, except it lets you see those groups without actually
  needing to join them with your mic/camera
---

# \&groupview

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Aliases

* `&viewgroup`
* `&gv`

## Options

Example: `&groupview=Groupname`

<table><thead><tr><th width="222.57142857142856">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code></td><td>adds the guest or director to group 1</td></tr><tr><td><code>2</code></td><td>adds the guest or director to group 2</td></tr><tr><td><code>3,4,5,6</code></td><td>adds the guest or director to group 3, 4, 5 and 6</td></tr><tr><td>(string)</td><td>creates/adds the guest or director to a custom group</td></tr></tbody></table>

## Details

`&groupview` is the same as [`&group`](../../general-settings/and-group.md), except it lets you see those groups without actually needing to join them with your mic/camera. (There's no button in the directors/guest view for this, since there isn't a need yet for that.)

You can change the view-only groups via the API (http/IFrame) or using the [Comms app](../../steves-helper-apps/comms.md), which has been updated with buttons for this option. the HTTP documentation: [https://github.com/steveseguin/Companion-Ninja/blob/main/README.md#api-commands](https://github.com/steveseguin/Companion-Ninja/blob/main/README.md#api-commands)

You can now use the HTTP/WSS API to both join and leave a group; not just toggle said state. Both the view-group function and regular group function.

## Related

{% content-ref url="../../general-settings/and-group.md" %}
[and-group.md](../../general-settings/and-group.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/and-groupaudio.md" %}
[and-groupaudio.md](../../general-settings/and-groupaudio.md)
{% endcontent-ref %}

{% content-ref url="and-groupmode.md" %}
[and-groupmode.md](and-groupmode.md)
{% endcontent-ref %}




---
description: Option for a custom hang-up message
---

# \&hangupmessage

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&hum`

## Options

Example: `&hangupmessage=bye`

<table><thead><tr><th width="225"></th><th></th></tr></thead><tbody><tr><td>(URL encoded string)</td><td>the message the guest will see when hanging up</td></tr></tbody></table>

## Details

Option for a custom hang-up message. `&hangupmessage` takes a URL encoded string. So it can be just "bye", or it can be some HTML, as shown in the link.

eg:\
[https://vdo.ninja/?hum=bye%3Cimg%20src%3D%22.%2Fmedia%2Flogo\_cropped.png%22%3E\&push=ZimFGxM](https://vdo.ninja/?hum=bye%3Cimg%20src%3D%22.%2Fmedia%2Flogo_cropped.png%22%3E\&push=ZimFGxM)\
 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>)

## Related

{% content-ref url="and-humb64-alpha.md" %}
[and-humb64-alpha.md](and-humb64-alpha.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-welcome.md" %}
[and-welcome.md](../../newly-added-parameters/and-welcome.md)
{% endcontent-ref %}

{% content-ref url="and-welcomeimage.md" %}
[and-welcomeimage.md](and-welcomeimage.md)
{% endcontent-ref %}




---
description: >-
  The same as &hangupmessage, except this takes an input as a base64 encoded
  string
---

# \&humb64

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&humb64=YnllJTNDaW1nJTIwc3JjJTNEJTIyLiUyRm1lZGlhJTJGbG9nb19jcm9wcGVkLnBuZyUyMiUzRQ==`

<table><thead><tr><th width="257"></th><th></th></tr></thead><tbody><tr><td>(base64 encoded string)</td><td>the message the guest will see when hanging up</td></tr></tbody></table>

## Details

`&humb64` is the same as [`&hangupmessage`](and-hangupmessage-alpha.md), except this new option takes an input as a base64 encoded string. VDO.Ninja will decode the base64 on load.

Base64 values are less likely to get parsed by apps like Slack incorrectly, so safer to share. If feeling lazy, you can also just use [invite.cam](https://invite.cam/), and encode the entire link itself; has a similar effect.

eg:\
[https://vdo.ninja/?push=khnCsjS\&wc\&humb64=YnllJTNDaW1nJTIwc3JjJTNEJTIyLiUyRm1lZGlhJTJGbG9nb19jcm9wcGVkLnBuZyUyMiUzRQ](https://vdo.ninja/?push=khnCsjS\&wc\&humb64=YnllJTNDaW1nJTIwc3JjJTNEJTIyLiUyRm1lZGlhJTJGbG9nb19jcm9wcGVkLnBuZyUyMiUzRQ)

## Related

{% content-ref url="and-hangupmessage-alpha.md" %}
[and-hangupmessage-alpha.md](and-hangupmessage-alpha.md)
{% endcontent-ref %}




---
description: The same as &label, except it asks the user still for a user name
---

# \&labelsuggestion

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&defaultlabel`
* `&ls`

## Options

Example: `&labelsuggestion=Steve`

<table><thead><tr><th width="232">Value</th><th>Description</th></tr></thead><tbody><tr><td>(string)</td><td>Sets the label if the user leaves the prompt blank</td></tr><tr><td>(no value given)</td><td>Asks the guest for a label</td></tr></tbody></table>

## Details

`&labelsuggestion` is the same as [`&label`](../../general-settings/label.md), except it asks the user still for a user name. If they leave it blank or cancel the prompt asking for a name, it will use the default label.\
[https://vdo.ninja/?labelsuggestion=guest\&webcam](https://vdo.ninja/?labelsuggestion=guest\&webcam)

Once the user enters their label, `&label=username` is added to the URL, so if they reload, they won't be asked again for the label. `&label` takes priority over `&labelsuggestion`.

## Related

{% content-ref url="../../general-settings/label.md" %}
[label.md](../../general-settings/label.md)
{% endcontent-ref %}

{% content-ref url="../design-parameters/showlabels.md" %}
[showlabels.md](../design-parameters/showlabels.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-screensharelabel.md" %}
[and-screensharelabel.md](../../newly-added-parameters/and-screensharelabel.md)
{% endcontent-ref %}




---
description: A mic only button shows if a guest joining a room
---

# \&miconlyoption

Sender-Side Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&moo`

## Details

Based on user feedback, I'm testing the concept of a "join with mic-only" button. You can enable it with `&miconlyoption`. It's exactly the same as join with video, except the video device is not selected by default. When used, a mic only button shows if a guest joining a room, and if [`&audiodevice=0`](../../source-settings/audiodevice.md) is not present. Hoping this will give more users courage to click the join button, but if it causes issues, I may revert.\
\
For testing at [https://vdo.ninja/?room=someetestroomhere\&moo](https://vdo.ninja/?room=someetestroomhere\&moo)

## Related

{% content-ref url="../../source-settings/miconly.md" %}
[miconly.md](../../source-settings/miconly.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/audiodevice.md" %}
[audiodevice.md](../../source-settings/audiodevice.md)
{% endcontent-ref %}




---
description: Sets a password to view a stream or to join a room
---

# \&password

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&director`](../../viewers-settings/director.md))

## Aliases

* `&pass`
* `&pw`
* `&p`

## Options

Example: `&password=PASSWORD123`

<table><thead><tr><th width="335">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>prompts you to select a password</td></tr><tr><td>(string)</td><td>1 to 49-characters long: aLphaNumEric-characters; case sensitive.</td></tr></tbody></table>

## Details

To make your stream or your room more secure, you can set a password by adding `&password=xxx` to the URL.

If no password value is provided via the URL parameter, the system will prompt for one when connecting.

 (4).png>)

You will want to add the password value to the URL if loading it into OBS.

Passwords apply to both Stream IDs and Room IDs.

Please use alphanumeric-characters only; spaces or other characters may cause the mechanism to fail.

{% hint style="info" %}
**Passwords are CASE-SENSITIVE**; mobile users should watch-out for auto-capitalization when entering them.
{% endhint %}

Adding [`&hash=HASH_VALUE`](../../newly-added-parameters/and-hash.md) will act as if `&password=PASSWORD` was added.

Use this link to get the hash for the password:\
[https://vdo.ninja/examples/changepass.html](https://vdo.ninja/examples/changepass.html)

## Related

{% content-ref url="../../newly-added-parameters/and-hash.md" %}
[and-hash.md](../../newly-added-parameters/and-hash.md)
{% endcontent-ref %}

{% content-ref url="../../director-settings/codirector.md" %}
[codirector.md](../../director-settings/codirector.md)
{% endcontent-ref %}

{% content-ref url="../settings-parameters/and-prompt.md" %}
[and-prompt.md](../settings-parameters/and-prompt.md)
{% endcontent-ref %}

{% content-ref url="../director-parameters/and-maindirectorpassword.md" %}
[and-maindirectorpassword.md](../director-parameters/and-maindirectorpassword.md)
{% endcontent-ref %}




---
description: >-
  Will save that stream ID to local storage and reuse it every time &permaid is
  used without a stream ID
---

# \&permaid

Sender-Side Option! ([`&room`](../../general-settings/room.md))

## Options

Example: `&permaid=StreamID`

<table><thead><tr><th width="183">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>creates a randomly generated stream ID</td></tr><tr><td>(string)</td><td>1 to 49-characters long: aLphaNumEric-characters; case sensitive.</td></tr></tbody></table>

## Details

If using `&permaid=streamidhere` to specify the stream ID, rather than just [`&push`](../../source-settings/push.md), will save that stream ID to local storage and reuse it every time `&permaid` is used without a stream ID.

You could also just use `&permaid` on its own initially, which will auto assign a unique stream ID and save that generated one to local storage, which makes it easier to use one invite for many users, but have VDO.Ninja manage the stream ID assignments.

If not using `&permaid`, it will just default to using `&push` with a random ID. (this avoids 'stream already in use' mishaps)

## Related

{% content-ref url="../../source-settings/push.md" %}
[push.md](../../source-settings/push.md)
{% endcontent-ref %}




---
description: The same as &welcome, except this takes an input as a base64 encoded string
---

# \&welcomeb64

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&welcome64=SGVsbG8=`

<table><thead><tr><th width="257"></th><th></th></tr></thead><tbody><tr><td>(base64 encoded string)</td><td>the message the guest will see when joining the room</td></tr></tbody></table>

## Details

`&welcome64` is the same as [`&welcome`](../../newly-added-parameters/and-welcome.md), except this new option takes an input as a base64 encoded string. VDO.Ninja will decode the base64 on load.

Base64 values are less likely to get parsed by apps like Slack incorrectly, so safer to share. If feeling lazy, you can also just use [invite.cam](https://invite.cam/), and encode the entire link itself; has a similar effect.

eg:\
[https://vdo.ninja/?push=khnCsjS\&wc\&welcomeb64=SGVsbG8](https://vdo.ninja/?push=khnCsjS\&wc\&welcomeb64=SGVsbG8)

## Related

{% content-ref url="../../newly-added-parameters/and-welcome.md" %}
[and-welcome.md](../../newly-added-parameters/and-welcome.md)
{% endcontent-ref %}




---
description: Lets you specify an image that appears for a few seconds once a guest joins
---

# \&welcomeimage

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&welcomeimg`

## Options

Example: `&welcomeimage=https://vdo.ninja/alpha/media/old_logo.png`

| Value | Description      |
| ----- | ---------------- |
| (URL) | URL of the image |

## Details

`&welcomeimage` lets you specify a welcome image (URL) that appears for a few seconds before fading away once a guest joins.

Example:\
[`https://vdo.ninja/?welcomeimage=https://vdo.ninja/alpha/media/old_logo.png&webcam`](https://vdo.ninja/?welcomeimage=https://vdo.ninja/alpha/media/old\_logo.png\&webcam)

## Related

{% content-ref url="../../newly-added-parameters/and-welcome.md" %}
[and-welcome.md](../../newly-added-parameters/and-welcome.md)
{% endcontent-ref %}

{% content-ref url="and-hangupmessage-alpha.md" %}
[and-hangupmessage-alpha.md](and-hangupmessage-alpha.md)
{% endcontent-ref %}




---
description: Options for setting up TURN and STUN servers
---

# TURN & STUN Parameters

<table><thead><tr><th width="189.1845330133903">Parameter</th><th width="446.4285714285714">Explanation</th></tr></thead><tbody><tr><td><a href="../../general-settings/turn.md"><code>&#x26;turn</code></a></td><td>Lets you specify a custom TURN server or disable all TURN servers</td></tr><tr><td><a href="../../general-settings/stun.md"><code>&#x26;stun</code></a></td><td>Lets you specify a STUN server for webRTC negotiation</td></tr><tr><td><a href="../../newly-added-parameters/and-addstun.md"><code>&#x26;addstun</code></a></td><td>Appends an added stun server</td></tr><tr><td><a href="../../general-settings/and-icefilter.md"><code>&#x26;icefilter</code></a></td><td>Filters ICE candidates</td></tr><tr><td><a href="../../newly-added-parameters/and-proxy.md"><code>&#x26;proxy</code></a></td><td>Forces your computer to try to connect to the handshake service via a different physical network end point and domain name</td></tr><tr><td><a href="../../general-settings/and-relay.md"><code>&#x26;relay</code></a></td><td>Forces TURN relay server into use</td></tr><tr><td><a href="../../source-settings/secure.md"><code>&#x26;secure</code></a></td><td>Disconnects communication with the handshake server as soon as possible and provides verbose feedback</td></tr><tr><td><a href="../../general-settings/and-tcp.md"><code>&#x26;tcp</code></a></td><td>Forces TCP mode</td></tr><tr><td><a href="../../newly-added-parameters/and-tz.md"><code>&#x26;tz</code></a></td><td>Specifies a negative timezone value in minutes for a TURN server</td></tr></tbody></table>




# &lanonly

#### **Description**

Restricts peer-to-peer connections to devices on the same local area network (LAN), blocking all external connections.

#### **General Option**

This parameter attempts to ensure that all WebRTC connections are established only between devices on the same local network.

#### **Usage**

* **`&lanonly`** - Enable LAN-only mode

#### **Examples**

```
https://vdo.ninja/?room=localroom&lanonly
https://vdo.ninja/?push=streamID&lanonly
https://vdo.ninja/?view=streamID&lanonly
```

#### **Details**

* Blocks all public IP addresses for both incoming and outgoing connections
* Disables TURN/STUN servers to prevent external relay
* Still requires internet connection for initial handshake and website access
* Failed external connections will retry but won't establish
* Only allows RFC1918 private IP ranges (192.168.x.x, 10.x.x.x, 172.16-31.x.x)

#### **Technical Implementation**

* Filters ICE candidates to exclude public IPs
* Removes TURN server configuration
* Modifies SDP to prevent external connection attempts
* May not work with WHEP/WHIP protocols

#### **Use Cases**

* Corporate networks requiring internal-only streaming
* Security-conscious deployments
* Testing local network performance
* Avoiding internet bandwidth usage for local streams

#### **Limitations**

* VDO.Ninja server (handshake) still requires internet
* Cannot connect to devices outside your LAN
* May not work with complex network configurations (VLANs, etc.)
* No fallback to TURN if direct connection fails

#### **Notes**

* For fully offline operation, consider self-hosting VDO.Ninja
* Devices must be on the same subnet for connection
* Useful for reducing latency in local productions
* May help with privacy concerns about external IP exposure

#### **Related Parameters**

* [`&relay`](../../general-settings/and-relay.md) - Forces TURN relay (opposite behavior)
* [`&privacy`](../turn-and-stun-parameters/README.md) - Enhanced privacy mode
* [`&icefilter`](../../general-settings/and-icefilter.md) - Custom ICE candidate filtering
* [`&tcp`](../../general-settings/and-tcp.md) - Forces TCP connections




# &privacy

#### **Description**

Enhanced privacy mode that forces TURN relay usage and adds additional privacy protections.

#### **General Option**

This parameter enables stricter privacy settings beyond just using TURN relay, including blocking potentially privacy-compromising features.

#### **Usage**

* **`&privacy`** - Enable enhanced privacy mode

#### **Examples**

```
https://vdo.ninja/?push=streamID&privacy
https://vdo.ninja/?room=roomname&privacy
https://vdo.ninja/?view=streamID&privacy
```

#### **Details**

* Forces all connections through TURN relay servers (hides IP addresses)
* Prompts for confirmation before loading iframes (except trusted sites)
* More restrictive than [`&relay`](../../general-settings/and-relay.md) alone
* Shows warnings even in OBS when iframes try to load
* Trusted sites (YouTube, Twitch, Vimeo) bypass iframe warnings

#### **Privacy Features**

1. **IP Address Protection**: Routes through TURN servers
2. **Iframe Blocking**: Prevents automatic loading of embedded content
3. **Enhanced Warnings**: Shows privacy notices for potential risks
4. **No Direct P2P**: Prevents direct peer connections

#### **Visual Example**

When an iframe tries to load with `&privacy`:

.png>)

#### **Use Cases**

* Streaming with hidden IP addresses
* Corporate environments with strict privacy requirements
* Public streams where location privacy is important
* Preventing tracking through embedded content

#### **Limitations**

* May increase latency due to relay usage
* Some features may be restricted
* Higher bandwidth usage on TURN servers
* Not all embedded content will work

#### **Notes**

* More restrictive than [`&relay`](../../general-settings/and-relay.md)
* Combines multiple privacy features
* Good for high-security scenarios
* May impact performance

#### **Related Parameters**

* [`&relay`](../../general-settings/and-relay.md) - Forces TURN relay (less restrictive)
* [`&nowebsite`](../../source-settings/nowebsite.md) - Completely disables iframe loading
* [`&lanonly`](and-lanonly.md) - Restricts to local network only
* [`&icefilter`](../../general-settings/and-icefilter.md) - Custom ICE filtering




---
description: Changing the bitrate of the outgoing and incoming video and for rooms
---

# Video Bitrate Parameters

They are separated in two groups: [source side](./#source-side-options) (push) options for the sender of the video and [viewer side](./#viewer-side-options) (view) options for the viewer of the video. Some of them are especially for rooms.

## Source side options

You have to add them to the source side ([`&push`](../../source-settings/push.md)).

<table><thead><tr><th width="150">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-outboundvideobitrate.md"><code>&#x26;outboundvideobitrate</code></a></td><td>Target video bitrate and max bitrate for outgoing video streams</td></tr><tr><td><a href="and-maxvideobitrate.md"><code>&#x26;maxvideobitrate</code></a></td><td>Limits the max video bitrate out for this publisher, per stream out</td></tr><tr><td><a href="limittotalbitrate.md"><code>&#x26;limittotalbitrate</code></a></td><td>Limits the total outbound bitrate</td></tr><tr><td><a href="and-controlroombitrate.md"><code>&#x26;controlroombitrate</code></a></td><td>Allows a guest to control their total room video bitrate dynamically from the settings panel (under video settings)</td></tr><tr><td><a href="roombitrate.md"><code>&#x26;roombitrate</code></a></td><td>Limits any guest viewer in the group chat room from pulling the video stream at more than the specified bitrate value</td></tr><tr><td><a href="and-maxbandwidth.md"><code>&#x26;maxbandwidth</code></a></td><td>Judges the available bandwidth of a sender's connection</td></tr></tbody></table>

## **Viewer side options**

You have to add them to the viewer side ([`&room`](../../general-settings/room.md) or [`&view`](../view-parameters/view.md) or [`&scene`](../view-parameters/scene.md) or [`&solo`](../mixer-scene-parameters/and-solo.md)).

<table><thead><tr><th width="150">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="bitrate.md"><code>&#x26;videobitrate</code></a></td><td>Sets the "desired target" bitrate in kbps</td></tr><tr><td><a href="and-totalscenebitrate.md"><code>&#x26;totalscenebitrate</code></a></td><td>Max. video bitrate a scene uses</td></tr><tr><td><a href="totalroombitrate.md"><code>&#x26;totalroombitrate</code></a></td><td>The total bitrate a guest in a room can view video streams with</td></tr><tr><td><a href="and-totalbitrate.md"><code>&#x26;totalbitrate</code></a></td><td>Sets both <a href="and-totalscenebitrate.md"><code>&#x26;totalscenebitrate</code></a> and <a href="totalroombitrate.md"><code>&#x26;totalroombitrate</code></a> flags</td></tr><tr><td><a href="and-zoomedbitrate.md"><code>&#x26;zoomedbitrate</code></a></td><td>Lets you set the target bitrate for a guest when they 'zoom in' (fullscreen) on a video</td></tr><tr><td><a href="optimize.md"><code>&#x26;optimize</code></a></td><td>Video bitrate reduced when the video is not visible in OBS (not active in a scene)</td></tr><tr><td><a href="../../newly-added-parameters/and-screensharebitrate.md"><code>&#x26;screensharebitrate</code></a></td><td>Lets you manually set the video bitrate for screen-shares</td></tr></tbody></table>

## Related

{% content-ref url="../video-parameters/" %}
[video-parameters](../video-parameters/)
{% endcontent-ref %}

{% content-ref url="../../guides/video-bitrate-in-rooms.md" %}
[video-bitrate-in-rooms.md](../../guides/video-bitrate-in-rooms.md)
{% endcontent-ref %}

{% content-ref url="../../guides/video-bitrate-for-push-view-links.md" %}
[video-bitrate-for-push-view-links.md](../../guides/video-bitrate-for-push-view-links.md)
{% endcontent-ref %}




---
description: >-
  Allows a guest to control their total room video bitrate dynamically from the
  settings panel (under video settings)
---

# \&controlroombitrate

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&crb`

## Details

Allows a guest to control their total room video bitrate dynamically from the settings panel (under video settings).

A slider appears in the guest’s settings menu.

This feature could be useful for guests that have limited CPU or Network bandwidth to self-regulate.

Lowering this slider will reduce the video bitrate of incoming video streams.

It will not allow the guest to increase the room bitrate's limits; only lower them.

You need to be a publisher to access this value (as the settings button is needed).

Consider using [`&totalroombitrate`](totalroombitrate.md) if you wish to increase the bitrate higher than the default max of \~ 500-kbps.

<div align="left">

</div>

## Related

{% content-ref url="roombitrate.md" %}
[roombitrate.md](roombitrate.md)
{% endcontent-ref %}

{% content-ref url="totalroombitrate.md" %}
[totalroombitrate.md](totalroombitrate.md)
{% endcontent-ref %}




---
description: Judges the available bandwidth of a sender's connection
---

# \&maxbandwidth

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&maxbandwidth=80`

<table><thead><tr><th width="241">Value</th><th>Description</th></tr></thead><tbody><tr><td>(percentage 1 to 100)</td><td>the connection never uses more than that amount of the available reported bandwidth</td></tr></tbody></table>

## Details

Made a new bitrate option called `&maxbandwidth`, which differs from other commands as it leverages a chromium (chrome/edge/brave/electron) feature to judge the available bandwidth of a sender's connection. Passing a value to it as the sender (a percentage; 1 to 100 ideally), you can try to ensure the connection never uses more than that amount of the available reported bandwidth.

So the notion is, if you want to set the invite link bitrate to 50-mbps, but one guest only has only a 20-mbps connection, `&maxbandwidth=80` will try to limit the bitrate to around 16-mbps. I sometimes will tell people to set the bit rate to about 80% of what their connection can allow, as higher than that can result in some frame stutter when there is packet loss, since the connection lacks headroom to recover. This command will try to do it automatically, for all the viewers of a stream.

My goal here is to use it with the [Mixer App](../../steves-helper-apps/mixer-app.md) or [Versus.cam](../../steves-helper-apps/versus.cam.md), so eSports users can crank out high bitrates with less tinkering per guest. I have no idea how well it will work in practice so far.

The upcoming and standalone replacement vor vdo.ninja/monitor:\
[https://versus.cam/](https://versus.cam/)

## Related

{% content-ref url="and-outboundvideobitrate.md" %}
[and-outboundvideobitrate.md](and-outboundvideobitrate.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-outboundaudiobitrate.md" %}
[and-outboundaudiobitrate.md](../../source-settings/and-outboundaudiobitrate.md)
{% endcontent-ref %}




---
description: Limits the max video bitrate out for this publisher, per stream out
---

# \&maxvideobitrate

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&maxbitrate`
* `&mvb`

## Options

Example: `&maxvideobitrate=8000`

| Value                    | Description                              |
| ------------------------ | ---------------------------------------- |
| (positive integer value) | max allowed video bitrate per stream out |

## Details

Useful if you are a director and you wish to prevent guests from pulling more than 500-kbps (LQ) or 1200-kbps (HQ) when in [broadcast](../view-parameters/broadcast.md) mode.

This is NOT the same as setting the target bitrate as a publisher; this just sets a max limit that viewers can pull video streams at.\
\
Please see [`&totalroombitrate`](totalroombitrate.md) or [`&limittotalbitrate`](limittotalbitrate.md), as well.

{% hint style="info" %}
Set to 600-kbps, 200-kbps, or 80-kbps if the goal is to reduce CPU load also. (2x, 3x, or 4x down-scaling is applied at those bitrate limits).
{% endhint %}

## Related

{% content-ref url="and-outboundvideobitrate.md" %}
[and-outboundvideobitrate.md](and-outboundvideobitrate.md)
{% endcontent-ref %}

{% content-ref url="limittotalbitrate.md" %}
[limittotalbitrate.md](limittotalbitrate.md)
{% endcontent-ref %}

{% content-ref url="bitrate.md" %}
[bitrate.md](bitrate.md)
{% endcontent-ref %}

{% content-ref url="totalroombitrate.md" %}
[totalroombitrate.md](totalroombitrate.md)
{% endcontent-ref %}




---
description: Target video bitrate and max bitrate for outgoing video streams
---

# \&outboundvideobitrate

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&ovb`

## Options

Example: `&outboundvideobitrate=4000`

| Value           | Description        |
| --------------- | ------------------ |
| (integer value) | value will be kbps |

## Details

Target video bitrate and max bitrate for outgoing video streams.

Sets the viewer's bitrate and overrides the [`&videobitrate`](bitrate.md) parameter. It won't override the room's total bitrate parameter, as that's a dynamically set bitrate, so **to get higher bitrate in group rooms you still need to use** [`&totalroombitrate`](totalroombitrate.md).

## Related

{% content-ref url="../../source-settings/and-outboundaudiobitrate.md" %}
[and-outboundaudiobitrate.md](../../source-settings/and-outboundaudiobitrate.md)
{% endcontent-ref %}




---
description: Sets both &totalscenebitrate and &totalroombitrate flags
---

# \&totalbitrate

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&tb`

## Options

Example: `&totalbitrate=3000`

<table><thead><tr><th width="245">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer value)</td><td>max. video bitrate in kbps a scene/room uses</td></tr></tbody></table>

## Details

`&totalbitrate` sets both [`&totalscenebitrate`](and-totalscenebitrate.md) and [`&totalroombitrate`](totalroombitrate.md) flags. Not quite sure how well it will work, but since a scene and a guest are exclusive possibilities, it's a bit of a flexible way to just learn one flag to do it all, as I realize all the options can get confusing.

[`&totalscenebitrate`](and-totalscenebitrate.md) and [`&totalroombitrate`](totalroombitrate.md) limit the total incoming bitrate, dividing up the bandwidth available to each video being played back. There are nuances in differences, with the main one being [`&totalroombitrate`](totalroombitrate.md) is for a guest link and [`&totalscenebitrate`](and-totalscenebitrate.md) is for a scene/view link.

## Related

{% content-ref url="and-totalscenebitrate.md" %}
[and-totalscenebitrate.md](and-totalscenebitrate.md)
{% endcontent-ref %}

{% content-ref url="totalroombitrate.md" %}
[totalroombitrate.md](totalroombitrate.md)
{% endcontent-ref %}




---
description: Max. video bitrate a scene uses
---

# \&totalscenebitrate

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&tsb`
* `&maxtotalscenebitrate`
* `&mtsb`

## Options

Example: `&totalscenebitrate=4000`

| Value           | Description                             |
| --------------- | --------------------------------------- |
| (integer value) | max. video bitrate in kbps a scene uses |

## Details

Mainly added to help offer another way to optimize performance and limit inbound bandwidth used, since why not.

This is similar to [`&totalroombitrate`](totalroombitrate.md), but `&totalscenebitrate` applies to scenes and faux-room scenes instead. That is, it splits the total bitrate available for playback by the number of videos in the scene. It's a way to keep the inbound bitrate below a certain threshold. If [`&videobitrate`](bitrate.md) is also used, [`&videobitrate`](bitrate.md) becomes a max limit on any individual video, so you can set `&totalscenebitrate=6000` and [`&videobitrate=2000`](bitrate.md), to keep all videos below 2-mbps each, but potentially go lower if more than 3 videos are present.

## Related

{% content-ref url="totalroombitrate.md" %}
[totalroombitrate.md](totalroombitrate.md)
{% endcontent-ref %}

{% content-ref url="and-totalbitrate.md" %}
[and-totalbitrate.md](and-totalbitrate.md)
{% endcontent-ref %}

{% content-ref url="bitrate.md" %}
[bitrate.md](bitrate.md)
{% endcontent-ref %}




---
description: >-
  Lets you set the target bitrate for a guest when they 'zoom in' (fullscreen)
  on a video
---

# \&zoomedbitrate

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&zb`

## Options

Example: `&zoomedbitrate=2000`

| Value            | Description                                    |
| ---------------- | ---------------------------------------------- |
| (no value given) | zoomed bitrate = 2500-kbps instead of 600-kbps |
| (integer value)  | zoomed bitrate in kbps                         |

## Details

Lets you set the target bitrate for a guest in a room when they 'zoom in' on a video using the full-window icon in the top-right of a video.

The idea is, you might want to still have a group call, but occasionally share a high resolution screen. This will increase the load a lot on the guest who is being zoomed-in on, but it's an option if increasing [`&totalroombitrate`](totalroombitrate.md) is not acceptable.

Using the flag unset increases the bitrate from 600-kbps to 2500-kbps.

## Related

{% content-ref url="totalroombitrate.md" %}
[totalroombitrate.md](totalroombitrate.md)
{% endcontent-ref %}




---
description: Sets the "desired target" bitrate in kbps
---

# \&videobitrate

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&bitrate`
* `&vb`

## Options

Example: `&videobitrate=6000`

| Value           | Description     |
| --------------- | --------------- |
| (integer value) | bitrate in kbps |

## Details

`&videobitrate` sets the target video bitrate of a video feed in a solo link or the video feeds in a scene.

This parameter is only for scenes and solo links. Use [`&totalroombitrate`](totalroombitrate.md) for example to set up the video bitrate for guests in a room.

{% hint style="info" %}
Default value will target around **2500**-kbps.
{% endhint %}

The maximum achievable bitrate is around 60,000-kbps (60-mbps).

**Lowering** the bitrate can sometimes **reduce CPU load**, **bandwidth**, and **stuttering** issues

You might want to increase the bitrate for game streams, to ensure smooth frame rates.

{% hint style="danger" %}
Not compatible with **Firefox**.
{% endhint %}

## Related

{% content-ref url="../../guides/video-bitrate-for-push-view-links.md" %}
[video-bitrate-for-push-view-links.md](../../guides/video-bitrate-for-push-view-links.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/audiobitrate.md" %}
[audiobitrate.md](../view-parameters/audiobitrate.md)
{% endcontent-ref %}




---
description: Limits the total outbound bitrate
---

# \&limittotalbitrate

Sender-Side Option! / Director Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&director`](../../viewers-settings/director.md))

## Aliases

* `&ltb`

## Options

Example: `&limittotalbitrate=2000` or `&limittotalbitrate=2000,1000`

| Value                    | Description                              |
| ------------------------ | ---------------------------------------- |
| (positive integer value) | max total outbound video bitrate in kbps |
| `1000,500`               | Desktop bitrate, Smartphone bitrate      |

## Details

_Tries_ to limit the total outbound bitrate to some max total value, via the publisher's side. This could be useful if you are broadcasting video as a director to the room, but only have a fixed amount of upload bandwidth or CPU.

`&limittotalbitrate` can now take two values; the second of which gets used if the device is a 'mobile' device, while the first gets used otherwise. ie: `&limittotalbitrate=1000,500`\
Useful if you don't know if the guest is going to join via Desktop or via Smartphone, and you wish to avoid overloading a mobile device.

### Director

When using the `&limittotalbitrate` option as a [director](../../viewers-settings/director.md), the room settings will include a new slider to let you dynamically change that value.

This lets the director set a maximum total bandwidth outbound from them to the guests; useful if you set the total room bitrate to something high. Combined, you can ensure the guests as high quality as possible from you, without causing your OBS RTMP output or whatever to get smashed.

### Mixer App

When using the [Mixer App](../../steves-helper-apps/mixer-app.md) ([vdo.ninja/alpha/mixer](https://vdo.ninja/alpha/mixer)), the `&limittotalbitrate` value was set to 350-kbps before, but now I have it set to 1500-kbps. Guests in the Mixer App should as a result now see the director's broadcast output in 3x higher quality now, for better or worse. I may adjust the default value in the mixer based on user issue reports.

The slider doesn't appear if not using the `&limittotalbitrate` value in the URL (or if not using the Mixer App). It's just too confusing to explain to include it by default.

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="totalroombitrate.md" %}
[totalroombitrate.md](totalroombitrate.md)
{% endcontent-ref %}

{% content-ref url="roombitrate.md" %}
[roombitrate.md](roombitrate.md)
{% endcontent-ref %}




---
description: >-
  Video bitrate reduced when the video is not visible in OBS (not active in a
  scene)
---

# \&optimize

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&optimize=1000`

| Value            | Description                                                           |
| ---------------- | --------------------------------------------------------------------- |
| (integer value)  | value in kbps                                                         |
| (no value given) | 600-kbps                                                              |
| `0`              | disables the video track when not considered visible in a scene (OBS) |

## Details

`&optimize` reduces the video bitrate to 600-kbps when the video is not visible in OBS (not active in a scene). This is mainly there to help with reducing load for OBS and for guests. It can take a few seconds for the bitrate to ramp back up after it becomes active again.

### Consider using \&optimize=0&#x20;

As of VDO.NInja v26, \&optimize=0 will make it so that a remote guest will not connect to a manual scene (\&scene=1, for example) until the director manually adds the guest to the scene.

What this means is that you can have each guest assigned to their own scene (eg: 1 to 8) and have each be treated like a \&solo link, so long as you never add more than one at a time and wait for the previous guest to disconnect.

Normally, otherwise, if you had 8 guests in a room, and each had their own scene, without \&optimize=0 set, each scene would still have each of those guests connected; so each guest would be connecting 7 additional times, without it being needed. This reduces stress on the VDO.Ninja servers, but also avoids connection issues when there are perhaps dozens of users in a room.\
\
While adding a guest to a scene this way takes about a second, for the connection to be made, once added you can remove and add the guest back quickly, as they stay connected at that point. \&optimize=0 will also, as before, mute the video/audio tracks, lowering the video/audio bitrate of those tracks to 0, when not needed.

Pausing and resuming a video/audio track does take a split second to do, and it may result in temporarily low quality video after being enabled, it you don't intend to add/remove guests frequently to a scene, it is highly recommended you use it.\
\
The only time you shouldn't use \&optimize=0 is perhaps when you have just a single group scene, and you prefer speed and quality as you add/remove guests to the room. This might also be the case if using the \&activespeaker mode, where guests are hidden and removed when not active speaking.\

{% hint style="warning" %}
This does not work with iPhone-sourced video streams.
{% endhint %}

## Related

{% content-ref url="bitrate.md" %}
[bitrate.md](bitrate.md)
{% endcontent-ref %}




---
description: >-
  Limits any guest viewer in the group chat room from pulling the video stream
  at more than the specified bitrate value
---

# \&roombitrate

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&roomvideobitrate`
* `&rbr`

## Options

Example: `&roombitrate=200`

| Value                         | Description                                                    |
| ----------------------------- | -------------------------------------------------------------- |
| `0`                           | disables access to your video for other guests in a group room |
| (some positive integer value) | max. allowed bitrate                                           |

## Details

Limits any guest viewer in the group chat room from pulling the video stream at more than the specified bitrate value.

Does not impact what the director sees and does not limit the quality of what OBS has access to.\
This is like [`&maxvideobitrate`](and-maxvideobitrate.md), but `&roombitrate` only applies to fellow group room guests.\
Practically, a guest normally won't pull more than 1200-kbps and that's only if they click the HQ full-window button.

{% hint style="info" %}
Set to 600-kbps, 200-kbps, or 80-kbps if the goal is to reduce CPU load. (2x, 3x, or 4x down-scaling is applied at those bitrate limits)
{% endhint %}

## Related

{% content-ref url="totalroombitrate.md" %}
[totalroombitrate.md](totalroombitrate.md)
{% endcontent-ref %}

{% content-ref url="and-controlroombitrate.md" %}
[and-controlroombitrate.md](and-controlroombitrate.md)
{% endcontent-ref %}

{% content-ref url="and-maxvideobitrate.md" %}
[and-maxvideobitrate.md](and-maxvideobitrate.md)
{% endcontent-ref %}

{% content-ref url="../../guides/video-bitrate-in-rooms.md" %}
[video-bitrate-in-rooms.md](../../guides/video-bitrate-in-rooms.md)
{% endcontent-ref %}




---
description: The total bitrate a guest in a room can view video streams with
---

# \&totalroombitrate

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))\
Director Option! ([`&director`](../../viewers-settings/director.md))

## Aliases

* `&totalroomvideobitrate`
* `&trb`

## Options

Example: `&totalroombitrate=4000` or `&totalroombitrate=2000,1000`

| Value           | Description                                    |
| --------------- | ---------------------------------------------- |
| (integer value) | set this to be the total combined room bitrate |
| `1000,500`      | Desktop bitrate, Smartphone bitrate            |

## Details

The total bitrate a guest in a room can view video streams with; their combined bitrate total of all inbound video streams.

{% hint style="info" %}
The default value is 500-kbps.
{% endhint %}

Split between the number of streams that guest is viewing.

So for example, with 6-guests in a room, the default of 500-kbps will have each guest requesting 100-kbps from each other. 5 streams x 100-kbps.

### Two values

`&totalroombitrate` can take two values; the second of which gets used if the device is a 'mobile' device, while the first gets used otherwise. ie: `&totalroombitrate=1000,500`\
Useful if you don't know if the guest is going to join via Desktop or via Smartphone, and you wish to avoid overloading a mobile device.

{% hint style="info" %}
Please note the difference between `&totalroombitrate` and [`&totalscenebitrate`](and-totalscenebitrate.md). `&totalroombitrate`controls what the total bitrate for guests in a room is limited to. [`&totalscenebitrate`](and-totalscenebitrate.md), on the other hand, is what you will want if you want to do the same for a view-link, added to OBS, for example.
{% endhint %}

### Limitations

Total room bitrate does not override any limits other guests in the room may have set to limit their outbound bandwidth.

Mobile devices are also coded to typically refuse requests of higher bitrates by other guests, even with a high total room bitrate set. Mobile devices will quickly overheat if publishing to many guests using software-encoding, so they are treated somewhat special.

In general, setting a high total room bitrate will increase the CPU and network requirements of the group room. Higher bitrates mean higher resolution, which means higher compute loads, so some computers may become overloaded. The default of 500-kbps seems low, but it was carefully selected to reduce such issues as much as reasonable.

Consider using [`&broadcast`](../view-parameters/broadcast.md), combined with either a powerful host computer or a service like [Meshcast.io](https://meshcast.io/) if you'd like to share high quality video to a larger room. A high total room bitrate value may cause severe problems in large rooms or on slower computers.

### Director's ability to control

If the director joins the room, they automatically set the default total room bitrate for every guest that joins the room; guests will match the director's value. This feature may even override the URL-parameter that any guest might have added to their URL already, depending on version of VDO.Ninja. (still being tweaked based on user feedback)

The director can also dynamically change their total room bitrate value using a slider that appears when pressing the room-settings button in the lower control bar. This will instantly change the total room bitrate value for all guests.

 (1).png>)

There is a toggle in the director's room which adds `&trb=2000` to the guest's invite link.

 (1).png>)

## Related

{% content-ref url="roombitrate.md" %}
[roombitrate.md](roombitrate.md)
{% endcontent-ref %}

{% content-ref url="and-totalbitrate.md" %}
[and-totalbitrate.md](and-totalbitrate.md)
{% endcontent-ref %}

{% content-ref url="and-controlroombitrate.md" %}
[and-controlroombitrate.md](and-controlroombitrate.md)
{% endcontent-ref %}

{% content-ref url="../../guides/video-bitrate-in-rooms.md" %}
[video-bitrate-in-rooms.md](../../guides/video-bitrate-in-rooms.md)
{% endcontent-ref %}




---
description: >-
  Resolution, FPS, effects, self preview, mute video, PTZ, codec, buffer,
  broadcast, scale
---

# Video Parameters

They are separated in three groups: [general options](./#general-options) (push and view), [source side](./#source-side-options) (push) options and [viewer side](./#viewer-side-options) (view) options.

If you want to change the bitrate:\
[video-bitrate-parameters](../video-bitrate-parameters/ "mention")

## General options

You can add them to both, source ([`&push`](../../source-settings/push.md)) and viewer ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md) or [`&solo`](../mixer-scene-parameters/and-solo.md)) sides.

<table><thead><tr><th width="322.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-blind.md"><code>&#x26;blind</code></a></td><td>Video playback is disabled</td></tr></tbody></table>

## Source side options

You have to add them to the source side ([`&push`](../../source-settings/push.md)).

<table><thead><tr><th width="150">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-quality.md"><code>&#x26;quality</code></a></td><td>Presets the quality setting for a guest</td></tr><tr><td><a href="../../source-settings/and-width.md"><code>&#x26;width</code></a></td><td>Sets the maximum width of the video allowed in pixels</td></tr><tr><td><a href="../../source-settings/and-height.md"><code>&#x26;height</code></a></td><td>Sets the maximum height of the video allowed in pixels</td></tr><tr><td><a href="and-aspectratio.md"><code>&#x26;aspectratio</code></a></td><td>Changes the aspect ratio on the publisher side</td></tr><tr><td><a href="and-contenthint.md"><code>&#x26;contenthint</code></a></td><td><code>=motion</code> prioritizes resolution;<br><code>=detail</code> prioritizes frame rate</td></tr><tr><td><a href="../../newly-added-parameters/and-mediasettings.md"><code>&#x26;mediasettings</code></a></td><td>Adds the option to change the video and audio settings dynamically via the settings menu</td></tr><tr><td><a href="../../newly-added-parameters/and-noscale.md"><code>&#x26;noscale</code></a></td><td>Disables the publishing resolution from being capped</td></tr><tr><td><a href="and-fps.md"><code>&#x26;fps</code></a></td><td>Sets the maximum frame rate of the video in frames per second</td></tr><tr><td><a href="../../source-settings/and-maxframerate.md"><code>&#x26;maxframerate</code></a></td><td>Like <a href="and-fps.md"><code>&#x26;fps</code></a>, except it will allow for lower frame rates if the specific frame rate requested failed</td></tr><tr><td><a href="../../source-settings/effects.md"><code>&#x26;effects</code></a></td><td>Applies effects to the video/audio feeds</td></tr><tr><td><a href="../../newly-added-parameters/and-effectvalue.md"><code>&#x26;effectvalue</code></a></td><td>Sets the amount of blur or effect applied</td></tr><tr><td><a href="and-imagelist.md"><code>&#x26;imagelist</code></a></td><td>Can be used to pass a list of background images via the URL</td></tr><tr><td><a href="and-avatar.md"><code>&#x26;avatar</code></a></td><td>Adds the ability to select an image, instead of a video device</td></tr><tr><td><a href="../../source-settings/fullscreen.md"><code>&#x26;fullscreen</code></a></td><td>The preview video will be fullscreen</td></tr><tr><td><a href="../../source-settings/and-preview.md"><code>&#x26;showpreview</code></a></td><td>Forces the guest to have a self-preview</td></tr><tr><td><a href="../../source-settings/and-minipreview.md"><code>&#x26;minipreview</code></a></td><td>Mini self-preview at the top right corner</td></tr><tr><td><a href="and-minipreview-1.md"><code>&#x26;minipreviewoffset</code></a></td><td>Used to position where the mini preview is located by default on screen</td></tr><tr><td><a href="and-largepreview.md"><code>&#x26;largepreview</code></a>*</td><td>Will disable the mini-preview functionality</td></tr><tr><td><a href="../../source-settings/and-nopreview.md"><code>&#x26;nopreview</code></a></td><td>Disables the local self-preview</td></tr><tr><td><a href="../../newly-added-parameters/and-hideguest.md"><code>&#x26;hideguest</code></a></td><td>Has a guest join a room not visible to others</td></tr><tr><td><a href="../../source-settings/and-videomute.md"><code>&#x26;videomute</code></a></td><td>Auto mutes guest's video</td></tr><tr><td><a href="../../source-settings/ptz.md"><code>&#x26;ptz</code></a></td><td>Enables pan/tilt control of the device, if compatible</td></tr><tr><td><a href="../view-parameters/webp.md"><code>&#x26;webp</code></a></td><td>Custom video codec for broadcasts</td></tr><tr><td><a href="../view-parameters/webpquality.md"><code>&#x26;webpquality</code></a></td><td>Quality setting for the <a href="../view-parameters/webp.md"><code>&#x26;webp</code></a> option</td></tr></tbody></table>

\*NEW IN [VERSION 24](../../releases/v24.md)

## **Viewer side options**

You have to add them to the viewer side ([`&room`](../../general-settings/room.md) or [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md)or [`&solo`](../mixer-scene-parameters/and-solo.md)).

<table><thead><tr><th width="233.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="../view-parameters/scale.md"><code>&#x26;scale</code></a></td><td>Scales the video resolution of the inbound video by the given percent</td></tr><tr><td><a href="../view-parameters/dpi.md"><code>&#x26;dpi</code></a></td><td>Overrides the automatically selected Device Pixel Ratio</td></tr><tr><td><a href="and-sharper.md"><code>&#x26;sharper</code></a></td><td>Should 'up to' double the amount of playback video resolution</td></tr><tr><td><a href="and-viewwidth.md"><code>&#x26;viewwidth</code></a></td><td>Does the same thing as <a href="../view-parameters/scale.md"><code>&#x26;scale</code></a> but you pass the width in pixels</td></tr><tr><td><a href="and-viewheight.md"><code>&#x26;viewheight</code></a></td><td>Does the same thing as <a href="../view-parameters/scale.md"><code>&#x26;scale</code></a> but you pass the height in pixels</td></tr><tr><td><a href="../view-parameters/codec.md"><code>&#x26;codec</code></a></td><td>Sets the codec to encode the video</td></tr><tr><td><a href="../../newly-added-parameters/and-h264profile.md"><code>&#x26;h264profile</code></a></td><td>OpenH264 software encoding will be used</td></tr><tr><td><a href="../view-parameters/buffer.md"><code>&#x26;buffer</code></a></td><td>Sets the video buffer</td></tr><tr><td><a href="and-buffer2.md"><code>&#x26;buffer2</code></a></td><td>Same as <a href="../view-parameters/buffer.md"><code>&#x26;buffer</code></a>, but instead includes the round-trip-time</td></tr><tr><td><a href="../view-parameters/fadein.md"><code>&#x26;fadein</code></a></td><td>Has videos fade in smoothly</td></tr><tr><td><a href="../view-parameters/broadcast.md"><code>&#x26;broadcast</code></a></td><td>A useful flag to allow the director to present their own video to the group, often used in conjunction with a virtual webcam or Meshcast. It allows for larger groups rooms by reducing load on guests</td></tr><tr><td><a href="and-directoronly.md"><code>&#x26;directoronly</code></a></td><td>A useful flag to allow the director to present their own video to the group, often used in conjunction with a virtual webcam or Meshcast. It allows for larger groups rooms by reducing load on guests</td></tr><tr><td><a href="novideo.md"><code>&#x26;showonly</code></a></td><td>Only shows any stream ID that is listed</td></tr><tr><td><a href="and-novideo.md"><code>&#x26;novideo</code></a></td><td>Disables all video playback on the local computer</td></tr><tr><td><a href="and-nodirectorvideo.md"><code>&#x26;nodirectorvideo</code></a>*</td><td>Disables all video playback from room directors</td></tr><tr><td><a href="and-slideshow.md"><code>&#x26;slideshow</code></a></td><td>Plays video back as a series of full-window images</td></tr></tbody></table>

\*NEW IN [VERSION 24](../../releases/v24.md)

## Related

{% content-ref url="../video-bitrate-parameters/" %}
[video-bitrate-parameters](../video-bitrate-parameters/)
{% endcontent-ref %}




---
description: Changes the aspect ratio on the publisher side
---

# \&aspectratio

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&ar`

## Options

Example: `&aspectratio=1.77777` or `&aspectratio=landscape`

| Value            | Description                     |
| ---------------- | ------------------------------- |
| `landscape`      | aspect ratio of 16:9 (1.777777) |
| `portrait`       | aspect ratio of 9:16 (0.5625)   |
| `square`         | aspect ratio of 1:1 (1)         |
| `1.33333`        | aspect ratio of 4:3             |
| (decimal number) | aspect ratio                    |

## Details

`&aspectratio` changes the aspect ratio on the publisher side. Floating point value; 1.777777 is common; not supported by all browsers.

[https://vdo.ninja/?webcam\&aspectratio=1.33333](https://vdo.ninja/?webcam\&aspectratio=1.33333)\
 (1).png>)

You can also change the aspect ratio via the video settings menu. (1) (1).png>)

If using `&aspectratio`, it will keep the [height](../../source-settings/and-height.md) constant, and vary width, unless [`&width`](../../source-settings/and-width.md) is set, which will then be the fixed constant.

### Screen-share

`&aspectratio` works with screen-shares, so you can force crop an incoming screen-share to be a certain aspect ratio. If [`&screenshareaspectratio`](../screen-share-parameters/and-screenshareaspectratio.md) is used it will apply to just screen-shares. If [`&screenshareaspectratio`](../screen-share-parameters/and-screenshareaspectratio.md) does not have a value passed, it's assumed to be set as "default", which overrides `&aspectratio` option, if used also.

## Related

{% content-ref url="../screen-share-parameters/and-screenshareaspectratio.md" %}
[and-screenshareaspectratio.md](../screen-share-parameters/and-screenshareaspectratio.md)
{% endcontent-ref %}

{% content-ref url="and-quality.md" %}
[and-quality.md](and-quality.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-width.md" %}
[and-width.md](../../source-settings/and-width.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-height.md" %}
[and-height.md](../../source-settings/and-height.md)
{% endcontent-ref %}




---
description: Adds the ability to select an image, instead of a video device
---

# \&avatar

Sender-Side Option! ([`&push`](../../source-settings/push.md))\
\* on [https://vdo.ninja/beta/](https://vdo.ninja/beta/) and [https://vdo.ninja/alpha/](https://vdo.ninja/alpha/)

## Options

Example: `&avatar=default`

<table><thead><tr><th width="190">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>adds the ability to select an image, instead of a video device</td></tr><tr><td>(encoded URL)</td><td>pre-selects the chosen image as an avatar</td></tr><tr><td><code>default</code></td><td>will pre-select the default avatar, rather than leaving it un-selected</td></tr></tbody></table>

## Details

`&avatar` adds the ability to select an image, instead of a video device. The image will trigger when the video is muted or no video device is selected. A default avatar image is provided, but you can select your own from disk. `&avatar=default` will pre-select the default avatar, rather than leaving it un-selected.

 (1) (1).png>)

You can toggle it for the guest's invite link in the director's room:\
 (1).png>)

You can encode your URL here:\
[https://www.urlencoder.org/](https://www.urlencoder.org/)

### Director

Choosing the default avatar / placeholder image is activated for the director on default

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="../newly-added-parameters/and-waitimage.md" %}
[and-waitimage.md](../newly-added-parameters/and-waitimage.md)
{% endcontent-ref %}

{% content-ref url="../design-parameters/and-bgimage.md" %}
[and-bgimage.md](../design-parameters/and-bgimage.md)
{% endcontent-ref %}




---
description: Video playback is disabled
---

# \&blind

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md))

## Details

Video playback is disabled in VDO.Ninja.

 (3) (1).png>)

## Related

{% content-ref url="../../general-settings/deafen.md" %}
[deafen.md](../../general-settings/deafen.md)
{% endcontent-ref %}




---
description: Same as &buffer, but instead includes the round-trip-time
---

# \&buffer2

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&buffer2=500`

| Value           | Description |
| --------------- | ----------- |
| (numeric value) | delay in ms |

## Details

`&buffer2=500` is the same as [`&buffer`](../view-parameters/buffer.md), but instead also tells the system to include the round-trip-time in the buffer delay calculation. This way 500-ms of buffer on a connection that has a 200ms ping time will result in a smaller 300-ms buffer, leading to an end-to-end playout delay of \~500ms.

It won't work that well with [Meshcast](../../newly-added-parameters/and-meshcast.md).

It's not super precise, but on a stable connection maybe within 20-ms of flux?

## Related

{% content-ref url="../view-parameters/buffer.md" %}
[buffer.md](../view-parameters/buffer.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/sync.md" %}
[sync.md](../view-parameters/sync.md)
{% endcontent-ref %}




---
description: '=motion prioritizes frame rate; =detail prioritizes resolution'
---

# \&contenthint

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&hint`
* `&contenttype`
* `&content`

## Options

Example: `&contenthint=detail`

| Value    | Description                                    |
| -------- | ---------------------------------------------- |
| `detail` | will prioritize **resolution** over frame rate |
| `motion` | will prioritize **frame rate** over resolution |

#### Additional value options

Depending on browser and version, there may be additional values you can pass, such as `text`. Please see the following link for possible options that your browser may offer:

[https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/contentHint](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/contentHint)

## Details

`&contenthint` can customize how you want VDO.Ninja to balance resolution vs frame rate, specifically when bitrate or CPU is insufficient to offer both at the same time.

The two options for video are `detail` or `motion`. Screen-shares generally tend towards `detail` by default, and camera sources are tend towards `motion` by default. `detail` will try to prioritize resolution over frame rate, so the frame rate may drop a lot used. `motion` will try to maximize frame rate, but may drop the resolution a lot. There's no way to force both on as there's no magic bullet if your CPU or network cannot keep up.

For more information on how to lock or maximize the resolution of a video feed, please see the following guide:

{% content-ref url="../../guides/how-do-i-lock-the-resolution.md" %}
[how-do-i-lock-the-resolution.md](../../guides/how-do-i-lock-the-resolution.md)
{% endcontent-ref %}

There is [`&screensharecontenthint`](../screen-share-parameters/and-screensharecontenthint.md) if you want the parameter to only affect screen-shares.

### Addressing core causes of lower quality

If facing poor video quality, you might also want to try increasing your bitrate or improving your network's connection quality, such as moving off of WiFi and onto Ethernet. Sometimes changing codecs, such as to h264 or av1, can help improve quality depending on the cause. \
\
If your CPU is overloaded, h264 might use less CPU than other codecs. You can also consider using \&meshcast to reduce CPU usage if sharing to multiple viewers at a time. Changing browsers might also help, such as trying Chrome, Firefox, or even Safari.

{% hint style="info" %}
If using [`&codec=vp9`](../view-parameters/codec.md) on the viewer side, the frame rate may drop as low as even 5-fps.
{% endhint %}

{% hint style="warning" %}
This parameter has been tested on Chrome, but other browsers may vary in behavior. Safari seems to just ignore things, for example.
{% endhint %}

## Related

{% content-ref url="../screen-share-parameters/and-screensharecontenthint.md" %}
[and-screensharecontenthint.md](../screen-share-parameters/and-screensharecontenthint.md)
{% endcontent-ref %}




---
description: Will show the audio and the video of the director but not of the guests
---

# \&directoronly

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&directorsonly`
* `&do`

## Details

`&directoronly` will show the audio and video of the director but not of the guests. It is basically the same as [`&broadcast`](../view-parameters/broadcast.md) but the guests can't hear each other. It is just the same as doing [`&view=DirectorStreamID`](../view-parameters/view.md), but without having to know the stream ID for the director.

It will actually connect to any director, including co-directors, not just the main one.

[`&view`](../view-parameters/view.md), [`&include`](../mixer-scene-parameters/and-include.md), [`&exclude`](../view-parameters/and-exclude.md) have a lower priority to `&directoronly`. So if there are two directors, you can do `&directoronly&exclude=coDirector123`, so that the codirector doesn't connect.

I changed the toggle in the director's room for "Guests hear others" from [`&view=`](../view-parameters/view.md) to `&directoronly`. The point of this change is that the [director](../../viewers-settings/director.md) can now still talk to those in the room.\
 (2).png>)

Purpose of change: I had a user who wanted [`&broadcast`](../view-parameters/broadcast.md), but also not have the guests hear each other. It's a bit of a hassle to do [`&view=DirectorStreamID`](../view-parameters/view.md), and the toggle is labelled to be misleading by saying "guests", not "everyone".

You can use `&directoronly` to replace [`&broadcast`](../view-parameters/broadcast.md) if you don't want the guests hearing each other.

## Related

{% content-ref url="../view-parameters/broadcast.md" %}
[broadcast.md](../view-parameters/broadcast.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/view.md" %}
[view.md](../view-parameters/view.md)
{% endcontent-ref %}




---
description: Sets the target frame rate of the video in frames per second
---

# \&fps

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&framerate`
* `&fr`

## Options

Example: `&fps=60`

| Value                         | Description                    |
| ----------------------------- | ------------------------------ |
| (some positive integer value) | Frame rate (frames per second) |

## Details

`&fps` specifies a target frame rate for the video capture, in frames per second; it is specified on the sender's side. The actual frame rate that's encoded and sent to the viewers may be less than the captured frame rate, sometimes quite a bit lower.

In most cases, if the target captured frame rate isn't supported, VDO.Ninja will throw an error. As a result, \&fps is considered pretty strict and isn't recommended for most normal use cases.&#x20;

{% hint style="danger" %}
If the camera cannot support the targetted frame rate, **it will likely fail**. Use [`&maxframerate`](../../source-settings/and-maxframerate.md) instead if you are okay with the system to fallback onto a different frame rate, as it is less strict compared to `&fps`.
{% endhint %}

Limiting the frame rate can reduce the CPU load and the bandwidth, as the encoded video frame rate will try to match the capture the captured frame rate. The higher the encoded frame rate, the more CPU is typically used. 30-fps is fairly standard, although VDO.Ninja targets 60-fps by default.

You can change the frame rate dynamically, as the sender, via the settings -> video options; if your browser and device supports it that is. The viewer cannot change or request a specific frame rate, but they can specify [`&contenthint`](and-contenthint.md), which indicates whether they prefer higher resolution vs higher frame rates.

[`&codec=av1`](../view-parameters/codec.md#av1) on the viewer side may achieve more stable encoded frame rates than [`&codec=h264`](../view-parameters/codec.md#h264) or [`&codec=vp8`](../view-parameters/codec.md#vp8), which are normally the defaults. Higher bitrates and more stable network conditions can also help ensure more stable frame rates of the actually streamed video. The encoded frame rate is often a bit less than what is captured, especially when dealing with packet loss.

Unless using [`&chunked`](../../newly-added-parameters/and-chunked.md) mode or a WHIP/WHEP source, it generally isn't possible to force a specific encoded frame rate. The system will try to keep the frame rate that's encoded and sent close to the captured frame rate, but it may drop due to packet loss, CPU limitations, or during moments of insufficient bitrate.

If screen sharing, window, vs. tab, vs. display capture methods can result in different max frame rates. Refer to the screen sharing section for details, but consider experimenting with different methods and browsers to find something that works for you. If screen sharing a game, consider setting the bitrate to at least 12- to 20-mbps, to keep the encoded frame rates steady.

#### Compatibility and flicker with 24, 25, 50, and 144-hz frame rates

24-fps capture devices may fail, so it is recommended to target 30- or 60-fps is possible. If in the UK or a country that has 50-hz lights or displays, you may wish to capture at 25-fps or 50-fps to avoid flicker caused by a mismatch between your display and the lights in the room. 30-fps or 60-fps is pretty standard for modern online video though.

If your display is set to 144-hz or some other odd frame rate, it is suggested to set your display to 120-hz or some multiple of 25- or 30-hz, depending on your location, to also avoid flicker with the camera's capture rate.

#### Higher than 60-fps, such as 120-fps

Capturing video higher than 60-fps, such as 120-fps, is supported in certain situations, such as if screen sharing an entire display that has higher 120-hz set. Normally however, the video encoding is limited to 60-fps max, so capturing at a higher frame rate doesn't make sense.

If using [`&chunked`](../../newly-added-parameters/and-chunked.md) mode on the sender's link however, chunked mode supports higher than 60-fps encoding, such as 120-fps. Chunked mode is considered an experimental option though, but it has been tested between two Windows 11 systems on a LAN running with Chrome.

[Raspberry.Ninja](../../steves-helper-apps/raspberry.ninja/) or using a remote WHIP/WHEP stream as a source may also unlock the option for higher than 60-fps streaming, but this isn't a suggested approach to the problem.

## Related

{% content-ref url="../../source-settings/and-maxframerate.md" %}
[and-maxframerate.md](../../source-settings/and-maxframerate.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/screensharefps.md" %}
[screensharefps.md](../../source-settings/screensharefps.md)
{% endcontent-ref %}

{% content-ref url="and-contenthint.md" %}
[and-contenthint.md](and-contenthint.md)
{% endcontent-ref %}




---
description: Can be used to pass a list of background images via the URL
---

# \&imagelist

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&imagelist=%5B%22https%3A%2F%2Fvdo.ninja%2Fmedia%2Fold_logo.png%22%2C%22https%3A%2F%2Fvdo.ninja%2Fmedia%2Fbg_sample.webp%22%2C%22https%3A%2F%2Fvdo.ninja%2Fmedia%2Fbg_sample2.webp%22%5D`

<table><thead><tr><th width="208">Value</th><th>Description</th></tr></thead><tbody><tr><td>(URL)</td><td>Passes a list of images via the URL</td></tr></tbody></table>

## Details

Added options to host your own default background images for the virtual background effect. `&imagelist=xxxx` can be used to pass a list of images via the URL.

Code to generate the list properly can be found here: [https://jsfiddle.net/steveseguin/w7z28kgb/](https://jsfiddle.net/steveseguin/w7z28kgb/) (images must be cross origin enabled) - at the base of index.html, if self-hosting VDO.Ninja, you can hard-code the list of images as well.

<div align="left">

<figure><figcaption><p>When selecting a background image, you'll get a gentle glow around the selected image now. There's also a horizontal scroll bar, if the number of images listed are too much to fit.</p></figcaption></figure>

</div>

### Complicated? It's simple if using Imgur (free hosting service)

If looking for a free image host, I think [Imgur.com](https://imgur.com) offers free image hosting that is CORS friendly. The URLs it provides are also seemingly safe to use without URL encoding. You can just replace the `XXXXXXX` in the link below, with your Imgur provided ID value, and it might get you going.\
\
Example: `&imagelist=[%22https://i.imgur.com/XXXXXXX.png%22]`

### Mirroring issues

By default, the image may be mirrored to the publisher, as webcam previews are by default mirrored in VDO.Ninja. The image will not be mirrored in the output however; just in the preview.

You can disable the mirroring on the preview though; use `&nomirror` on the URL as a parameter.

## Related

{% content-ref url="../../source-settings/effects.md" %}
[effects.md](../../source-settings/effects.md)
{% endcontent-ref %}




---
description: Will disable the mini-preview functionality
---

# \&largepreview

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Details

If you want the VDO.Ninja self-preview to not be mini-sized in [broadcast](../view-parameters/broadcast.md) mode, which might be the case on mobile, you can try using [`&minipreview=0`](../../source-settings/and-minipreview.md) or `&largepreview`. These flags will disable the mini-preview functionality, keeping the preview the same size as other videos.

## Related

{% content-ref url="../../source-settings/and-minipreview.md" %}
[and-minipreview.md](../../source-settings/and-minipreview.md)
{% endcontent-ref %}

{% content-ref url="and-minipreview-1.md" %}
[and-minipreview-1.md](and-minipreview-1.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-preview.md" %}
[and-preview.md](../../source-settings/and-preview.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-nopreview.md" %}
[and-nopreview.md](../../source-settings/and-nopreview.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/broadcast.md" %}
[broadcast.md](../view-parameters/broadcast.md)
{% endcontent-ref %}




# &leaveorientationflag

#### **Description**

Preserves the video orientation metadata in the WebRTC stream, preventing automatic orientation corrections.

#### **Sender-Side Option**

This parameter prevents VDO.Ninja from removing the 3GPP video orientation extension from the SDP.

#### **Usage**

* **`&leaveorientationflag`** - Preserves orientation metadata

#### **Examples**

```
https://vdo.ninja/?push=streamID&leaveorientationflag
https://vdo.ninja/?room=roomname&leaveorientationflag
```

#### **Technical Details**

* Preserves `a=extmap:3 urn:3gpp:video-orientation` in SDP
* By default, VDO.Ninja removes this flag
* Affects how video rotation is handled
* Important for certain mobile streaming scenarios

#### **What It Does**

When enabled:
- Raw orientation data is passed through
- Receiving applications handle rotation
- No automatic orientation correction
- Preserves original mobile device orientation

When disabled (default):
- VDO.Ninja handles orientation
- Automatic rotation for mobile sources
- Consistent orientation across platforms

#### **Use Cases**

* Custom applications that handle rotation
* Debugging orientation issues
* Preserving raw mobile video streams
* Integration with systems expecting orientation data

#### **Platform Considerations**

* **Mobile devices**: May affect portrait/landscape handling
* **Desktop**: Usually no visible effect
* **OBS**: May impact how mobile sources are displayed
* **Custom receivers**: Can read orientation metadata

#### **Notes**

* Advanced parameter for specific use cases
* Most users should use default behavior
* Can affect mobile video display
* Test thoroughly when enabling

#### **Related Parameters**

* [`&forcelandscape`](../mobile-parameters/and-forcelandscape.md) - Forces landscape orientation
* [`&forceportrait`](../mobile-parameters/and-forceportrait.md) - Forces portrait orientation
* [`&rotate`](../design-parameters/and-rotate.md) - Rotates video display
* [`&leavevideorotation`](README.md) - Related rotation handling




---
description: Used to position where the mini preview is located by default on screen
---

# \&minipreviewoffset

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&mpo`

## Options

Example: `&minipreviewoffset=60`

<table><thead><tr><th width="295">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given) | <code>0</code></td><td>left-most side of the screen</td></tr><tr><td><code>40</code></td><td>center of the screen</td></tr><tr><td>(integer value) <code>-20</code> to <code>120</code></td><td>defines the position of the mini preview</td></tr></tbody></table>

## Details

Added `&minipreviewoffset` accepts an integer value, `-20` to `120`, which is used to position where the [mini preview](../../source-settings/and-minipreview.md) is located by default on screen. `40` would imply center of the screen, as the mini preview is about 20% of the screen size. `0` (or just `&minipreviewoffset`) is the left-most side of the screen.

<figure><figcaption><p><code>&#x26;minipreviewoffset=40</code></p></figcaption></figure>

## Related

{% content-ref url="../../source-settings/and-minipreview.md" %}
[and-minipreview.md](../../source-settings/and-minipreview.md)
{% endcontent-ref %}




---
description: Disables all video playback from room directors
---

# \&nodirectorvideo

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Details

`&nodirectorvideo` is just like [`&novideo`](and-novideo.md) (disables all video playback on the local computer), except it only applies to incoming connections from room directors. So, if your are using the [Mixer App](../../steves-helper-apps/mixer-app.md) with OBS, but you want to exclude the video of yourself from the OBS, this potentially could be an easy way to do that.

## Related

{% content-ref url="and-novideo.md" %}
[and-novideo.md](and-novideo.md)
{% endcontent-ref %}

{% content-ref url="../audio-parameters/and-nodirectoraudio.md" %}
[and-nodirectoraudio.md](../audio-parameters/and-nodirectoraudio.md)
{% endcontent-ref %}

{% content-ref url="../../viewers-settings/director.md" %}
[director.md](../../viewers-settings/director.md)
{% endcontent-ref %}

{% content-ref url="../../steves-helper-apps/mixer-app.md" %}
[mixer-app.md](../../steves-helper-apps/mixer-app.md)
{% endcontent-ref %}




---
description: Disables all video playback on the local computer
---

# \&novideo

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&nv`
* `&hidevideo`
* [`&showonly`](novideo.md)

## Details

`&novideo` disables all video playback on the local computer. Useful for reducing the CPU and network load on other connect peers if voice-chat is sufficient.

* Join a group-room as audio-only, to limit load on the guests.

When used together with [`&noaudio`](../view-parameters/noaudio.md) (`&novideo&noaudio`), prevents guest room member from seeing or hearing other member's audio or video feeds.

* Useful for directors who may wish to only issue commands or text chat, but not need to see video or audio.

You can pass a comma separated list of stream IDs that will be excluded, so that they specifically will play video. `?novideo=guest1a,guest2a` will only allow video from guest1a and guest2a to play.

Video tracks are blocked and do not form any connection when using peer-to-peer, not taking up bandwidth or system load, but they also cannot be re-enabled without reconnecting. Video tracks from WHIP-based sources, Iframes, or some non-standard sources may still allow video tracks to connect, using up bandwidth, but will not be rendered. Check the connection stats for that stream ID to confirm.

Use [`&broadcast`](../view-parameters/broadcast.md) or [`&showonly`](novideo.md) if you want to disable all videos except any stream IDs listed.

## Related

{% content-ref url="../view-parameters/noaudio.md" %}
[noaudio.md](../view-parameters/noaudio.md)
{% endcontent-ref %}

{% content-ref url="novideo.md" %}
[novideo.md](novideo.md)
{% endcontent-ref %}

{% content-ref url="and-nodirectorvideo.md" %}
[and-nodirectorvideo.md](and-nodirectorvideo.md)
{% endcontent-ref %}




---
description: Presets the quality setting for a guest
---

# \&quality

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&q`

## Options

Example: `&quality=0`

| Value                   | Description                                                               |
| ----------------------- | ------------------------------------------------------------------------- |
| `0` \| (no value given) | about 1080p60, depending on hardware                                      |
| `1`                     | about 720p60, depending on hardware                                       |
| `2`                     | about 360p30, depending on hardware                                       |
| `-1` (device's default) | useful in allowing the screen share at the same resolution as the display |

## Details

Presets the "quality" setting for a guest. Not "strict" and is less likely to give errors than explicit resolution requests.

Without using `&quality` on the URL a guest can change the "quality" when setting up the camera:\
 (1) (2) (1).png>)

Use [`&width`](../../source-settings/and-width.md) and [`&height`](../../source-settings/and-height.md) to get a higher resolution than 1920x1080.

There is a toggle in the director's room guest's invite link customization which adds `&q`:\
 (1).png>)

## Related

{% content-ref url="../../source-settings/screensharequality.md" %}
[screensharequality.md](../../source-settings/screensharequality.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-mediasettings.md" %}
[and-mediasettings.md](../../newly-added-parameters/and-mediasettings.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-width.md" %}
[and-width.md](../../source-settings/and-width.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-height.md" %}
[and-height.md](../../source-settings/and-height.md)
{% endcontent-ref %}




---
description: Should 'up to' double the amount of playback video resolution
---

# \&sharper

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&sharpen`
* [`&dpi=2`](../view-parameters/dpi.md)

## Details

`&sharper` is now an alias of [`&dpi=2`](../view-parameters/dpi.md), which should 'up to' double the amount of playback video resolution, if the dynamic resolution optimization is enabled at least, in certain cases. This is a lot like [`&scale=100`](../view-parameters/scale.md), but perhaps _slightly_ more efficient in some cases. This is mainly for when you intend to have a large screen-share in a scene, where you don't want the tiny guest videos to be a 100% scale, but 50% scale is fine (up from 25% scale). [`&dpi`](../view-parameters/dpi.md) already exists on production, but by adding these aliases, I hope it's more discoverable.

As an alternative to `&sharper`, I've also added [`&sharperscreen`](../screen-share-parameters/and-sharperscreen.md), which sets [`&scale=100`](../view-parameters/scale.md), but _only_ for screen-shares (virtual cameras not included). This is probably even more efficient than [`&scale=100`](../view-parameters/scale.md) or `&sharper`, and it's designed for when screen-sharing a lot of text. Text looks a bit soft when streaming video at 1:1 pixel resolution.

It's recommended to only use these parameters within the context of a scene link, and not on guest links, due to the higher CPU / bandwidth it may use.

## Related

{% content-ref url="../screen-share-parameters/and-sharperscreen.md" %}
[and-sharperscreen.md](../screen-share-parameters/and-sharperscreen.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/dpi.md" %}
[dpi.md](../view-parameters/dpi.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/scale.md" %}
[scale.md](../view-parameters/scale.md)
{% endcontent-ref %}




---
description: Plays video back as a series of full-window images
---

# \&slideshow

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Details

This option decodes incoming video (first video to load), but plays them back as series of full-window images. That is, a single image element, that gets updated 24 times a second, instead of playing the video back within an efficient video element. I have no idea why you might want this option, as it pretty crude up and uses up a lot of CPU, but you can right-click to save a single frame from the video to disk, as a PNG file. This might be useful if you need to take a lot of snap shots of some video and don't want to have to hassle with cropping a window-grab. Quality of the images is pretty high; near lossless.

.png>)

## Related

{% content-ref url="../settings-parameters/and-postimage.md" %}
[and-postimage.md](../settings-parameters/and-postimage.md)
{% endcontent-ref %}




---
description: Does the same thing as &scale but you pass the height in pixels
---

# \&viewheight

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&vh`

## Options

Example: `&viewheight=1080`

| Value           | Description            |
| --------------- | ---------------------- |
| (value integer) | video height in pixels |

## Details

Added new viewer-side parameters that can be used in place of [`&scale`](../view-parameters/scale.md): `&viewheight=180` and [`&viewwidth=320`](and-viewwidth.md), which effectively does the same thing as [`&scale`](../view-parameters/scale.md), but instead you pass a resolution.&#x20;

It's important to note, that due to flexibility to request width/heights that are not aspect-ratio compatible, and due to bitrate/quality resolution limitations, these values are just 'max' target resolution values; the actual resolution you get could be still less. They also do not impact the actual capture resolution of the remote sender's camera, so its purely for requesting a specific downscaled resolution. This command applies to all video elements in a view port, and it disables the auto-scaler functionality.

Similarly, also added the option to the IFRAME API to request different down-scaled resolutions dynamically, per connection, if you want greater programmatic control vs static URL options.

 (1).png>)

.png>)

## Related

{% content-ref url="and-viewwidth.md" %}
[and-viewwidth.md](and-viewwidth.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/scale.md" %}
[scale.md](../view-parameters/scale.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-noscale.md" %}
[and-noscale.md](../../newly-added-parameters/and-noscale.md)
{% endcontent-ref %}




---
description: Does the same thing as &scale but you pass the width in pixels
---

# \&viewwidth

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&view`](../view-parameters/view.md), [`&solo`](../mixer-scene-parameters/and-solo.md))

## Aliases

* `&vw`

## Options

Example: `&viewwidth=1920`

| Value           | Description           |
| --------------- | --------------------- |
| (value integer) | video width in pixels |

## Details

Added new viewer-side parameters that can be used in place of [`&scale`](../view-parameters/scale.md): [`&viewheight=180`](and-viewheight.md) and `&viewwidth=320`, which effectively does the same thing as [`&scale`](../view-parameters/scale.md), but instead you pass a resolution.&#x20;

It's important to note, that due to flexibility to request width/heights that are not aspect-ratio compatible, and due to bitrate/quality resolution limitations, these values are just 'max' target resolution values; the actual resolution you get could be still less. They also do not impact the actual capture resolution of the remote sender's camera, so its purely for requesting a specific downscaled resolution. This command applies to all video elements in a view port, and it disables the auto-scaler functionality.

Similarly, also added the option to the IFRAME API to request different down-scaled resolutions dynamically, per connection, if you want greater programmatic control vs static URL options.

 (1) (1).png>)

 (1).png>)

## Related

{% content-ref url="and-viewheight.md" %}
[and-viewheight.md](and-viewheight.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/scale.md" %}
[scale.md](../view-parameters/scale.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-noscale.md" %}
[and-noscale.md](../../newly-added-parameters/and-noscale.md)
{% endcontent-ref %}




---
description: Set the optical/driver-based zoom on your camera to some preset on start
---

# \&zoom

Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Options

Example: `&quality=0`

| Value                             | Description                                    |
| --------------------------------- | ---------------------------------------------- |
|  (no value given)                 | Will ask for Pan Tilt and Zoom permissions     |
| `Some zoom amount to use on load` | Will zoom in by this amount; depends no device |

## Details

A Logitech Brio has a range of 100 to 500 for its digital zoom, with steps of 1.\
\
It's not possible as a result to get perfectly smooth zooming this way, as its a digital zoom in the Logitech Brio that will step up the zoom immediately, so you may find using \&digitalzoom instead more useful. To increase the quality, use \&digitalzoom in conjunction with \&quality=4k, but the digital zoom offered by VDO.Ninja is smoothed out.\
\
That said, if your device does have an optical zoom, using \&zoom instead makes sense, and may actually provide smooth zooming giving the analog nature of optical zoom.\
\
Just like with using \&ptz, using \&zoom may ask you on joining if you wish to give VDO.Ninja permissions to control your pan, tilt, and zoom. For a Logitech Brio, this permission is needed, but it's not needed for all devices; some smartphones fro example.\
\
Regardless, \&zoom=200 for example can be use to pre-set the zoom to 2X, however the number representing how to much zoom in depends on your browser, device, and camera.\
\
You can visit [https://vdo.ninja/supports](https://vdo.ninja/supports) to see if your camera supports \&zoom, and if so, what range it offers.

<figure><figcaption><p>Example URL &#x26;zoom=400 resulting in 4x zoom with a Brio 4K camera</p></figcaption></figure>

<figure><figcaption><p>As per seen in <a href="https://vdo.ninja/supports">https://vdo.ninja/supports</a></p></figcaption></figure>




---
description: Only shows any stream ID that is listed
---

# \&showonly

Viewer-Side Option! ([`&view`](../view-parameters/view.md), [`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* [`&novideo`](and-novideo.md)
* `&nv`
* `&hidevideo`

## Options

Example: `&showonly=streamID1,streamID2`

<table><thead><tr><th width="174">Value</th><th>Description</th></tr></thead><tbody><tr><td>(string value)</td><td>the stream IDs to view; can be a comma separated list</td></tr></tbody></table>

## Details

`&showonly` only shows any stream IDs that are listed. Useful for reducing the CPU and network load on other connect peers if voice-chat is sufficient.

* Useful for a large group room where you want everyone in the room to see only the OBS Virtualcam output.
* Consider using [`&broadcast`](../view-parameters/broadcast.md) option instead of this flag as it is better suited for presenting a single feed to a group than using `&showonly` alone.

This is actually just an alias of [`&novideo`](and-novideo.md).

## Related

{% content-ref url="../view-parameters/broadcast.md" %}
[broadcast.md](../view-parameters/broadcast.md)
{% endcontent-ref %}

{% content-ref url="and-novideo.md" %}
[and-novideo.md](and-novideo.md)
{% endcontent-ref %}




---
description: >-
  Auto-hides remote guests videos when added, if those guests are not speaking
  actively
---

# \&activespeaker

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&sas`
* `&speakerview`

## Options

Example: `&activespeaker=1`

| Value                   | Description                                                                             |
| ----------------------- | --------------------------------------------------------------------------------------- |
| `1` \| (no value given) | will only show one speaker at a time; the loudest or last-loud speaker                  |
| `2`                     | will show whoever is talking; mixed together; if no one is talking, just shows yourself |
| `3`                     | the same as `1`, but it will not switch to show audio-only sources (just video only)    |
| `4`                     | the same as `2`, but it will not switch to show audio-only sources (just video only)    |

In all four cases, if someone else is talking/active, your local preview will become a [mini-preview](../../source-settings/and-minipreview.md) in the top right.

### Customize the delay on switching

By default, the active speaker switches fairly quickly, typically within a few hundred milliseconds of a louder speaker taking over. You can add a fixed added delay, which works with modes 1 and 3, which will delay how long it takes before a switch between speakers is made

`&activespeakerdelay`=2000, where 2000 is a value in milliseconds.

This will not impact modes 2 or 4

## Related

If looking to add a green box around active speakers, or make it just easier to see who is talking, please considering using \&meterstyle instead.

{% content-ref url="../design-parameters/meterstyle.md" %}
[meterstyle.md](../design-parameters/meterstyle.md)
{% endcontent-ref %}

{% content-ref url="../mixer-scene-parameters/and-motiondetection-alpha.md" %}
[and-motiondetection-alpha.md](../mixer-scene-parameters/and-motiondetection-alpha.md)
{% endcontent-ref %}




---
description: Shifts audio channels 0 and 1 up channels, based on the offset value
---

# \&channeloffset

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&channeloffset=1`

| Value           | Description                                                  |
| --------------- | ------------------------------------------------------------ |
| (numeric value) | Number of channels to shift the audio, starting at channel 0 |

## Details

`&channeloffset` shifts audio channels 0 and 1 up channels, based on the offset value you set.

Total channels is assumed to be 8 if this is used and not otherwise specified.

Does not work with all audio output devices and may require experimentation.

Best to use this with a mono input, as stereo channel shifting can cause issues - simpler that way.

Please see here for detailed testing results with different audio devices: [https://docs.google.com/spreadsheets/d/1R-y7xZ2BCn-GzTlwqq63H8lorXecO02DU9Hu4twuhuA/](https://docs.google.com/spreadsheets/d/1R-y7xZ2BCn-GzTlwqq63H8lorXecO02DU9Hu4twuhuA/)

## Related

{% content-ref url="../audio-parameters/and-inputchannels.md" %}
[and-inputchannels.md](../audio-parameters/and-inputchannels.md)
{% endcontent-ref %}

{% content-ref url="and-channels.md" %}
[and-channels.md](and-channels.md)
{% endcontent-ref %}

{% content-ref url="../audio-parameters/and-channeloffset-1.md" %}
[and-channeloffset-1.md](../audio-parameters/and-channeloffset-1.md)
{% endcontent-ref %}




---
description: Specifies the number of output audio channels you wish to mix up or down to
---

# \&channels

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&channels=4`

| Value           | Description                     |
| --------------- | ------------------------------- |
| (integer value) | number of audio output channels |

## Details

Left and right is available for most users; channels 1 and 2

* Up to 6-channels is possible, if your output device supports it.
* On Windows, you might need to select 5.1 surround sound with your device in the Windows audio settings.
* On macOS, you might want to consider using SoundFlower, as it seems the most correct with its routing.

Designed to be used with [`&channeloffset`](and-channeloffset.md).

Please see here for detailed testing results with different audio devices: [https://docs.google.com/spreadsheets/d/1R-y7xZ2BCn-GzTlwqq63H8lorXecO02DU9Hu4twuhuA/](https://docs.google.com/spreadsheets/d/1R-y7xZ2BCn-GzTlwqq63H8lorXecO02DU9Hu4twuhuA/)

{% hint style="info" %}
If looking to set the number of input channels, rather than output, please see [`&inputchannels`](../audio-parameters/and-inputchannels.md) instead.
{% endhint %}

## Related

{% content-ref url="and-channeloffset.md" %}
[and-channeloffset.md](and-channeloffset.md)
{% endcontent-ref %}

{% content-ref url="../audio-parameters/and-inputchannels.md" %}
[and-inputchannels.md](../audio-parameters/and-inputchannels.md)
{% endcontent-ref %}

{% content-ref url="../audio-parameters/and-channeloffset-1.md" %}
[and-channeloffset-1.md](../audio-parameters/and-channeloffset-1.md)
{% endcontent-ref %}




---
description: Same concept as &view, except does the opposite
---

# \&exclude

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&ex`

## Options

Example: `&exclude=StreamID1,StreamID2`

<table><thead><tr><th width="200">Value</th><th>Description</th></tr></thead><tbody><tr><td>(string value)</td><td>stream ID to view; can be a comma-separated list of IDs</td></tr></tbody></table>

## Details

Any stream ID listed as a value will **NOT** be played or requested.

Example usage:

`https://vdo.ninja/?room=myroom123&exclude=stream121,sidestream321`

{% hint style="warning" %}
Excluding a stream ID will prevent even a peer connection.\
No video, audio, or chat can be had.
{% endhint %}




---
description: Maximum packet size of audio
---

# \&maxptime

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&maxptime=60`

| Value           | Description           |
| --------------- | --------------------- |
| (integer value) | max packet size in ms |

## Details

{% hint style="danger" %}
If you do not know what this is, you definitely don't want to touch it.
{% endhint %}

60-ms is common. 30-ms is reasonable.

Optimized already, but it's available for experimentation and fun if desired.

## Related

{% content-ref url="and-ptime.md" %}
[and-ptime.md](and-ptime.md)
{% endcontent-ref %}

{% content-ref url="minptime.md" %}
[minptime.md](minptime.md)
{% endcontent-ref %}





---
description: Limits the number of remote peer connections that are publishers
---

# \&maxpublishers

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&mp`

## Options

Example: `&maxpublishers=7`

| Value           | Description                             |
| --------------- | --------------------------------------- |
| (integer value) | limit number of remote peer connections |

## Details

Limits the number of remote peer connections that are publishers.

## Related

{% content-ref url="../../source-settings/and-maxconnections.md" %}
[and-maxconnections.md](../../source-settings/and-maxconnections.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-maxviewers.md" %}
[and-maxviewers.md](../../source-settings/and-maxviewers.md)
{% endcontent-ref %}




---
description: >-
  Disables or adjusts the sensitivity of the VP8/VP9 Codec packet loss 'fix' for
  OBS
---

# \&obsfix

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&obsfix=5`

| Value            | Description                                             |
| ---------------- | ------------------------------------------------------- |
| (integer value)  | adjust the sensitivity of the packet loss 'fix' for OBS |
| (no value given) | defaults to 15                                          |
| `0` \| `off`     | Turns it off                                            |

## Details

It's on by default and set to `15` if only using OBS and if using the VP8/VP9 video [codec](../../advanced-settings.md#codec).

* There is a bug in OBS where the VP8 codec (default in most cases) does not handle packet loss events. This function attempts fixes its.
* You can disable this 'fix' by passing it the value `0` or `off`.
* When on, it will trigger a key frame request to combat pixel smearing caused by packet loss and poor network conditions.
* Triggers around every 3-seconds if needed; may not activate often with very light packet loss.
* May lower video quality, or may not be desirable, so this flag lets you disable it.
* Stream pushers can open the debug/stats menu and manually send key frames also.
* VP9 is far less prone to packet loss issues, but it can still happen with heavy packet loss.
* Increasing the integer value passed to `&obsfix` will reduce the frequency and sensitivity of the key frame request.




---
description: Pans the outgoing audio left or right, allowing for spatial audio group chats
---

# \&panning

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&pan`

## Options

Example: `&panning=120`

| Value                    | Description                                                   |
| ------------------------ | ------------------------------------------------------------- |
| (no value given) \| `90` | has the audio centered, but published as a mono-stereo stream |
| (0-89)                   | pans the audio left                                           |
| (91-180)                 | pans the audio right                                          |
| `-1`                     | panning will be randomized                                    |

## Details

The default, if no value is passed, is to have the audio centered, but published as a mono-stereo stream.&#x20;

To pan the audio left, pass a value of 0 to 89.

To center, pass 90 or leave blank.

To pan the audio right, pass a value of 91 to 180.

0 is the most left, while 180 is the most right.

If negative 1 is passed `&panning=-1`, then the panning will be randomized; center weighted a bit. This allows for a group-room experience where everyone in the room to have a different spatial position, making it easier to have larger group discussions where guests may sound similar to each other.

You may need to use [`&stereo`](../../general-settings/stereo.md) as a flag, or variants of it on the publisher and/or viewer's side, to ensure the audio is transmitted as stereo as well.

Please also note, the volume is gained up or down digitally to compensate for the value changes of mixing and panning; it attempts to retain the same loudness and avoid clipping. Please report issues or provide feedback if you encounter problems with it.

Also note, the audio can be dynamically panned left or right thereafter by the IFRAME API. For VR-applications, this could provide for some interesting user experiences.

## Related

{% content-ref url="../../general-settings/stereo.md" %}
[stereo.md](../../general-settings/stereo.md)
{% endcontent-ref %}




---
description: Optimizes the video mixer for 9:16 videos
---

# \&portrait

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&916`
* `&vertical`

## Details

Optimize the auto-mixer to work with video streams that are in portrait mode (versus landscape).

Can be used together with [`&cover`](cover.md) to get a better effect.\
For example:\
`https://vdo.ninja/?scene&room=roomname&portrait&cover`\
.png>)

## Related

{% content-ref url="cover.md" %}
[cover.md](cover.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-square.md" %}
[and-square.md](../../newly-added-parameters/and-square.md)
{% endcontent-ref %}

{% content-ref url="../design-parameters/and-rotate.md" %}
[and-rotate.md](../design-parameters/and-rotate.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-43.md" %}
[and-43.md](../../newly-added-parameters/and-43.md)
{% endcontent-ref %}




---
description: Audio packet size
---

# \&ptime

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&ptime=40`

| Value           | Description             |
| --------------- | ----------------------- |
| (integer value) | audio packet size in ms |

## Details

{% hint style="danger" %}
If you do not know what this is, you definitely don't want to touch it.
{% endhint %}

## Related

{% content-ref url="minptime.md" %}
[minptime.md](minptime.md)
{% endcontent-ref %}

{% content-ref url="and-maxptime.md" %}
[and-maxptime.md](and-maxptime.md)
{% endcontent-ref %}




---
description: Audio playback sample-rate, in hz
---

# \&samplerate

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&sr`

## Options

Example: `&samplerate=48000`

| Value           | Description       |
| --------------- | ----------------- |
| (integer value) | sample-rate in hz |

## Details

`&samplerate` sets the audio playback sample-rate in Hz (not capture or transmission sample-rate).

This is mainly for debugging audio distortion or clicking issues.

Sometimes it can remove clicking when used, even if set to the typical 48000 value.




---
description: >-
  Outputs the audio to the specified audio output device, rather than the
  default
---

# \&sink

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](view.md), [`&scene`](scene.md))

## Options

Example: `&sink=1dee4206f5deb75973e33f7078d4c1539782e29e255799d59b8b61a855d17bea`

| Value          | Description                                                        |
| -------------- | ------------------------------------------------------------------ |
| (string value) | device ID ([https://vdo.ninja/devices](https://vdo.ninja/devices)) |

## Details

{% hint style="danger" %}
Device IDs are tied to the browser + domain + cookie session combination.
{% endhint %}

Outputs the audio to the specified audio output device, rather than the default.

Designed to be used in conjunction with [https://vdo.ninja/electron.](https://vdo.ninja/electron)

You can find out the string value of your audio output device here: [https://vdo.ninja/devices](https://vdo.ninja/devices)

## Related

{% content-ref url="../setup-parameters/and-audiooutput.md" %}
[and-audiooutput.md](../setup-parameters/and-audiooutput.md)
{% endcontent-ref %}




---
description: Videos in a group scene will slide around the screen when being re-arranged
---

# \&animated

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&animate`

## Options

Example: `&animated=false`

| Value                           | Description                                                      |
| ------------------------------- | ---------------------------------------------------------------- |
| (no value given)                | videos in a group scene will slide around when being re-arranged |
| `false` \| `0` \| `no` \| `off` | disables the animated effect                                     |

## Details

Videos in a group scene will slide around the screen when being re-arranged, such as when a new video gets added to the scene.

{% hint style="info" %}
In the newest version of VDO.Ninja `&animated` is on by default. You can disable it with `&animated=0`. There is also a toggle in the director's room to disable it in the guest's invite URL.\
 (5).png>)
{% endhint %}

Mobile phone users will not have this effect enabled by default, but most other guest and scene types will.

You can force enable this animation effect by adding `&animated` to the URL, or you can force disable the effect by passing false, such as `&animated=false` , or passing `0`, `no`, or `off`.

## Related

{% content-ref url="fadein.md" %}
[fadein.md](fadein.md)
{% endcontent-ref %}




---
description: Manually sets the audio bitrate in kbps
---

# \&audiobitrate

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&ab`

## Options

Example: `&audiobitrate=128`

| Value           | Description     |
| --------------- | --------------- |
| (integer value) | bitrate in kbps |

## Details

The default is around 32-kbps per track with a mono-channel (VBR on by default).

The audio codec used is OPUS and the target sample rate is 48khz.

510-kbps is the highest value allowed, with around 300-kbps the highest value for a mono-channel track.

For voice, the default audio bitrate is sufficient for most users, however 64- to 80-kbps may offer an audible improvement. For music, you may wish to go higher.

{% hint style="info" %}
For reference, music streaming providers will use around 64- to 128-kbps as their default.
{% endhint %}

When an audio bitrate is manually specified, CBR is enabled by default.

Setting the audio bitrate to be very high can sometimes cause video bitrates on weak connections to become stuck at around 30-kbps.dio on mobile devices.

### Considerations

If you are using the [Echo-Cancellation (`&aec`)](../../source-settings/aec.md) and [`&denoise`](../../source-settings/and-denoise.md) filters, audio quality may still sound like telephone quality in some cases, even with an increased bitrate. These filters are on by default.\
\
Filtering out echos and noise can impact the audio quality, so while these filters are effective in what they do, the harder they have to work, the more the audio will sound like a telephone call.

Finding ways to eliminate background noise, hum, and feedback can improve audio quality, as the echo/noise filters will then not need to activate or be used with such strength. You can of course disable those filters entirely, which when combined with a higher audio bitrate, will get you closer to what sounds like a raw audio recording; this assumes feedback isn't an issue of course.

{% content-ref url="../video-bitrate-parameters/bitrate.md" %}
[bitrate.md](../video-bitrate-parameters/bitrate.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/stereo.md" %}
[stereo.md](../../general-settings/stereo.md)
{% endcontent-ref %}




---
description: >-
  A useful flag to allow the director to present their own video to the group,
  often used in conjunction with a virtual webcam or Meshcast. It allows for
  larger groups rooms by reducing load on guests
---

# \&broadcast

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&bc`

## Options

Example: `&broadcast=StreamID`

<table><thead><tr><th width="195">Value</th><th>Description</th></tr></thead><tbody><tr><td>(no value given)</td><td>Only play-back the director's stream</td></tr><tr><td>(stream ID)</td><td>You can pass an optional stream-ID to specify the stream's source manually.<br>If no value is passed, the source will be the room's director video out feed.</td></tr></tbody></table>

## Details

This command is like using [`&showonly=directorsStreamID`](../video-parameters/novideo.md) but with some extras tweaks that might be appropriate to a larger group room.

In essence, `&broadcast` only allows the playback of video-tracks and [shared-websites](../../source-settings/and-website.md) that originate from the main director. You may not know the stream ID of the main director ahead of time, so this parameter handles that for you automatically as well.

You can pass a stream ID as a value, which will specify the video source to be from a guest (or co-director), rather than the main director. You cannot pass multiple stream IDs to the `&broadcast` flag; just one. If needing more, consider using the [`&showonly`](../video-parameters/novideo.md) flag instead.

You add `&broadcast` to the guest invite links. You do not add this to the director or scene links.

{% embed url="https://youtu.be/QcFKI9q0yFs" %}
Configuring VDO.Ninja in a broadcast group mode
{% endembed %}

#### Why might you want to use this option?

In `&broadcast` mode, only the director is sharing video to the guests of the group room, so only the director has the burden of encoding multiple video streams and uploading them to guests. This is great if your guests are primarily on mobile-devices, have slow-Internet, or it is a larger room; otherwise each guest would be sharing video with each other guest as well.

When used with Meshcast, the director can reduce their own system burden even further. You can achieve fairly large group rooms with modest system requirements this way.

To ensure the guests see all that's needed, if the director selects their Virtual Camera output as their video source, then all the guests in the room will be able to see the live output of that virtual camera stream. The source of this virtual camera feed could be the main OBS output mix, or a specific [custom scene mix](https://github.com/exeldro/obs-virtual-cam-filter) that's design just for the guests.

#### Default settings and styles that are applied when \&broadcast is used

* The guest's self-preview becomes a mini-preview, rather than the normal large self-preview. You can disable the preview all together by using [`&nopreview`.](../../source-settings/and-nopreview.md)
* While `&broadcast` disables the video from other guests, it does not disable or impact their audio, so guests should still be able to hear each other.
* [`&showlist`](../../source-settings/showlist.md) is enabled by default for the guests, which provides a list of those in the room to the guests. `&showlist=0` can hide this, when added to the guest link; useful if you want a cleaner output for the guests.
* The header bar, with basic stats, is shown by default. [`&noheader`](../design-parameters/and-hideheader.md) can be added to the guest links, which will hide this top bar, room name and the stats.
* It hides the audio-only playback elements of other guests in the room, so it's not possible to mute or control the volume, as a guest, or other guests, when `&broadcast` is set. This is akin to having [`&style=1`](../../advanced-settings.md#style)set.

You can some-what imitate the `&broadcast` parameter using something like :&#x20;

`&showonly=DirectorStreamID&noiframe=DirectorStreamID&minipreview&style=1`

#### Performance considerations

While the `&broadcast` flag is great for reducing the load on guests in a room, it will put all the load onto the director instead.

* Consider using NVEnc or other hardware-encoders to encode any RTMP streams in your studio software to reduce CPU load there. This frees up more CPU for VDO.Ninja.
* Make sure you have a capable computer; an AMD 5900x CPU is recommend for most users using this mode without Meshcast, allowing for medium-sized group rooms with some headroom to spare.
* A quad-core computer might only be able to support 1 or 2 guests adequately in this mode, although using Meshcast can help overcome that limitation.
* If you would like the guests to see even higher quality video, consider using [`&totalroombitrate=2500`](../video-bitrate-parameters/totalroombitrate.md) as an option to greatly improve the video quality. This also will greatly also increase the load on the director, so good internet and a powerful CPU will be needed.

#### Using `&broadcast` mode with Meshcast as a source

* Using a service like meshcast.io, along with the [`&website`](../../source-settings/and-website.md) sharing option, can also greatly reduce load on the director and guests. The website sharing function works with other video content delivery networks, not just Meshcast.io, so you have choices.
* When the director shares a website, their own low-latency VDO.Ninja audio remains active, so audio doubling could happen if the website contains their audio also. You'll want to mute either the website's audio or the director's VDO.Ninja audio, to avoid this issue. To also avoid echo-cancellation issues and audio delays, it is recommended to mute the website audio, as VDO.Ninja's audio will have not have those issues.
* You may want to add [`&novideo`](../video-parameters/and-novideo.md) to the guest invite links if you only intend to share video via the website sharing function. This ensures the director's VDO.Ninja video-track doesn't appear, as VDO.Ninja can't always tell if a website contains a video track or not, and so may show the director's video alongside the shared website in some cases otherwise.
* In more recent versions of VDO.Ninja (v22), Meshcast is available built-into VDO.Ninja via the [`&meshcast`](../../newly-added-parameters/and-meshcast.md) parameter, which sends both audio and video over meshcast in sync, without concerns of echo cancellation or audio doubling. Just add `&meshcast` to the director's URL to use this mode; the director's audio and video will auto-publish via Meshcast without needing to visit meshcast.io.
* The director's ability to share a website (meshcast.io link) is via a button found in the director's control bar. The director doesn't need to use [`&website`](../../source-settings/and-website.md) parameter since a website sharing functionality has its own dedicated button in the director's control room.

 (1) (1).png>)

* If using meshcast.io and the website share functionality, rather than `&meshcast`, you will want to mute the Meshcast source to avoid echo cancellation or audio-doubling. The meshcast.io source page has options to do so there, but you can also add [`&mute`](../../source-settings/and-mute.md) to the meshcast.io when sharing it, to have it auto-mute on playback for the guests.

{% embed url="https://youtu.be/YxduINMXw1M" %}
Understanding Meshcast as a tool for VDO.Ninja
{% endembed %}

{% embed url="https://www.youtube.com/watch?v=-7QsLChfdsE" %}
An older video, but it gets some basics across still about \&broadcast mode
{% endembed %}

## Related

{% content-ref url="../video-parameters/novideo.md" %}
[novideo.md](../video-parameters/novideo.md)
{% endcontent-ref %}

{% content-ref url="../video-parameters/and-largepreview.md" %}
[and-largepreview.md](../video-parameters/and-largepreview.md)
{% endcontent-ref %}




---
description: Sets the video buffer
---

# \&buffer

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&buffer=500`

| Value           | Description |
| --------------- | ----------- |
| (numeric value) | delay in ms |

## Details

This feature is viewer-side and increases the incoming audio/video _playout delay_ by means of tweaking the WebRTC _jitter buffer_ pipeline, or a related browser buffer. It affects the browser tab using the view/scene/director URL, not the sender and not other viewers.

This can effectively be used as a way to delay incoming video and audio by a few seconds in normal WebRTC mode. Support and maximum useful delay are browser-dependent; modern Chromium-based browsers and Firefox expose the needed receiver buffer controls, while Safari support is not expected.

While in theory this option can also help to improve video and audio quality, as a larger playback buffer should help reduce the effects of network jitter and packet loss, it's not a miracle solution in this regard. Adding 200-ms of buffer delay using this feature is worth trying however, as some users have reported it has helped improve their connections.

The problem is that the browser doesn't fully make use of the available buffer if set high, and so it's largely used as mainly a hint. Network conditions, memory limits, browser limits, and whether the browser applies the delay independently per track may impact the results as well. Negative buffer values are not supported here. \
\
Older versions of Chromium allowed upwards of 15-seconds of buffering, with recent versions of Chromium allowing only a few seconds in practice. Values beyond roughly 3 seconds may not behave consistently in normal WebRTC mode.

### Chunked-mode

If using the `&chunked` transfer mode, the method and function of the `&buffer` option is different than normal. There is not hard coded limit on what delay you can add, as it that uses it a custom buffering solution that isn't controlled by the browser. You can set the delay to be whatever you want; minutes even, assuming you have the memory for it.

Using `&buffer` with `&chunked` mode can improve quality. Chunked/WebCodecs mode uses VDO.Ninja's own buffering path, so longer buffers are possible there than in normal WebRTC mode, although more than a few seconds is still usually not advisable unless that added latency is intentional.

#### Example values

`&buffer=0` will force the audio to be in sync with the video, with the video playing back with minimal delay.

`&buffer=100` will add a 100-ms time delay to the video, on top of any existing delay.

`&buffer=200` can help reduce video problems, such as frame jitter, with 200-ms of added delay.

{% hint style="warning" %}
* This feature depends on browser WebRTC playout-delay support. Modern Chromium and Firefox expose receiver buffer controls; Safari and older embedded browsers may not.
* OBS v27.1.3 or older (on PC) uses Chromium v75 though, so you will need to update to OBS 27.2 or newer to use it there.
* The Electron Capture app also supports the `&buffer` command, along with vMix using a compatible Chromium version.
* Using the `&buffer` command may stop [Echo Cancellation](../../source-settings/aec.md) from working due to the audio delay this feature produces.
* Beyond roughly 3 seconds of buffering may cause audio/video sync issues in normal WebRTC mode, and some browsers may clamp or ignore longer requested delays.
{% endhint %}

{% hint style="info" %}
You can refer to the [`&sync`](sync.md) command if you wish to delay the incoming audio relative to the video. `&buffer` will try to delay incoming audio and video together, which is usually desired for jitter smoothing.
{% endhint %}

## Chunked mode

When using \&buffer with a stream that is being sent using chunked-mode ([\&chunked](../../newly-added-parameters/and-chunked.md)), the method of buffering will be different as it doesn't rely on the built-in system playout webRTC buffer delay function.

The practical benefit of using \&chunked mode with \&buffer is that you can have buffers that are minutes long, up to whatever your system's resources can handle.

As well, the buffering works to buffer the stream, in a way similar to HLS or RTMP buffering.\
\
The default buffer is around 1-second actually when using \&chunked mode, as it requires a buffer to avoid playback issues. If the buffer underruns, the stream may fail.

Please refer to \&chunked mode for more details, but it could be an option for you if your goal is to improve the quality of streams when facing high-packet loss. It's only compatible with Chromium-based browsers; not Firefox or Safari as of yet.

## Update in [v23](../../releases/v23.md)

The option to right click a remote video and add/adjust the [`&buffer`](buffer.md) delay for that specific incoming video dynamically. This per-peer control is local to the browser where it is changed; it does not change the sender or other viewers.\
.png>)

## Related

{% content-ref url="../video-parameters/and-buffer2.md" %}
[and-buffer2.md](../video-parameters/and-buffer2.md)
{% endcontent-ref %}

{% content-ref url="sync.md" %}
[sync.md](sync.md)
{% endcontent-ref %}




---
description: Sets the codec to encode the video
---

# \&codec

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&videocodec`
* `&codecs`

## Options

Example: `&codec=h264`

<table><thead><tr><th width="176">Value</th><th>Description</th></tr></thead><tbody><tr><td><a href="codec.md#h264"><code>h264</code></a></td><td>request the h264 codec </td></tr><tr><td><a href="codec.md#vp8"><code>vp8</code></a></td><td>request the VP8 codec </td></tr><tr><td><a href="codec.md#vp9"><code>vp9</code></a></td><td>request the VP9 codec</td></tr><tr><td><a href="codec.md#av1"><code>av1</code></a></td><td>request the AV1 codec</td></tr><tr><td><a href="codec.md#h265-hevc"><code>h265</code></a></td><td>request the H265 codec</td></tr><tr><td><a href="codec.md#webp"><code>webp</code></a></td><td>request the webp codec</td></tr><tr><td><a href="codec.md#hardware"><code>hardware</code></a></td><td>request the h264 codec and<a href="../../newly-added-parameters/and-h264profile.md"><code>&#x26;h264profile</code></a></td></tr><tr><td><a href="codec.md#comma-seperated-update-in-v23-on-alpha"><code>av1,h264</code></a></td><td>Comma separated values that define the order of preferred video codecs if the primary one fails</td></tr></tbody></table>

### Example usage

`https://vdo.ninja/?view=abc123`**`&codec=h264`**\
\
`https://vdo.ninja/?room=xxx7654&scene&bitrate=2000`**`&codec=vp9`**\
\
The `&codec` parameter is added to the viewer-side; so the [`&view`](view.md) or [`&scene`](scene.md) link.

### **Description**

Video that is captured by a camera is compressed and sent over VDO.Ninja. The default codec is left up to the peer-connection to decide on, where the viewer and the sender agree on what is best automatically.

Normally VP8 is selected, which is an older codec that uses little CPU, but isn't as efficient as some others. Some mobile devices may hardware-encoder VP8, such as Google Pixel phones, but the vast majority will use software (CPU) to encode VP8.

H264 is the second most common codec automatically selected, which is popular with Apple-devices and many Android devices. H264 is commonly hardware-encoded, which \*sometimes\* uses less CPU and battery power, but hardware-encoding is more fickle than software-based encoding.

VP9 and AV1 are more modern codecs, with AV1 only supported by Chromium-based browsers using Version 90 or newer, although. VP9 may not be available on older Apple devices, but is becoming more available. It is not common to find VP9 or AV1 hardware encoded currently.

Hardware-encoding has pros and cons. A device generally has limited hardware-encoders, and they are also normally more problematic, including compatibility issues.

{% hint style="warning" %}
**If running into problems with video distortion, switching the codec to VP9 may resolve the issue, although at the cost of higher-CPU load.**
{% endhint %}

## Details

### **H264**

H264 may offer hardware encoding for better battery life with mobile and embedded devices. In these causes, it is often used automatically by VDO.Ninja. Support for H264 on Android devices is hit and miss though, so if enabling it, be prepared for it to potentially result in no video playback.

iOS devices should generally use H264, but the max resolution supported then is 1280x720p30 with iOS 14 and under. With iOS 15, 1080p30 is supported, but I'm not entirely sure if 1080p30 is hardware-encoded as the phone will get quite warm at that resolution.

macOS systems generally prefer H264 and will sometimes hardware-encode. It seems to use less CPU resources decoding H264 versus other codecs, so give it a go if facing CPU issues on your mac.

As for Windows PCs, if using a Chromium-based browsers (Chrome/Edge), your system may choose to use hardware-encoding when using publishing via a H264. This typically happens at 360p or higher resolutions, but it may not always happen. You can check to see if you are hardware-encoding by checking your video out stats, via `CTRL + Left-Click` on your video: "External Encoder" would likely indicate hardware acceleration of some sort.

If you have an Nvidia graphics card, you may be limited to two or three H264 hardware encoders, which could cause problems if you intend to use NVEnc for RTMP streaming also. AMD hardware encoders may limit bitrate.

On PC, while H264 encoding will use less CPU than other codecs, hardware-encoders may actually use more CPU than the software-based ones.

H264 doesn't seem to offer the picture quality, at least when screen sharing, but it seems more resistant to rainbow puke in OBS 27.1 and older.

Firefox on Apple M1 chips may not support H264. OperaGX may also not support H264.

#### Customizing H264 further

Starting with VDO.Ninja [v20](../../releases/v20.md), you can specify the flavour of H264 being used with the [`&h264profile`](../../newly-added-parameters/and-h264profile.md) flag.

Using that parameter without specifying a particular H264 profile ID will trigger the software OpenH264 encoder to be used, blocking any hardware H264 encoder. On Windows, OpenH264 may actually use less CPU than the a hardware encoder and may side step video glitching issues.

Definitely worth trying to use this flag, in combination with `&codec=h264`, if you're looking to inch out every bit of performance, but testing is needed if going this direction.

### **VP8**

VP8 is the default codec selected in most cases, even though Apple devices may default to H264.

OBS on PC does not handle packet loss well when using VP8, while the [Electron Capture](https://github.com/steveseguin/electroncapture) app handles VP8 very well.

iOS devices can stream at 1080p30 or 720p60 when using VP8, but they get warm in doing so.

Google Pixel smartphones may default to VP8, using hardware-encoding, but may also face video distortion with some browsers as a result. Switching to VP9 may fix the issue.

VP8 generally uses more CPU than H264, but not by a lot. Maybe there's a 5 to 15% difference? You may wish to consider using H264 if CPU load is an issue as a result.

VP8 is highly compatible these days between devices and browsers.

### **VP9**

VP9 offers better compression than VP8, but it is also more CPU-intensive to use. It might use 25 to 30% more CPU than H264, but can offer potentially a cleaner image than VP8 or H264, especially with screen-shares.

VP9 seems to reduce the chance of "rainbow puke" video problems in OBS Studio vs VP8.

Do not feel compelled to stream at HD resolutions; even 540p can look good and runs much cooler.

VP9 is often not hardware encoded, so it may solve video distortion issues that persist with H264 or even VP8.

### **AV1**

AV1 is the most advanced codec, but also the most CPU-intensive to use.

Requires Chrome v90 or newer on both publisher and viewer to work. The Electron Capture app 2.6.0 and newer supports AV1, as well. OBS Studio v27.2 and newer \*may\* also support it, but as of the time of this writing, that hasn't been confirmed.

Experimental at this point in time and may not perform well, but if very bandwidth constrained, it is a worthwhile option.

### H265 / HEVC

H265, also known as HEVC or H.265, is a fairly modern and yet common video codec, capable of high-efficiency video compression. It's non-free however, so its availability in browsers has historically been limited.

**Good news!** Starting from Chrome version 136 and above, H.265/HEVC is now supported natively for WebRTC without requiring any special configuration. This native support works on Windows and macOS out of the box, while Linux users will need VAAPI support.

**Browser Support:**

* **Chrome/Chromium v136+**: Native support (no configuration needed)
* **Safari-based browsers**: Native support
* **Thorium browser**: Native support
* **Chrome/Chromium v135 and below**: Manual enablement required (see below)
* **Firefox and other browsers**: Generally not supported

**For older Chrome versions (v135 and below)**, you can try enabling H265 support manually by using the following command line to start your Chrome instance:

```
chrome.exe --enable-features=PlatformHEVCEncoderSupport,WebRtcAllowH265Receive,WebRtcAllowH265Send --force-fieldtrials=WebRTC-Video-H26xPacketBuffer/Enabled
```

 (1) (1) (1).png>)

For more help with enabling H265 on your browser, or to see if your browser currently supports it, please see: [https://vdo.ninja/h265](https://vdo.ninja/h265)

### WEBP

{% content-ref url="webp.md" %}
[webp.md](webp.md)
{% endcontent-ref %}

### HARDWARE

The parameter `&codec=hardware` is Android-specific and is the same as doing `&codec=h264`[`&h264profile`](../../newly-added-parameters/and-h264profile.md), but perhaps easier to remember. Worth trying if your android phone is struggling to publish video at a high enough quality into OBS. I may expand on this feature to be smarter.

### Prioritize a list of codecs

`&codec` can now accept comma separated values that define the order of preferred video codecs if the primary one fails. You might want this it you want AV1 to be the main codec, falling back to H264 rather than VP8 if not supported. ie: `&codec=av1,h264`

### Figuring out what encoders your browser supports

I've created this page to help you list what encoders are available on your system, for a variety of different purposes. [https://vdo.ninja/codecs](https://vdo.ninja/codecs)

## Related

{% content-ref url="../../newly-added-parameters/and-h264profile.md" %}
[and-h264profile.md](../../newly-added-parameters/and-h264profile.md)
{% endcontent-ref %}

{% content-ref url="webp.md" %}
[webp.md](webp.md)
{% endcontent-ref %}

{% content-ref url="../recording-parameters/and-recordcodec.md" %}
[and-recordcodec.md](../recording-parameters/and-recordcodec.md)
{% endcontent-ref %}




---
description: >-
  Has the videos fully "cover" their assigned areas, even if it means cropping
  the video
---

# \&cover

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Details

Can be used to have a video be zoomed in and cropped, so it fills its window area completely. Useful if you don't want any gaps between videos.

On the left you see two video feeds in a scene without using `&cover` and on the right with using `&cover`:\
 (3) (1).png>) (1) (2) (1).png>)

## \&cover=2

If you set the value to 2, it will only apply the cover effect so the video is cropped horizontally. It will not crop the vertical area. This is available in VDO.Ninja version 27.5 and newer.

[https://vdo.ninja/alpha/?scene\&room=asdfasdfasdf\&fakeguests=2\&rows=1\&cover=2](https://vdo.ninja/alpha/?scene\&room=asdfasdfasdf\&fakeguests=2\&rows=1\&cover=2)\
\

<figure><figcaption></figcaption></figure>

## Related

{% content-ref url="and-portrait.md" %}
[and-portrait.md](and-portrait.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-square.md" %}
[and-square.md](../../newly-added-parameters/and-square.md)
{% endcontent-ref %}

{% content-ref url="../design-parameters/rounded.md" %}
[rounded.md](../design-parameters/rounded.md)
{% endcontent-ref %}




---
description: Overrides the automatically selected Device Pixel Ratio
---

# \&dpi

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&dpr`

## Options

Example: `&dpi=2`

| Value             | Description                 |
| ----------------- | --------------------------- |
| `1`               | Set Device Pixel Ratio to 1 |
| `2`               | Set Device Pixel Ratio to 2 |
| `3`               | Set Device Pixel Ratio to 3 |
| (integer value X) | Set Device Pixel Ratio to X |

## Details

This allows a user to override the automatically selected Device Pixel Ratio value. It is often either 1 or 2 by default, depending on your display's DPI setting.

An accurate DPI value is important for calculating the correct requested resolution of a video. For high density displays, you'll want to have a higher resolution of video, especially in the case of the Electron Capture app, where the reported resolution isn't the same as the displayed resolution.

Changing this value can provide for higher quality or lower quality video on playback, a bit like changing the [`&scale`](scale.md) value, but dynamic to the current window-size of the video being played back.

## Related

{% content-ref url="../video-parameters/and-sharper.md" %}
[and-sharper.md](../video-parameters/and-sharper.md)
{% endcontent-ref %}

{% content-ref url="../screen-share-parameters/and-sharperscreen.md" %}
[and-sharperscreen.md](../screen-share-parameters/and-sharperscreen.md)
{% endcontent-ref %}

{% content-ref url="scale.md" %}
[scale.md](scale.md)
{% endcontent-ref %}




---
description: >-
  Tells the remote source that you would like them to prioritize the audio
  stream over other streams
---

# \&enhance

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Details

Tells the remote source that you would like them to prioritize the audio stream over other streams.

* May not be compatible with all remote sources; depends on the browser they have
* Prioritizing audio may cause problems elsewhere, such as for other viewers or for video streams
* Prioritization applies to both encoding and networking sending of audio packets
* May override custom ptime values
* This option may be useful in reducing audio 'clicking', but likely will be just as effective as a placebo

For advanced users, this sets the following of the audio's stream: `networkPriority = "high";` `priority = "high";` `adaptivePtime = true;`

For more details, please see:\
[https://www.w3.org/TR/webrtc-priority/#dom-rtcrtpencodingparameters-networkpriority](https://www.w3.org/TR/webrtc-priority/#dom-rtcrtpencodingparameters-networkpriority)




---
description: Has videos fade in smoothly
---

# \&fadein

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Values

Example: `&fadein=400`

| Value            | Description                           |
| ---------------- | ------------------------------------- |
| (no value given) | fades in video in 500-ms              |
| (value in ms)    | value in ms for the fade in animation |

## Details

Has videos fade in smoothly in 500-ms. You can pass a custom fade in time in milliseconds.

Also available as a director's room toggle for scenes.

.png>)

## Related

{% content-ref url="animated.md" %}
[animated.md](animated.md)
{% endcontent-ref %}




---
description: Let you set font-size of the closed captions and stream labels
---

# \&fontsize

General Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md), [`&view`](view.md), [`&scene`](scene.md))

## Aliases

* `&labelsize`
* `&sizelabel`

## Options

Example: `&fontsize=70`

| Value           | Description                     |
| --------------- | ------------------------------- |
| (integer value) | font size value as a percentage |

## Details

Lets you set font-size of the [guest labels](../design-parameters/showlabels.md) or [closed captions](../settings-parameters/and-closedcaptions.md).

## Related

{% content-ref url="../settings-parameters/and-closedcaptions.md" %}
[and-closedcaptions.md](../settings-parameters/and-closedcaptions.md)
{% endcontent-ref %}

{% content-ref url="../design-parameters/showlabels.md" %}
[showlabels.md](../design-parameters/showlabels.md)
{% endcontent-ref %}




---
description: This tells the remote publishers to send keyframes at a specified rate
---

# \&keyframerate

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&keyframeinterval`
* `&keyframe`
* `&kfi`

## Options

Example: `&keyframerate=2000`

| Value           | Description    |
| --------------- | -------------- |
| (integer value) | interval in ms |

## Details

`&keyframerate` tells the remote publishers to send keyframes at a specified rate.

Could be useful if packet loss is causing a lot frame corruption.

If you make it less than 1000-ms, you will face a pretty steep drop in video quality.

It may not work at all if set too low; under 500-ms didn't work at all in my testing.




---
description: Disables the auto-mixer, allowing for a custom mixer to be used
---

# \&manual

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Details

This is an advanced feature, for primarily developers, who wish to utilize their own auto-mixing code or perhaps are not using VDO.Ninja for video/audio specifically.

`session.rpcs` is an object that can be queried for a list of active receiving peer sessions. `session.rpcs[UUID].videoElement.srcObject` contains video/audio data if available.

## Related

{% content-ref url="../../guides/iframe-api-documentation.md" %}
[iframe-api-documentation.md](../../guides/iframe-api-documentation.md)
{% endcontent-ref %}




---
description: Minimum packet size of audio
---

# \&minptime

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&minptime=20`

| Value           | Description               |
| --------------- | ------------------------- |
| (integer value) | minimum audio packet size |

## Details

{% hint style="danger" %}
If you do not know what this is, you definitely don't want to touch it.
{% endhint %}

Minimum packet size of audio in ms. 10-ms is lowest that you can set in Chromium I think.

Optimized already, but it's available for experimentation and fun if desired.

## Related

{% content-ref url="and-ptime.md" %}
[and-ptime.md](and-ptime.md)
{% endcontent-ref %}

{% content-ref url="and-maxptime.md" %}
[and-maxptime.md](and-maxptime.md)
{% endcontent-ref %}




---
description: Has the inbound audio playback as mono audio
---

# \&mono

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Details

If using [`&proaudio`](../audio-parameters/and-proaudio.md), this will retain the publishing benefits of [`&proaudio`](../audio-parameters/and-proaudio.md), while keeping the audio as mono instead of stereo.

Audio bitrates may be reduced from 256-kbps to 128-kbps, if not explicitly stated, in some cases.

{% hint style="warning" %}
In Version 22 `&mono` also works with Firefox.
{% endhint %}

To set the source to mono, see [`&monomic`](../audio-parameters/and-monomic.md).

## Related

{% content-ref url="../audio-parameters/and-monomic.md" %}
[and-monomic.md](../audio-parameters/and-monomic.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/stereo.md" %}
[stereo.md](../../general-settings/stereo.md)
{% endcontent-ref %}




---
description: Delivers video only streams; audio playback is disabled
---

# \&noaudio

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&na`
* `&hideaudio`

## Details

Delivers video only streams; audio playback is disabled for all incoming streams. `&noaudio` also hides the speaker button.

You can pass a comma separated list of stream IDs that will be excluded, so that they specifically will play audio. `?noaudio=guest1a,guest2a` will only allow audio from guest1a and guest2a to play

External Iframes may or may not be muted by default if using \&noaudio. While I try to mute frames when possible, like embedded Youtube videos, there may be still some Iframe sources I cannot mute.

`&exludeaudio` can also be used to specify certain stream IDs that will NOT play audio, so the inverse of `&noaudio`

If you want to be able to unmute the speaker button during production, use [`&mutespeaker`](../../source-settings/and-mutespeaker.md) instead of `&noaudio`.&#x20;

[`&deafen`](../../general-settings/deafen.md) also disables monitoring your own audio, then it's impossible to get any sound from VDO.Ninja.

## Related

{% content-ref url="../audio-parameters/and-nodirectoraudio.md" %}
[and-nodirectoraudio.md](../audio-parameters/and-nodirectoraudio.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/and-mutespeaker.md" %}
[and-mutespeaker.md](../../source-settings/and-mutespeaker.md)
{% endcontent-ref %}

{% content-ref url="../../general-settings/deafen.md" %}
[deafen.md](../../general-settings/deafen.md)
{% endcontent-ref %}

{% content-ref url="../video-parameters/and-novideo.md" %}
[and-novideo.md](../video-parameters/and-novideo.md)
{% endcontent-ref %}




---
description: Random video loading order
---

# \&randomize

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&random`

## Details

Forces the videos in a room to have a random loading order.




---
description: Scales the video resolution of the inbound video by the given percent
---

# \&scale

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&scale=100`

| Value                             | Description                                                        |
| --------------------------------- | ------------------------------------------------------------------ |
| (integer value between 0 and 100) | scale the incoming video feed by this percentage                   |
| `100`                             | doesn't allow the incoming video feed to scale down the resolution |

## Details

Example: If the video inbound has a resolution of 1920x1080, `&scale=50` would limit the resolution to 960x540 instead.

The nice thing about this is that it doesn't matter which resolution their camera supports; the scale is software based and doesn't care about resolutions or aspect ratios.

This can help a viewer reduce frame stuttering, CPU load, and improve frame rates, without having to have the guest rejoin the stream.

Requires the publisher of the stream to support dynamic scaling; Firefox and Chrome should be supported.

There is a toggle in the director's room to add `&scale=100` to the scene URL:\
 (1) (1) (1) (1).png>)

## Related

{% content-ref url="../video-parameters/and-sharper.md" %}
[and-sharper.md](../video-parameters/and-sharper.md)
{% endcontent-ref %}

{% content-ref url="../screen-share-parameters/and-sharperscreen.md" %}
[and-sharperscreen.md](../screen-share-parameters/and-sharperscreen.md)
{% endcontent-ref %}

{% content-ref url="dpi.md" %}
[dpi.md](dpi.md)
{% endcontent-ref %}




---
description: Defines the link to be treated like a scene
---

# \&scene

Viewer-Side Option! ([`&room`](../../general-settings/room.md))

## Aliases

* `&scn`

## Options

Example: `&scene=2` or `&scene=choosethename`

| Value                   | Description                                             |
| ----------------------- | ------------------------------------------------------- |
| `0` \| (no value given) | auto-add all videos to the scene; they can't be removed |
| `1`                     | empty by default; manually add videos in                |
| (string)                | like `&scene=1`, but videos are not preloaded           |

## Details

{% hint style="info" %}
Must be used in conjunction with the [`&room`](../../general-settings/room.md) parameter.&#x20;
{% endhint %}

By adding `&scene` to a room URL, it tells VDO.Ninja that this is no [`&push`](../../source-settings/push.md) connection.

`&scene=0` by default has all videos in the room automatically added to the scene. They cannot be removed.

* `&scene=1` by default has no videos added to the scene. Videos need to be added manually by the director. Videos not yet added to the scene are connected, and streaming at around 400-kbps, so when they become active they appear immediately. Bitrate will ramp up after a second to the target bitrate of, normally, 2500-kbps or whatever is set via the URL.\
   (1).png>)
* `&scene=2` is like `&scene=1`, except the video streams that are not yet added to the scene are disabled with 0-bitrate used. They are connected, but not actively streaming any video data, so it takes a moment longer for videos to appear once added.
*   `&scene=N`, where `N` is a string or integer - it's just like `&scene=2`. There are buttons marked S3, S4, .. S8 in the director's room to control these scene types. If they are not already there, new buttons for them will be created automatically when used. See the video below.\

* When using a scene, if you manually specify a video via the [`&view`](view.md) parameter, it automatically is added to the scene.
* Audio of videos in scenes can be controlled by the director: volume and mute are options.
* In [v17.2](broken-reference) of VDO.Ninja, if using [`&view`](view.md) in a scene link, the director won't be able to remotely control the scene. This applies to solo links.
* In [v18](../../releases/v18/), you can create custom scenes, as per the video below.

{% embed url="https://www.youtube.com/embed/axgIqPcHExQ" %}

### Optimize scene performance using \&optimize=0&#x20;

If using a normal manual scene, such as \&scene=3, you can add [\&optimize=0](scene.md#alternative-using-and-optimize-0) to the scene URL to enable a mode that is similar to \&solo. It's one of a few different ways to have permanent generic scene links that you can place specific guests into with varying stream IDs. There's also slots, however \&optimize=0 is tweaked for low CPU and network usage, at the cost of a slight added delay in adding a guest to the scene

## Related

{% content-ref url="../../general-settings/room.md" %}
[room.md](../../general-settings/room.md)
{% endcontent-ref %}

{% content-ref url="../mixer-scene-parameters/and-solo.md" %}
[and-solo.md](../mixer-scene-parameters/and-solo.md)
{% endcontent-ref %}

{% content-ref url="../video-bitrate-parameters/optimize.md" %}
[optimize.md](../video-bitrate-parameters/optimize.md)
{% endcontent-ref %}




---
description: >-
  Tells VDO.Ninja to not block VDO.Ninja from attempting to run when using
  Streamlabs for MacOS
---

# \&streamlabs

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Details

Tells VDO.Ninja to not block VDO.Ninja from attempting to run when using Streamlabs for MacOS.

For normal OBS users, update to OBS 26.1.2 on MacOS to obtain native support for VDO.Ninja in OBS.

Streamlabs doesn't yet have full support for VDO.Ninja; consider the [Electron Capture](../../steves-helper-apps/electron-capture.md) app if it fails to work well.




---
description: Sets an offset (in ms) for the automatic audio sync fix node
---

# \&sync

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Options

Example: `&sync=50`

| Value           | Description |
| --------------- | ----------- |
| (integer value) | value in ms |

## Details

`&sync=X` is a viewer-side option that sets an offset in milliseconds for incoming audio playback. Positive values delay audio relative to video, which can help when the audio is arriving or playing early.

[`&buffer=0`](../../advanced-settings.md#buffer) or `&sync=0` will do the same thing: it will try to auto-sync video and audio.

Tiny negative offsets _may_ work, like `&sync=-25` is possible, but large negative offsets will not work. If audio is already late, `&sync` cannot cleanly fix that by delaying video; try `&buffer`/`&audiobuffer` combinations on the viewer or fix the sender path instead.

Support depends on the browser/player exposing the needed WebRTC audio pipeline controls. It works in modern Chromium/Chrome; OBS and other embedded browsers depend on the Chromium version they ship. Firefox support should be verified for the specific build being used.

`&sync=500` without the [`&buffer`](buffer.md) command only adds an audio delay; there will be no additional video buffer or delay. The setting applies to the viewer URL that contains it, so it is only effectively per-guest if that URL is viewing only that guest.

{% hint style="info" %}
Using this may stop [Echo Cancellation](../../source-settings/aec.md) from working.
{% endhint %}

## Related

{% content-ref url="buffer.md" %}
[buffer.md](buffer.md)
{% endcontent-ref %}

{% content-ref url="../video-parameters/and-buffer2.md" %}
[and-buffer2.md](../video-parameters/and-buffer2.md)
{% endcontent-ref %}




---
description: Sets the audio bitrate to be variable, instead of constant
---

# \&vbr

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Details

Sets the audio bitrate to be variable, instead of constant, but only when an audio bitrate is manually specified.

By default, Chrome uses a variable bitrate with a cap at around 32-kbps with mono-audio.

When manually specifying a bitrate, Chrome keeps the audio bitrate pretty constant, even if VBR is turned on.

## Related

{% content-ref url="audiobitrate.md" %}
[audiobitrate.md](audiobitrate.md)
{% endcontent-ref %}




---
description: Defines the stream(s) you are receiving, by their stream IDs
---

# \&view

Viewer-Side Option! ([`&scene`](scene.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&streamid`
* `&pull`
* `&v`

## Options

Example: `&view=StreamID1,StreamID2`

<table><thead><tr><th width="188">Value</th><th>Description</th></tr></thead><tbody><tr><td>(string value)</td><td>stream ID to view; can be a comma-separated list of IDs</td></tr><tr><td>(no value given)</td><td>in a room, you don't see any other guests including the director</td></tr></tbody></table>

## Details

`&view` defines the stream or streams you are receiving, by their stream IDs.

[https://vdo.ninja/?push=streamid](https://vdo.ninja/?push=streamid)\
[https://vdo.ninja/?view=streamid](https://vdo.ninja/?view=streamid)

Optional if you are publishing a stream using [`&push`](../../source-settings/push.md).\
If the `&view` parameter is not added, the default behaviour will occur.\
If the `&view` parameter is provided, it will try to play any stream listed.\
If the `&view` parameter is provided, but no values are provided, no streams will play; only publishing will be allowed.

This is useful is you wish to publish a video into a group chat room, but only view video from specific known participants.\
This is also useful if you wish to create ad-hoc group chat sessions without using a group room.\
Videos will auto-load when they are available if not already.

You can use `&view` in a room combined with [`&scene`](scene.md) or [`&solo`](../mixer-scene-parameters/and-solo.md) to watch one or more specified video feeds of the room:\
`https://vdo.ninja/?room=roomname&scene&view=streamid1,streamid2`

## Related

{% content-ref url="../../getting-started/multi-person-chat.md" %}
[multi-person-chat.md](../../getting-started/multi-person-chat.md)
{% endcontent-ref %}

{% content-ref url="../../source-settings/push.md" %}
[push.md](../../source-settings/push.md)
{% endcontent-ref %}

{% content-ref url="scene.md" %}
[scene.md](scene.md)
{% endcontent-ref %}

{% content-ref url="../mixer-scene-parameters/and-include.md" %}
[and-include.md](../mixer-scene-parameters/and-include.md)
{% endcontent-ref %}




---
description: Custom video codec for broadcasts
---

# \&webp

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

{% hint style="info" %}
V22: Sender-Side Option! ([`&push`](../../source-settings/push.md))
{% endhint %}

## Aliases

* `&images`

## Options

Example: `&webp=jpeg`

| Value            | Description       |
| ---------------- | ----------------- |
| (no value given) | webp image format |
| `jpeg`           | jpeg image format |

## Details

#### Changes on Version 22 of VDO.Ninja

The `&webp` mode has been modified a bit. Main change is that you now enable it by add `&webp` to the sender's URL, and [`&codec=webp`](codec.md) to the viewer's URL (otherwise, it falls back to normal video mode). No need for [`&broadcast`](broadcast.md) anymore. (as a reminder, this mode sends the video as a series of low-quality images, rather than a more efficient video stream).

I've removed the toggle in the director's room for this `&webp` feature, as [`&chunked`](../../newly-added-parameters/and-chunked.md) mode is replacing its purpose there, but you might still want to use this mode when the viewer-side does not support video playback or hardware acceleration. Specifically, this option lets you bring motion images (aka, crude video) into the streamlabs mobile app, as a browser source, where other forms of video decoding is not supported.

#### Version 21 and backwards

In Version 21 and backwards it must be used with [`&broadcast`](broadcast.md) on the viewer side but the director doesn't need to be the designated broadcaster.

The Electron Capture app should work to allow for webp-based broadcasting even if the tab is not visible, as tab throttling is disabled with that application.\
This is essentially a stream of webp-based images sent over the webRTC data-channels.\
The quality by default is limited in both frame rate and resolution, as this custom video codec is very inefficient at higher resolutions and frame-rates.

Based on my testing, the webp mode is only efficient if you are keeping the bitrates under like 2 mbps, so the higher qualities make little sense IMO outside of some niche use cases as they use up a lot of bandwidth.

If you have issues with Webp-mode, or find the quality or CPU savings not sufficient, you can check out the [`&meshcast`](../../newly-added-parameters/and-meshcast.md) integration instead. It's a relatively new supported addition to VDO.Ninja.

#### Details

Default quality is 270p @ 10-fps webp. You can change this with [`&webpquality`](webpquality.md) to increase resolution and max frame rate.

The default frame rate is a target, but if the connection cannot keep up, a lower frame rate will be used. This ensures the lowest latency possible.

Compression quality is set to 66% in all cases. This seems the best bang for buck.

This mode can work with audio, which uses the normal audio mode for transport.  Audio and these motion images stay roughly in sync.

{% content-ref url="../../guides/iframe-api-documentation.md" %}
[iframe-api-documentation.md](../../guides/iframe-api-documentation.md)
{% endcontent-ref %}

{% embed url="https://www.youtube.com/watch?v=-7QsLChfdsE" %}

## Related

{% content-ref url="webpquality.md" %}
[webpquality.md](webpquality.md)
{% endcontent-ref %}

{% content-ref url="codec.md" %}
[codec.md](codec.md)
{% endcontent-ref %}

{% content-ref url="../../newly-added-parameters/and-chunked.md" %}
[and-chunked.md](../../newly-added-parameters/and-chunked.md)
{% endcontent-ref %}




---
description: Quality setting for the &webp option
---

# \&webpquality

Viewer-Side Option! ([`&view`](view.md), [`&scene`](scene.md), [`&room`](../../general-settings/room.md))

{% hint style="info" %}
V22: Sender-Side Option! ([`&push`](../../source-settings/push.md))
{% endhint %}

## Aliases

* `&webpq`
* `&wq`

## Options

Example: `&webpquality=1`

| Value | Description    |
| ----- | -------------- |
| `0`   | 1080p          |
| `1`   | 720p           |
| `2`   | 540p           |
| `3`   | 360p           |
| `4`   | 270p           |
| `5`   | 270p @ 15-fps  |
| `6`   | 270p @ 5-fps   |
| `7`   | 270p @ 2.5-fps |
| `8`   | 360p @ 1-fps   |

## Details

You add this parameter to the director (or designated broadcaster) and it then sets the quality target for the [`&webp`](../../advanced-settings.md#webp) mode.

Default is 270p @ 10-fps.

Compression quality is set to 66% in all cases. This seems the best bang for buck. Unless specified, this is also webp.

## Related

{% content-ref url="webp.md" %}
[webp.md](webp.md)
{% endcontent-ref %}




---
description: Options for the &whip parameter
---

# WHIP Parameters

**WHIP Parameters** are specific to the[ WHIP and WHEP tooling](../../steves-helper-apps/whip-and-whep-tooling.md).

## Viewer side options

<table><thead><tr><th width="335.57142857142856">Parameter</th><th>Explanation</th></tr></thead><tbody><tr><td><a href="and-whipout.md"><code>&#x26;whipout</code></a></td><td>Publish directly from OBS (or other) to VDO.Ninja without a virtual camera</td></tr><tr><td><a href="and-whip.md"><code>&#x26;whipview</code></a></td><td>Publish directly from OBS (or other) to VDO.Ninja without a virtual camera</td></tr><tr><td><a href="and-whipoutcodec.md"><code>&#x26;whipoutcodec</code></a></td><td>Lets you specify the WHIP video output codec</td></tr><tr><td><a href="and-whipoutaudiobitrate.md"><code>&#x26;whipoutaudiobitrate</code></a></td><td>Lets you specify the WHIP audio bitrate (kbps)</td></tr><tr><td><a href="and-whipoutvideobitrate.md"><code>&#x26;whipoutvideobitrate</code></a></td><td>Lets you specify the WHIP video bitrate (kbps)</td></tr><tr><td><a href="and-whipoutscale-alpha.md"><code>&#x26;whipoutscale</code></a>*</td><td>Scales down the WHIP video output via the URL</td></tr><tr><td><a href="and-whipoutscreensharecodec-alpha.md"><code>&#x26;whipoutscreensharecodec</code></a>*</td><td>Option to change codec of the WHIP while screen-sharing</td></tr><tr><td><a href="and-whipoutscreensharebitrate-alpha.md"><code>&#x26;whipoutscreensharebitrate</code></a>*</td><td>Option to change outbound screen-share video bitrate of WHIP</td></tr><tr><td><a href="and-cftoken-alpha.md"><code>&#x26;cftoken</code></a>*</td><td>Accepts the special token without needing to specify the cloudflare.vdo.ninja part if using <a href="and-whipout.md"><code>&#x26;whipout</code></a> instead</td></tr><tr><td><a href="and-svc.md"><code>&#x26;svc</code></a>*</td><td>Useful for publishing to WHIP broadcast servers that support scalable video modes</td></tr></tbody></table>

\*NEW IN [VERSION 24](../../releases/v24.md)




---
description: >-
  Accepts the special token without needing to specify the cloudflare.vdo.ninja
  part if using &whipout instead
---

# \&cftoken

[WHIP Option](../../steves-helper-apps/whip-and-whep-tooling.md) / Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&cft`

## Options

Example: `&cftoken=token`

<table><thead><tr><th width="154">Value</th><th>Description</th></tr></thead><tbody><tr><td>(string value)</td><td>Accepts the special token without needing to specify the cloudflare.vdo.ninja part if using <a href="and-whipout.md"><code>&#x26;whipout</code></a> instead</td></tr></tbody></table>

## Details

If using a cloudflare.com WHIP URL on the sender side, I'll guess at the WHEP link - seems to be working so far. (built this logic into VDO.Ninja directly and works automatically). This of course still implies a unique whip URL per guest.

<figure><figcaption></figcaption></figure>

To make using Cloudflare easier though, I've also created the WHIP end point `cloudflare.vdo.ninja`, which takes a Cloudflare API token, instead of a stream token.

This special end point will auto-create a unique WHEP URL. The official cloudflare.com whip endpoint can only be used by one sender at a time, but this API special endpoint and token approach can be used by many senders at a time. It automatically generates unique WHIP/WHEP when used, in the same way Meshcast does, so no need for unique invite urls per guest.

I've created a page to generate the required special api token; the page also provides further information on this all: [https://vdo.ninja/alpha/cloudflare](https://vdo.ninja/alpha/cloudflare)

`&cftoken` accepts the special token without needing to specify the cloudflare.vdo.ninja part if using [`&whipout`](and-whipout.md) instead.

I focused mainly on adding Cloudflare support first, as it has good pricing for its WHIP/WHEP service, it doesn't require deploying anything, and it has a lot of features (RTMP, SRT, recording, API). It's not 100% cooked yet though, so it's just on alpha currently for testing.

## Related

{% content-ref url="../../steves-helper-apps/whip-and-whep-tooling.md" %}
[whip-and-whep-tooling.md](../../steves-helper-apps/whip-and-whep-tooling.md)
{% endcontent-ref %}

{% content-ref url="and-whipout.md" %}
[and-whipout.md](and-whipout.md)
{% endcontent-ref %}




---
description: >-
  Useful for publishing to WHIP broadcast servers that support scalable video
  modes
---

# \&svc

[WHIP Option](../../steves-helper-apps/whip-and-whep-tooling.md) / Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&scalabilitymode`

## Options

Example: `&svc=L1T3`

<table><thead><tr><th width="167">Value</th><th>Description</th></tr></thead><tbody><tr><td>(SVC value)</td><td>Takes an SVC value, with <code>L1T3</code> being the most universal option, but other options exist</td></tr></tbody></table>

## Details

`&svc` is useful for publishing to WHIP broadcast servers that support scalable video modes. Takes an SVC value, with `L1T3` being the most universal option, but other options exist. You'll get an error when publishing if you use an invalid one.

<div align="left">

<figure><figcaption></figcaption></figure>

</div>

There are SVC scalable options to the WHIP output option on [https://vdo.ninja/whip](https://vdo.ninja/whip), making it easy to select a compatible SVC mode if desired.

Experiment with this feature here:\
[https://webrtc.github.io/samples/src/content/extensions/svc/](https://webrtc.github.io/samples/src/content/extensions/svc/)

## Related

{% content-ref url="../../steves-helper-apps/whip-and-whep-tooling.md" %}
[whip-and-whep-tooling.md](../../steves-helper-apps/whip-and-whep-tooling.md)
{% endcontent-ref %}

{% embed url="https://vdo.ninja/whip" %}




---
description: Publish directly from OBS (or other) to VDO.Ninja without a virtual camera
---

# \&whipview

Viewer-Side Option! ([`&scene`](../view-parameters/scene.md), [`&room`](../../general-settings/room.md), [`&director`](../../viewers-settings/director.md))

## Aliases

* `&whip`

## Options

Example: `&whipview=bearertoken`

| Value          | Description           |
| -------------- | --------------------- |
| (string value) | bearer token from OBS |

## Details

Added experimental "WHIP" support to VDO.Ninja, which means in the near future you'll be able to publish directly from OBS to VDO.Ninja without a virtual camera. There's some big caveats to it all, so I don't recommend it over the normal method to most users, but we'll see how it evolves.

To publish use: [https://whip.vdo.ninja/bearertoken](https://whip.vdo.ninja/bearertoken)\
To view use: [https://vdo.ninja/?whip=bearertoken](https://vdo.ninja/?whip=bearertoken)

You can also go to [https://vdo.ninja/alpha/whip](https://vdo.ninja/alpha/whip) for a page to help auto-generate basic VDO.Ninja WHIP links for you.

You have to use a version of OBS that contains WHIP support to get OBS to WHIP working. As of April 2023, these are some builds of OBS that support WHIP:\
[https://github.com/obsproject/obs-studio/suites/12263428876/artifacts/649328007](https://github.com/obsproject/obs-studio/suites/12263428876/artifacts/649328007) win (x64)\
[https://github.com/obsproject/obs-studio/suites/12263428876/artifacts/649328001](https://github.com/obsproject/obs-studio/suites/12263428876/artifacts/649328001) mac (arm)\
[https://github.com/obsproject/obs-studio/actions/runs/4711358202?pr=7926](https://github.com/obsproject/obs-studio/actions/runs/4711358202?pr=7926) (others here)

Hopefully WHIP support will be in OBS officially sometime soon. WHIP support is already added to many other applications and services, and VDO.Ninja will do its best to ensure compatibility as the situation evolves.

See this video for details how to set up OBS WHIP to VDO.Ninja:

{% embed url="https://youtu.be/ynSOE2d4Z9Y" %}
Publishing from OBS directly to VDO.Ninja
{% endembed %}

I've refined the WHIP service on `vdo.ninja/alpha/?whipview=xxx`, making it as robust as I can I think, so if some third-party WHIP client/app doesn't work with it, it may not an issue with VDO.Ninja. In those cases it will be up to the client to ensure full support of the WHIP specification, else it may not work with VDO.Ninja.

## Related

{% content-ref url="../../guides/publish-from-obs-into-vdo.ninja.md" %}
[publish-from-obs-into-vdo.ninja.md](../../guides/publish-from-obs-into-vdo.ninja.md)
{% endcontent-ref %}




---
description: Publish directly from OBS (or other) to VDO.Ninja without a virtual camera
---

# \&whipout

Sender-Side Option! ([`&push`](../../source-settings/push.md), [`&room`](../../general-settings/room.md))

## Aliases

* `&whippush`
* `&pushwhip`

## Options

Example: `&whipout=bearertoken`

| Value          | Description           |
| -------------- | --------------------- |
| (string value) | bearer token from OBS |

## Details

Added experimental "WHIP" support to VDO.Ninja, which means in the near future you'll be able to publish directly from OBS to VDO.Ninja without a virtual camera. There's some big caveats to it all, so I don't recommend it over the normal method to most users, but we'll see how it evolves.

To publish use: [https://whip.vdo.ninja/bearertoken](https://whip.vdo.ninja/bearertoken)\
To view use: [https://vdo.ninja/?whip=bearertoken](https://vdo.ninja/?whip=bearertoken)

You can also go to [https://vdo.ninja/alpha/whip](https://vdo.ninja/alpha/whip) for a page to help auto-generate basic VDO.Ninja WHIP links for you.

You have to use a version of OBS that contains WHIP support to get OBS to WHIP working. As of April 2023, these are some builds of OBS that support WHIP:\
[https://github.com/obsproject/obs-studio/suites/12263428876/artifacts/649328007](https://github.com/obsproject/obs-studio/suites/12263428876/artifacts/649328007) win (x64)\
[https://github.com/obsproject/obs-studio/suites/12263428876/artifacts/649328001](https://github.com/obsproject/obs-studio/suites/12263428876/artifacts/649328001) mac (arm)\
[https://github.com/obsproject/obs-studio/actions/runs/4711358202?pr=7926](https://github.com/obsproject/obs-studio/actions/runs/4711358202?pr=7926) (others here)

Hopefully WHIP support will be in OBS officially sometime soon. WHIP support is already added to many other applications and services, and VDO.Ninja will do its best to ensure compatibility as the situation evolves.\
\
**UPDATE**: While it's possible OBS v31 fixes this WHIP firewall issue, I do have a custom version of OBS that also has proper VDO.Ninja WHIP support [available for Win64 here.](https://backup.vdo.ninja/OBS_VDO_Ninja.zip) \[[fork](https://github.com/steveseguin/obs-studio)]  This version should let you publish WHIP via VDO.Ninja across the Internet, regardless of Firewall. (This OBS binary was last built November 2024.)

See this video for details how to set up OBS WHIP to VDO.Ninja:

{% embed url="https://youtu.be/ynSOE2d4Z9Y" %}
Publishing from OBS directly to VDO.Ninja
{% endembed %}

A goal for a while has been to allow anyone to drop-in their own Meshcast replacement, using a third-party WHIP/WHEP server/service. That is, publish to a whip-service, and have viewers of the stream get the WHEP-view link, so they can view via WHEP instead of p2p. I've achieved this finally; close enough at least.

There's a few requirements to make it work though, so either an API wrapper is needed or a set of rules needs to be followed:\
\-- If your WHIP server returns an exposed "WHEP" field in the POST response header, with the URL to the WHEP view link, it will use that WHEP link. You just need to then specify the `&whipout` URL on the sender side then.\
\-- This should let you make your own Meshcast service with minimal work; the open-source WHIP API code I released the other day further makes it pretty easy.

I've refined the WHIP service on `vdo.ninja/alpha/?whipview=xxx`, making it as robust as I can I think, so if some third-party WHIP client/app doesn't work with it, it may not an issue with VDO.Ninja. In those cases it will be up to the client to ensure full support of the WHIP specification, else it may not work with VDO.Ninja.

## Related

{% content-ref url="../../steves-helper-apps/whip-and-whep-tooling.md" %}
[whip-and-whep-tooling.md](../../steves-helper-apps/whip-and-whep-tooling.md)
{% endcontent-ref %}

{% content-ref url="and-whip.md" %}
[and-whip.md](and-whip.md)
{% endcontent-ref %}




---
description: Lets you specify the WHIP audio bitrate (kbps)
---

# \&whipoutaudiobitrate

[WHIP Option](../../steves-helper-apps/whip-and-whep-tooling.md) / Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&woab`

## Options

Example: `&whipoutaudiobitrate=128`

| Value           | Description           |
| --------------- | --------------------- |
| (integer value) | audio bitrate in kbps |

## Details

`&whipoutaudiobitrate` lets you specify the WHIP audio bitrate (kbps).

## Related

{% content-ref url="and-whip.md" %}
[and-whip.md](and-whip.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/audiobitrate.md" %}
[audiobitrate.md](../view-parameters/audiobitrate.md)
{% endcontent-ref %}

{% content-ref url="and-whipoutvideobitrate.md" %}
[and-whipoutvideobitrate.md](and-whipoutvideobitrate.md)
{% endcontent-ref %}




---
description: Lets you specify the WHIP video output codec
---

# \&whipoutcodec

[WHIP Option](../../steves-helper-apps/whip-and-whep-tooling.md) / Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&woc`

## Options

Example: `&whipoutcodec=av1`

| Value  | Description |
| ------ | ----------- |
| `av1`  | av1 codec   |
| `h264` | h264 codec  |
| `vp8`  | vp8         |

## Details

Added `&whipoutcodec=` lets you specify the WHIP video output codec. It can take multiple values; if not used, the default at the moment is open264.

## Related

{% content-ref url="and-whip.md" %}
[and-whip.md](and-whip.md)
{% endcontent-ref %}

{% content-ref url="../view-parameters/codec.md" %}
[codec.md](../view-parameters/codec.md)
{% endcontent-ref %}

{% content-ref url="../../guides/publish-from-obs-into-vdo.ninja.md" %}
[publish-from-obs-into-vdo.ninja.md](../../guides/publish-from-obs-into-vdo.ninja.md)
{% endcontent-ref %}




---
description: Scales down the WHIP video output via the URL
---

# \&whipoutscale

[WHIP Option](../../steves-helper-apps/whip-and-whep-tooling.md) / Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&woscale`

## Options

Example: `&whipoutscale=50`

<table><thead><tr><th width="260">Value</th><th>Description</th></tr></thead><tbody><tr><td>(percentage 1 to 100)</td><td>will scale down the video to the percentage given</td></tr></tbody></table>

## Details

The `&whipoutscale` parameter will scale down the WHIP video output via the URL, post camera capture setup. You may wish to use this to lower the resolution if your camera has a fixed capture resolution.&#x20;

{% hint style="info" %}
Alternatively, if you need to dynamically adjust the resolution, that option already exists via camera settings via width/height slider adjustments.
{% endhint %}

## Related

{% content-ref url="../../steves-helper-apps/whip-and-whep-tooling.md" %}
[whip-and-whep-tooling.md](../../steves-helper-apps/whip-and-whep-tooling.md)
{% endcontent-ref %}

{% content-ref url="and-whip.md" %}
[and-whip.md](and-whip.md)
{% endcontent-ref %}




---
description: Option to change outbound screen-share video bitrate of WHIP
---

# \&whipoutscreensharebitrate

[WHIP Option](../../steves-helper-apps/whip-and-whep-tooling.md) / Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&wossbitrate`

## Options

Example: `&whipoutscreensharebitrate=2000`

<table><thead><tr><th width="238">Value</th><th>Description</th></tr></thead><tbody><tr><td>(integer value)</td><td>publishing screen share WHIP video bitrate in kbps</td></tr></tbody></table>

## Details

`&whipoutscreensharebitrate` controls the outbound screen-share video bitrate of the [`&whip`](and-whip.md) parameter while screen-sharing via WHIP. It will override the [`&whipoutvideobitrate`](and-whipoutvideobitrate.md) if the video is a screen-share.

## Related

{% content-ref url="../../steves-helper-apps/whip-and-whep-tooling.md" %}
[whip-and-whep-tooling.md](../../steves-helper-apps/whip-and-whep-tooling.md)
{% endcontent-ref %}

{% content-ref url="and-whip.md" %}
[and-whip.md](and-whip.md)
{% endcontent-ref %}




---
description: Option to change codec of the WHIP while screen-sharing
---

# \&whipoutscreensharecodec

[WHIP Option](../../steves-helper-apps/whip-and-whep-tooling.md) / Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&wosscodec`

## Options

Example: `&whipoutscreensharecodec=h264`

<table><thead><tr><th width="234">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>h264</code></td><td>h264 codec</td></tr><tr><td><code>vp8</code></td><td>vp8 codec</td></tr><tr><td><code>vp9</code></td><td>vp9 codec</td></tr><tr><td><code>42e01f</code></td><td>open h264 codec</td></tr><tr><td>(xxxxxx)</td><td>h264 profile IDs</td></tr></tbody></table>

## Details

Adding `&whipoutscreensharecodec` to the publisher's side gives the option to change the publishing codec while screen-sharing via WHIP.

There's 4 codec options currently, including the default option:

* The unspecified default, which is software h264.&#x20;
* There's also `h264`, which is what the browser then sets. This could include hardware encoding, but that will not work with Firefox or Safari viewers then.&#x20;
* `vp8` is pretty compatible, so if the default codec doesn't work, you can try that.&#x20;
* `vp9` is also available, which has better compression/quality, but not fully compatible with all devices.&#x20;
* av1 and SVC are not yet supported, but that is planned at some point.

## Related

{% content-ref url="../../steves-helper-apps/whip-and-whep-tooling.md" %}
[whip-and-whep-tooling.md](../../steves-helper-apps/whip-and-whep-tooling.md)
{% endcontent-ref %}

{% content-ref url="and-whip.md" %}
[and-whip.md](and-whip.md)
{% endcontent-ref %}

{% content-ref url="and-whipoutcodec.md" %}
[and-whipoutcodec.md](and-whipoutcodec.md)
{% endcontent-ref %}




---
description: Lets you specify the WHIP video bitrate (kbps)
---

# \&whipoutvideobitrate

[WHIP Option](../../steves-helper-apps/whip-and-whep-tooling.md) / Sender-Side Option! ([`&push`](../../source-settings/push.md))

## Aliases

* `&wovb`

## Options

Example: `&whipoutvideobitrate=6000`

| Value           | Description           |
| --------------- | --------------------- |
| (integer value) | video bitrate in kbps |

## Details

`&whipoutaudiobitrate` lets you specify the WHIP video bitrate (kbps).

## Related

{% content-ref url="and-whip.md" %}
[and-whip.md](and-whip.md)
{% endcontent-ref %}

{% content-ref url="../video-bitrate-parameters/bitrate.md" %}
[bitrate.md](../video-bitrate-parameters/bitrate.md)
{% endcontent-ref %}

{% content-ref url="and-whipoutaudiobitrate.md" %}
[and-whipoutaudiobitrate.md](and-whipoutaudiobitrate.md)
{% endcontent-ref %}




---
description: >-
  ATEM devices don't support HDCP, which some HDMI input devices require.
  Disabling HDCP with some HDMI splitters can resolve the issue.
---

# ATEM not working with Firestick

One user reports that their ATEM extreme wasn't working with an Amazon Firestick via HDMI.

Due to HDCP, it turns out you need to use an HDMI splitter that bypasses HDCP for it to work, else you'll just get a black screen. The ATEM does not support HDCP, so you need a way to disable it, and some splitters can offer that.

{% embed url="https://www.youtube.com/watch?v=vweEwAvusfE" %}
Taking a look at the Firestick HD Max and VDO.Ninja
{% endembed %}

### Background and more information

In a YouTube video, it was demonstrated that a Firestick, such as the 4K Max, can play VDO.Ninja videos at full-screen with a clean output. AV1 is even supported to some degree with the 4K Max, which offers excellent color reproduction versus VP8 or H264.

Given the price of a Firestick versus something like an SBC (ie: Orange Pi 5), it's an appealing option to use as a source for an ATEM device, like an ATEM mini. ATEMs don't have browser source support on their own, making a hack like this necessary.

Needing to disable HDCP may also apply to other HDMI input devices when paired with a Firestick, Chromecast, or other media dongle.&#x20;

If using this setup with an overlay, like [Social Stream](../steves-helper-apps/social-stream-ninja/), you may want to use `&chroma` on the featured chat overlays to enable the green background. From there, you should be able to chroma-filter out the green in the ATEM device, providing transparency.

It's also possible to use OBS to output a source to an ATEM device, via HDMI output on your computer. You'll still need to use a green screen if wanting transparencies of course.

Lastly, you can use IFrames and the VDO.Ninja mixer app to create custom scenes and layouts with transparencies in a browser source, if you wanted to do the mixing that way, avoiding the need for Chroma keying. Just please note that a Firestick or other low-powered dongle don't seem to handle multiple videos and complex effects all that well, or even full HD video for that matter. You may want to get a NUC device or powerful SBC to do more complex mixes that feed out into an ATEM of such.




# Audio is delayed in OBS

### OBS specific issues

Might be caused by a Browser-source related bug in OBS; this is normally the cause

Fully restart OBS and see if that clears the issue.\
\
Start OBS in administrator mode, if on Windows, to ensure it's not being throttled.\
\
Some users have had better luck fully uninstalling OBS and then re-installing it.\
\
If that fails, you can try to bring in audio via [https://vdo.ninja/electron](https://vdo.ninja/electron) instead. [`&novideo`](../advanced-settings/video-parameters/and-novideo.md) can be used to ingest just the audio. Route the audio to a virtual audio device and then bring that into OBS as an audio device. Should be in sync this way.

### Other possible options

VDO.Ninja uses 48000-hz sample rate for audio; using this sample rate whenever possible can help keep things in sync.

Try to avoid overloading your CPU or using too many browser source elements in OBS; OBS Browser Source can get overwhelmed.

VMix could be an alternative to OBS if problems persist; Vmix supports VDO.Ninja also.




---
description: Several possible causes of audio not working in Windows are listed
---

# Audio over VDO.Ninja isn't working

### OBS isn't set to capture audio

If using OBS for audio playback, be sure that you select "Control Audio via OBS" in the browser source to capture the audio. You won't be able to hear the audio by default this way, but OBS should show the audio level meters moving, signifying the audio is being captured.

<figure><figcaption></figcaption></figure>

### OBS may be having a max buffer issue

Restarting the computer or OBS can sometimes resolve issues where OBS stops capturing audio via browser sources or sometimes other audio soures.

Some users report that the audio may sound distorted or out of sync as well, but often there may be no audio at all.\
\
Starting OBS in adminstirator mode, if using Windows, may help. Reducing the CPU load on your computer may also also help.

### Sample rates or invalid audio settings

If however you are testing VDO.Ninja and audio isn't working at all, from browser to browser, yet you see your mic-level loudness green indicator moving in VDO.Ninja as you speak, double check your Windows audio settings. In particular, high sample rates, like 384-khz sample rates, 32-bit depth audio playback, or other professional audio device settings in Windows may cause problems with audio playback.

<figure><figcaption></figcaption></figure>

To avoid issues, set your audio playback devices (specifically to the audio playback device) to 24-bit or 16-bit audio, with an audio sample rate of 48,000-hz, or as close to it as possible. If you mic-source isn't working, also check to make sure your microphone is 16 or 24-bit capture mode, and isn't in ASIO mode.

Surround sound or multi-channel audio, for both the microphone and audio playback devices, can cause audio problems with the browser. Disable surround sound, limiting audio playback to stereo 2.0 channels, and try again.

If using a remote virtual desktop, such as a server-hosted version of Windows, be sure the Windows audio service is enabled; you might be able to turn this on via `services.msc` , accessible via the `Windows Key + R` run prompt.

Also check that the default audio device in Windows is as expected and that any select audio output device in VDO.Ninja is pointed to the right location. Bluetooth devices may sometimes be problematic, especially on mobile, so try to avoid Bluetooth if possible.

In some cases, adding `&noap` to the URL for the sender or/and reciever of the audio may help, as this will disable web-audio node processing in VDO.Ninja, which may fail when using invalid sample rates of an overly stressed CPU.

### Not all playback devices support audio

Some media devices, like the Magewell Director Mini, may not support audio via VDO.Ninja, and only video. Please also ensure the video is playing, as some devices may pause a media track until there is a user-gesture, which would prevent audio from playing in cases.

### Echo cancellation

Sometimes if there is background audio being captured, the system will remove that audio thinking it is an echo of feedback. If this background audio contains your microphone audio, your microphone audio may be removed. You can disable echo cancellation in this case, or resolve the core issue.

{% content-ref url="echo-or-feedback-issues.md" %}
[echo-or-feedback-issues.md](echo-or-feedback-issues.md)
{% endcontent-ref %}

### External USB / Lightning audio

If using an external audio device on mobile, like via USB, it's suggested to use a TRRS audio input adapter, with the your microphone connected to that.

[https://www.youtube.com/watch?v=BBus\_S8iJUE](https://www.youtube.com/watch?v=BBus_S8iJUE\&feature=youtu.be)\
\
If on Android, using Firefox might work well without the need of TRRS however.

### If using the native mobile app

If using the native VDO.Ninja mobile app, please note that screen sharing might only contain microphone-sourced audio -- the system audio won't be detected at the moment. This will hopefully change soon, but there is no timeline as to when it will be working.





---
description: Browsers may prevent videos from auto-playing on initial page load
---

# Autoplay doesn't work in Chrome or vMix v77

Since 2017, Browsers have required users "interact" with a website in some way before videos will be allowed to auto-play. You can modify Chrome to allow for auto-play, but it's not super easy to do.

In OBS and the Electron Capture app, auto-play is allowed.

vMix v77 does not support auto-play, which must be an oversight on their behalf... right?? haha. A complaint has been filed regardless; voice your own request for the feature here: [https://forums.vmix.com/posts/t22181-CEF-V77-browser-setting](https://forums.vmix.com/posts/t22181-CEF-V77-browser-setting).

A full-screen-sized play button will show up to help accommodate the need for user gestures before auto playing videos.\
\
**TL;DR;** you have a few options:

* use the Electron Capture app or OBS Studio to play videos; these apps have gesture-requirements disabled
* in Chrome, go to: `chrome://settings/content/sound?search=sound` and add vdo.ninja to the list of "allowed to play sound" list
* add `&noaudio` to your VDO.Ninja view link, so no audio track loads -- without audio, the video should auto-play.&#x20;
* try adding `--autoplay-policy=no-user-gesture-required` to the Chrome/Chromium command line to have the auto-play policy changed on load (this may not work with recent versions of Chrome though)
* make sure there are no Adblockers installed or other extensions install; sometimes these may interfere with auto-playing





# Blue spinning window

_**If you are experiencing this issue and you are using MacOS, please refer to the MacOS specific section**_

If this happens, there could be numerous reasons.

* Check that you have hardware-acceleration turned on, within OBS, and have updated your graphic drivers.
* Ensure that you are not behind a VPN or firewall. Symmetrical firewalls may block OBS.Ninja traffic.
* If on macOS, use the Electron Capture application instead of the Browser source used by OBS (Also ensure you are running OBS v26.1.2 or newer!).
* Try using a VPN, such as Speedify, to bypass any networking firewalls that your ISP may have enabled.
* Check [test.webrtc.org](https://test.webrtc.org/).

#### Are you using cellular?

* If you are on cellular, try connecting to Wi-Fi instead.
* Ensure your are using a compatible browser (Safari on iOS or Chrome on Android).
* Older iOS devices do not work.
* Check [test.webrtc.org](https://test.webrtc.org/).

#### Are you on IPv6?

Check to make sure your TURN server supports IPv6. The ones I provide _should_ support it though. Check [test.webrtc.org](https://test.webrtc.org/).

#### Are you using an iPhone?

There are numerous issues with iOS devices; see the [iOS help section](https://github.com/steveseguin/obsninja/wiki/FAQ#ios) for more info. Check [test.webrtc.org](https://test.webrtc.org/).

#### Are you within a condo building or corporate office?

Firewalls may be setup that block traffic of this type. Talk to your network administrator Other problems? Check [test.webrtc.org](https://test.webrtc.org/) and see if anything is marked as "RED". You can also try different networks and see if that helps.

In the meantime, [OBS.Ninja/old](https://obs.ninja/old) is up, and will remain up until I can resolve all the issues with the new release. This may solve your issue temporarily. So if you have this problem , where you see the fullscreen video, but it is just grey and spinning, then it could be a network issue.




# Can't auto-start screen sharing

Browsers won't let you auto-start a screen share, as it will require a user's input to select the source. You can configure the screen share pop up to show certain screen share options instead of others, but you'll still need to manually select which source to capture.

There are still some other options though that might work for your use case:

* The[ Electron Capture app](../steves-helper-apps/electron-capture.md) can be configured to allow for automatic screen sharing, which is useful if you want to start the screen share from command line or as a quickstart icon.
* OBS Studio can be used for screen capturing, and then when needed, you can have VDO.Ninja auto-select the OBS Virtual Camera as a source, since it can be selected automatically as a web camera.
* If you don't want to have to start OBS or are already running it, there's a virtual camera driver that will let you select screen shares as a source. [See here](https://github.com/rdp/screen-capture-recorder-to-video-windows-free).




# Can't capture an application's audio when screen-sharing

**Chrome** only supports audio capture from a TAB or from the DESKTOP. If you would like to capture the audio from a desktop application, two popular options include VB Virtual Cable for Windows or Loopback for macOS.

**Firefox** and **Safari** only support Desktop audio capture, so Chrome (Edge/Brave) are generally recommended instead.

To capture an application's audio, and not the entire desktop, you can use a virtual audio cable.

On **Windows**, VB Cable is a free option, you can use it with Windows' built-in "mixer" app to push the audio from the application to the virtual cable. From there, you can bring the audio into VDO.Ninja as needed. There's also Voicemeeter, which offers more advanced routing and features for Windows users.

With **macOS**, Loopback is a wonderful app that makes capturing audio from an application easy, but it is non-free. For a list of free options for macOS, please see here: [https://docs.vdo.ninja/platform-specific-issues/macos#capturing-audio](https://docs.vdo.ninja/platform-specific-issues/macos#capturing-audio)

For a detailed guide on how to capture an application's audio, please see here: [https://docs.vdo.ninja/guides/audio](https://docs.vdo.ninja/guides/audio)

There are other methods and software alternatives out there to solving this problem, although.




---
description: >-
  At a corporate event? Maybe state censorship is blocking access? Here's some
  options if a VPN isn't possible.
---

# Can't connect unless via VPN

## tl;dr; — The Quick Solutions

* Restart all devices, including WiFi Router
* Change to a different browser or try incognito mode
* Try different network (WiFi vs cellular)
* Restart your [winsock ](../guides/how-to-restart-your-winsock.md)if on Windows
* Use [https://proxy.vdo.ninja](https://proxy.vdo.ninja/) to access VDO.Ninja via a hosted Cloudflare proxy
* Use a version of VDO.NInja hosted in Hong Kong instead of in North America: [https://alt.vdo.ninja/alpha](https://china.vdo.ninja/alpha/)
* Self-host the VDO.Ninja handshake server on your local network
* Use an network tunnel to bridge your network with the remote network one

## Connectivity Troubleshooting Checklist

Here's a concise list of things to check if a user can't connect to VDO.Ninja:

#### WebSocket Connection Issues

Check if you can connect to websocket server, and if not:

* Try proxy mode via `proxy.vdo.ninja` or `vdo.ninja/?proxy`
* Use backup server at `https://backup.vdo.ninja`
* Try alternate websocket client: `https://vdo.ninja/?wss2=wss.socialstream.ninja&push=LNZFxhQ`
* Consider using your own websocket server with `vdo.ninja/?wss=serverhere.com`

#### WebRTC Connection Issues

* Check for cellular connection issues (UDP throttling/blocking)
* Try a different browser (Firefox, Chrome, Edge)
* Use incognito mode to test without extensions
* Disable browser extensions or security options blocking WebRTC
* Allow IP leaking in browser settings
* Ensure WebRTC is enabled
* Avoid de-Googled or highly secured/privacy browsers
* For Safari: ensure microphone permissions are granted

#### Network/Firewall Issues

* Check corporate firewalls blocking WebRTC/UDP
* Modify pfSense firewall settings to allow WebRTC/UDP traffic
* Check for symmetrical firewalls (contact ISP)
* Try a VPN service like Speedify
* Enable TCP encapsulation mode if UDP throttling occurs
* Run diagnostics at `vdo.ninja/speedtest`, `vdo.ninja/check`, or `vdo.ninja/browsercheck`
* Add `&stats` to VDO.Ninja URL to check connection stats
* Check for network configuration issues (double NAT setups)
* Ensure ports TCP 443, UDP 3478, and UDP 49152-65535 are open

####




---
description: >-
  Can't load camera both in both VDO.Ninja and OBS (or other app) at the same
  time
---

# Can't load camera both in OBS and VDON

If using a physical camera in OBS, or using a physical camera in [VDO.Ninja](https://vdo.ninja/), it can't be used by a second app.

If using the camera with [VDO.Ninja](https://vdo.ninja/), you can use it with other websites within the same browser though. So you can use the web version of Discord with [VDO.Ninja](https://vdo.ninja/); no issues with that.

#### However if you need to load the camera up in two different desktop apps, try the following:

* Open up a second OBS instance, and load your camera in that instead.
* Enable its Virtual Camera.
* Select the Virtual Camera in [VDO.Ninja](https://vdo.ninja/).
* Select the Virtual Camera now also in the first OBS instance (or other app). \
  \
  Your camera \*may\* now be working in both apps; this has been tested with OBS and VDO.NInja on Windows 11 anyways.

_Example:_

<figure><figcaption><p>Demo of it working</p></figcaption></figure>

#### If that doesn't work, another option that works well:

* Just pull your video into OBS from VDO.Ninja. It uses up a bit more CPU, but it simplifies things to just use [VDO.Ninja](https://vdo.ninja/) as the source for OBS.
* You can also always use the Virtual Camera from OBS to load the VDO.Ninja camera feed into another app.




---
description: Can't load camera from local webserver issues and how to resolve them.
---

# Can't load camera from non-SSL host

The Chrome / Edge / Chromium browsers will not allow access to media devices (camera / microphone) without SSL enabled.

Possible solutions include switching to https, accessing the site from http://localhost, or enabling the `unsafely-treat-insecure-origin-as-secure` browser switch.\
\
The browser flag, which works with Chromium-based browsers, can be accessed from: _**chrome://flags/#unsafely-treat-insecure-origin-as-secure.**_ Specify the hostname and the IP address that you will be accessing, such as https://192.168.1.15:8080. Enable the option, and then restart the browser.

<figure><figcaption><p><em><strong>#unsafely-treat-insecure-origin-as-secure</strong></em></p></figcaption></figure>

More advanced users can try using **openssl** to generate self-signed certificates, and using them with their local webserver to enable SSL, assuming you have access to the webserver.&#x20;

```
openssl req  -nodes -new -x509  -keyout key.pem -out cert.pem
```

<figure><figcaption></figcaption></figure>

If you can access the site via http://localhost, or http://127.0.0.1, that may work also. This could be possible if hosting VDO.Ninja locally, and accessing it via a local webserver.  If you have Python installed, you could get away using it to host VDO.Ninja in this way.

```
git clone https://github.com/steveseguin/vdoninja
cd vdoninja
python -m http.server 8000
```

When accessing VDO.Ninja in this way, make sure the remote computer that may also be accessing VDO.Ninja is using the same "salt". To debug this, you can try adding `&salt=vdo.ninja` to all the VDO.Ninja links, as that will manually assign all the links to use the same salt. The salt is used in the encryption process for site isolation and increased privacy/security when not using the official VDO.Ninja deployment.\




---
description: Some games may need settings tweaked to be captured properly with the browser
---

# Can't screen capture certain games

If you're struggling to capture a game with VDO.Ninja using the browser, a list of options are below.

* Disable Fullscreen Optimizations: Right-click the game's .exe file, go to Properties > Compatibility, and check "Disable fullscreen optimizations"
  * Sometimes you want to even uncheck "Disable fullscreen optimizations", so try both ways
  * Restart the game after applying changes.\

* Run as Administrator: Try running both the game and your capture software as administrator.\

* Compatibility Mode: Run the game in compatibility mode for an earlier version of Windows.\

* Run the game in windowed or borderless windowed mode\

* Consider using OBS Studio to capture the game with, and then output the captured video to VDO.Ninja using the OBS Virtual Camera.
  * Sound can be captured with a virtual audio device in conjunction with the the OBS audio monitoring output option.\

* If using hybrid graphics, such as two graphics cards, try to run the game on the same graphics card as the system / browser.\

* Try window capture or full-screen capture, or try with a different browser.
  * If using Window capture, you can capture the game's audio with the use of a virtual audio device, like Voicemeeter.
  * Display capture tends to offer better frame rates than window capture\

* Use an HDMI splitter and an HDMI to USB adapter to capture the output sent to your monitor.\

* Update your graphics card drivers\

* If using a browser such as Opera GX, it may throttle or disable VDO.Ninja when gaming.
  * The Electron Capture application, or a different browser, are better choices





---
description: >-
  Some applications don't like being screen captured by Chrome; there are some
  options however
---

# Can't screen share Adobe Lightroom

**Disable Hardware Acceleration:**

* Sometimes, hardware acceleration in either Chrome or Lightroom can cause issues. Try disabling hardware acceleration in Chrome by going to `chrome://settings` > Advanced > System > uncheck "Use hardware acceleration when available". Also, check if there's an option to disable hardware acceleration in Lightroom

**Try a Different Browser:**

* Test if the issue persists with other browsers like Mozilla Firefox or Microsoft Edge. This can help determine if the problem is specific to Chrome.

**Use Windowed Mode:**

* If Lightroom is in full-screen mode, try switching to windowed mode. Some applications don't share their display properly when in full-screen.

**Use Display Capture in Chrome instead of Window Capture**

* While this option may reveal more of your desktop than desired, if using a secondary screen to host the Lightroom application, it may still be a suitable solution.

**Use OBS and it's Virtual Camera:**

* You can use OBS to capture Lightroom, and from there output it to VDO.Ninja via the OBS Virtual Camera.  You would select the virtual camera in VDO.Ninjas a camera source, instead of a screen share source.  OBS has more advanced screen capture options than Chrome does.





---
description: iPhones don't allow the user to select the audio output destination by default
---

# Can't select audio output on iOS

While iOS devices have so far not allowed the user to select the audio output destination of VDO.Ninja via Safari, there are some experimental options in the Advanced settings menu of Safari.

You can access such experimental option via Settings -> Safari ->Advanced -> Allow speaker device selection, as seen in the below screen capture.

There is no guarantee this will work, and maybe it will be enabled by default in the future.

<figure><figcaption></figcaption></figure>

There are some other experimental options as well that you can enable on iOS, such as AV1 and H265 codec support, and perhaps in the future Screen Capture will work, too. iPadOS tends to have more functionality available, such as external USB video device support (as of iPadOS 17), as least compared to the iOS 16 at time of writing.

 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1).png>) (1) (1) (1) (1) (1) (1) (1).png>)




---
description: Some common problems and solutions with screen sharing
---

# Can't share my screen

### Windows

If using a Windows PC, and you can't see one or all of your screens to share, consider setting your display's resolution to 1080p or/and disabling any HDR (high dynamic range) on that display.

If using a laptop, the display you may wish to capture needs to be on the same GPU that the capturing is happening. Some laptops with dual graphics systems will have issues. Using an HDMI to USB adapter that has an HDMI splitter built-in is a cheap hardware-solution.

### Electron Capture

If using the Electron Capture app, please consider loading that app with Elevated privilege's, which can be done via command line or via right-clicking the app and selecting the option to elevate from the context menu.

### macOS

If on macOS, please be sure to give your browser system-level access in macOS to access your screen.

Chrome will let you share tabs, windows, and the entire screen, although audio capture is only available via Virtual Audio device (ie: Loopback) or tab-capture.

Safari has very limited options; it lets you capture the entire screen, and that is mostly it.

### iOS

If on iOS, there isn't an option available to screen share from within the browser or native iOS app, but you can wirelessly airplay your screen to a computer, and then window capture that output.

Better than Airplay though, if you can connect your iPhone to a mac via USB, QuickTime supports USB-connected access to an iPhone's camera. This does not require any downloads and offers a high-quality stream. Using a virtual audio device, you can even capture IOS audio with this method.

Please refer to this guide for more details:\
[https://docs.vdo.ninja/guides/screen-share-your-iphone-ipad](https://docs.vdo.ninja/guides/screen-share-your-iphone-ipad)

### Android

For Android users, downloading the VDO.Ninja APK file will let you screen share on Android, however you can't screen share via the browser on Android.

The Android app is available here: [https://docs.vdo.ninja/getting-started/native-mobile-app-versions](https://docs.vdo.ninja/getting-started/native-mobile-app-versions)




# Can't turn off echo-cancellation on macOS

I've had user reports that MacOS is forcing Echo cancellation on all devices except the built in mic. This was at least tested with a Scarlett Solo gen3\
\
Any "extra" device has echo cancellation forced on currently.\
\
You can try forcing it off via the URL with `&aec=0` or perhaps use a virtual audio cable.\
\
If you have added insights or solutions, please contribute them.




---
description: When screen sharing, the mouse cursor causes visual glitches or trailing
---

# Cursor shows trailing or artifacting

If using Chrome, launch Chrome from command line using the flag:&#x20;

`--enable-features=AllowWgcDesktopCapturer`

There is an issue in some versions of Chrome where the mouse cursor can cause visual issues while screen sharing.

Another option is to use a different browser; Firefox is a safe alternative if the issue is specific to Chrome. Browsers like Edge and Opera also use Chromium, so likely you will see the same issue across Chrome, Edge, and Opera, while Firefox does not use Chromium. You might lose some audio support options when using Firefox however.

If the issue is just that the cursor shows while screen sharing, see:

{% embed url="https://docs.vdo.ninja/common-errors-and-known-issues/cursor-shows-when-screen-sharing" %}




# Cursor shows when screen-sharing

Most browsers do not allow the mouse cursor to be hidden when screen sharing.&#x20;

For gaming, this can be an obvious problem.

If you're a gamer comfortable with AutoHotKey, you can hide the cursor with it using a custom hotkey. You can download the free script to do this here: [https://github.com/steveseguin/hide-cursor](https://github.com/steveseguin/hide-cursor), which works with Windows and is preset to toggle the cursor with WinKey+Click.

You can use OBS to capture the game and use the OBS Virtual Camera to share the screen with VDO.Ninja that way. This might result in more stable game play capture, but it is added work.

You can setup the OBS Virtual Camera to output a specific scene or screen-share, rather than the current active scene, using this filter:\
[https://obsproject.com/forum/resources/virtual-cam-filter.1142/](https://obsproject.com/forum/resources/virtual-cam-filter.1142/)

If you prefer not to use OBS at all, there are numerous screen-sharing tools that can turn your screen into a virtual camera. Below is a link to a free one for Windows:

{% embed url="https://github.com/rdp/screen-capture-recorder-to-video-windows-free" %}
[https://github.com/rdp/screen-capture-recorder-to-video-windows-free](https://github.com/rdp/screen-capture-recorder-to-video-windows-free)
{% endembed %}

Another paid option is to use an application that can toggle the visibility of the mouse cursor off and on. The paid app YoloMouse might be an option for gamers, as you can hotkey buttons to select different styles of cursors. If you select an invisible cursor, then you can hide the cursor on-demand with hotkeys.

Eventually cursor-visibility control will be available for Chrome, but for now, it will be a bit more hassle.




---
description: >-
  Blackmagic Decklink support isn't compatible with Google Chrome (chromium)
  browsers, but support is still possible.
---

# Decklink support?

Chrome continues to be incompatible with Blackmagic Decklink video sources, however there still are solutions.

* Someone says Firefox works for them, but not Chrome, so perhaps try Firefox with VDO.Ninja
* Bringing the Decklink into OBS, and then into Chrome via the OBS Virtual Camera seems like a popular approach.
* It's possible to bring in Decklink via OBS using WHIP WebRTC output, which is compatible with VDO.Ninja if there is no NAT firewall blocking the connection.
  * An option on this page ([https://whip.vdo.ninja/](https://whip.vdo.ninja/)), shows the WHIP ingestion URL and will offer a view-link.
  * I also have WHIP working with [https://meshcast.io/](https://meshcast.io/), if needed, but this may limit bitrates. Details on WHIP publishing should be available on meshcast.io.
* Raspberry Ninja as a command-line tool for VDO.Ninja that I am able to support myself, [https://raspberry.ninja/](https://raspberry.ninja/),  and it is compatible with a large array of input sources.
  * Basic Decklink support could be added probably within a few minutes, but it's not as easy to use as the browser-based version of VDO.Ninja.
  * I don't have Decklink device to actually test support with here, and Windows compatibility may be challenging, but it may be worth considering for your needs.

Please advocate to both Decklink and the Chromium development teams for proper Decklink support, as this has been a long-standing issue without either party addressing the issue yet.




---
description: Guests are sometimes able to hear themselves
---

# Echo or feedback issues

Dealing with feedback is challenging, as the reasons are numerous, but not always obvious. Below are some common causes:

* Headphones are too loud. This is especially true if you've disabled echo cancellation or enabled the [`&proaudio`](../advanced-settings/audio-parameters/and-proaudio.md)/[`&stereo`](../general-settings/stereo.md) modes.
* Using Safari as it has poor AEC abilities; use Chrome instead. Safari struggles when a room has bad reverb issues, so changing locations might also help, if forced to use Safari.
* [`&proaudio`](../general-settings/stereo.md) or [`&stereo`](../general-settings/stereo.md) mode is being used. This mode will disable echo-cancellation and so you must use headphones in this mode. As noted above, if using this mode, lower your headphone volume or/and use closed-back headphones.
* Screen-sharing the desktop /w audio capture on, especially in the case of a group room, will create nasty feedback for others. You can add [`&sstype=3`](../newly-added-parameters/and-screensharetype.md) to the guest's invite link to try to prevent this issue, but otherwise you may need to use a virtual audio cable to limit what application's audio gets recorded. Details on that here: [https://docs.vdo.ninja/guides/audio](https://docs.vdo.ninja/guides/audio)
* Incorrect OBS configuration is common, especially if the echo is only heard in the RTMP broadcast or recording, and not by those using VDO.Ninja themselves
* Having two browser tabs open (such as one with the YouTube output playing) will cause echo. Echo cancellation only works within the same tab that the audio is played back and captured, and only if the echo is not prolonged.\
  \
  You can use an experimental Chrome feature to solve this issue though. Go to [chrome://flags/#chrome-wide-echo-cancellation](chrome://flags/#chrome-wide-echo-cancellation) and enable Chrome Wide Echo Cancellation, to see if it helps.
* Having two devices connected to VDO.Ninja near each other, or sometimes even in the same house, can create echo. Phones have very sensitive microphones and can pick up the audio of others who might also be on the group call.
* Enabling certain advanced web-audio effects, such as per-video-specific audio output destinations can break echo cancellation.
* Playing an IFrame within VDO.Ninja (website share) may not have that IFrame's audio cancelled out by the echo-cancellation features.
* If only appearing in the OBS recording or stream, check to make sure you are not capturing the desktop's audio in OBS. This can happen if not using "Control audio via OBS" in the OBS Browser source, capturing a screen-share into OBS, or trying to record the director's room audio with OBS.

 (1) (1) (1) (1).png>)

#### Troubleshooting

A good way to troubleshoot is to mute one person at a time in a room, seeing if muting any specific single person solves the issue for everyone else.&#x20;

Normally the person who isn't hearing any echo or feedback is the cause.

If you identify that person, triple check that they are using Chrome and not Safari, make sure they are wearing headphones and that the audio is correctly playing into them, and have them close all other browser tabs and applications.

If the issue is only within OBS, this is likely an issue with OBS and not VDO.Ninja. Try disabling all global audio devices, muting audio devices in OBS one at a time, and double checking the advanced audio mixing settings.




---
description: >-
  If screen sharing, you may see a frame rate drop once VDO.Ninja loses focus.
  This background app-throttling can normally be disabled
---

# FPS drop if app not in focus

Chrome and Chromium-based browsers will sometimes throttle or limit the resources available to browser tabs that are not visible or in the background. This can result in a frame rate loss, often when using digital effects (green screen), when screen sharing, or using VDO.Ninja while gaming.

### Windows process throttling (efficiency mode)

If the issue is with Windows itself throttling the tab or application, you can open the Task Process manager (`Ctrl + Shift + Esc`), expand the processes for the browser application, and click on the VDO.Ninja tab process.

You can right-click it and disable efficiency mode if it is on.

<figure><figcaption></figcaption></figure>

### GPU Driver Settings

* **NVIDIA Control Panel:**
  1. Navigate to `Manage 3D Settings` -> `Program Settings`.
  2. Add or select the browser executable (e.g., `chrome.exe`).
  3. Set `Power management mode` to `Prefer maximum performance`.
  4. Ensure `Background Application Max Frame Rate` is `Off` or set to a high value.
* **AMD Radeon Software:**
  1. Navigate to `Gaming` -> `Games`.
  2. Add or select the browser executable.
  3. Review performance settings: disable `Radeon Chill`, `Enhanced Sync`, or other features that might limit background app performance. Check for specific power-saving options for background applications.

### **Windows System Settings**

* **Graphics Settings:**
  1. Go to `Settings` -> `System` -> `Display` -> `Graphics settings`.
  2. Under "Choose an app to set preference", select `Desktop app`.
  3. Browse to and add the browser executable.
  4. Click the browser in the list, select `Options`, and set to `High performance`.
* **Game Mode:**
  1. Go to `Settings` -> `Gaming` -> `Game Mode`.
  2. Try toggling Game Mode `Off`. It might be deprioritizing the browser too aggressively.
* **Power Plan:**
  1. Open `Control Panel` -> `Hardware and Sound` -> `Power Options`.
  2. Select `High performance` or `Ultimate Performance`.
  3. Click `Change plan settings` -> `Change advanced power settings`.
     * Check `PCI Express` -> `Link State Power Management` and set to `Off`.
     * Review `Processor power management` settings to ensure no aggressive throttling.

### **Game-Specific Settings**

* **Display Mode:**
  1. In the game's video/display settings, try using `Borderless Windowed` or `Windowed Fullscreen` mode instead of `Exclusive Fullscreen`.
* **In-Game FPS Limiters/V-Sync:**
  1. Experiment with disabling in-game FPS limiters or V-Sync to see if they interact negatively with background capture when the game itself is not the application in focus.

### Chromium background tab throttling

Disabling throttling for Chrome can be done in different ways; the methods to control throttling seem to change every couple years however.

Some flags you can try disable in Chrome are the following:

`chrome://flags/#calculate-native-win-occlusion`

`chrome://flags/#enable-throttle-display-none-and-visibility-hidden-cross-origin-iframes`

You can also go into your browser's settings and search for "performance" or go to `chrome://settings/system` , and at the bottom, you might see performance setting options. You might also find something at`chrome://settings/performance,` with options related to performance throttling or background tabs, such as "ThrottleJavaScriptt timers in background".\
\
To prevent browser auto-suspension and tab discarding, go to `chrome://discards/` and toggle off "Auto Discardable" on VDO.Ninja pages.

<figure><figcaption></figcaption></figure>

Disable the efficiency mode, or customize as desired, and that might help with performance of VDO.Ninja when gaming with the tab in the background.

<figure><figcaption></figcaption></figure>

These visibility strategies help prevent the browser from throttling inactive tabs after periods of inactivity.

### Electron Capture

If you can't get things to improve, you can try the [Electron Capture app](../steves-helper-apps/electron-capture.md) for screen sharing or for VDO.Ninja. It's optimized to not throttle in most cases, and it can be pinned on top of other applications if occlusion is a cause of throttling.

{% embed url="https://github.com/steveseguin/electroncapture" %}
Get Electron Capture here. Enable elevated privs if screen sharing with it
{% endembed %}

### OBS Virtual Camera

If screen sharing is getting low frame rates still, you can try using OBS to screen capture your game or application, and use it's virtual camera output as the source for VDO.Ninja.

OBS with its Virtual Camera can maintain a higher steady frame rate than most browsers can when screen sharing. You can use a virtual audio cable to capture the games/application audio, if needed.

{% embed url="https://docs.vdo.ninja/guides/publish-from-obs-into-vdo.ninja" %}

### Using WHIP from within OBS

An alternative to using the Virtual Camera and browser though is to use a feature in OBS to publish directly to VDO.Ninja.

This is an newer feature it may require a special version of OBS at the moment to work, but WHIP support is now included in OBS v30, but it may be another version or two before OBS supports WHIP properly. \
\
If having issues with using OBS WHIP with VDO.Ninja over the Internet, I do have a custom version of OBS that has proper WHIP support [available for Win64 here.](https://backup.vdo.ninja/OBS_VDO_Ninja.zip) \[[fork](https://github.com/steveseguin/obs-studio)]  This version should let you publish WHIP via VDO.Ninja across the Internet, regardless of Firewall. This OBS binary was last built November 2024, but hopefully future releases of OBS make this custom version redundant. :)\

Check out a demo YouTube video of how to accomplish publishing WHIP into VDO.Ninja:\
[Publishing from OBS directly to VDO.Ninja](https://www.youtube.com/watch?v=ynSOE2d4Z9Y)

This mode should give OBS Studio control over frame rate and bitrate, so with a good connection it should be possible to lock in a solid 60-fps.




# Getting “Overconstrained" Camera Error

If you get an Overconstrained error, it typically means the webcam or camera device has settings that are not compatible with VDO.Ninja code. With every camera being different, and everyone wanting high-quality video, it's a game of whack-a-mole to address each specific instance.

Some ideas though:

* You can try unplugging and reconnecting the device, and then trying again.
* You can use a different browser: Chrome, Firefox, Opera, etc.
* Do not try to specific a manual resolution; perhaps try the defaults.
* Do not use the camera in other applications at the same time.
* Try installing SnapCam or OBS virtual cam and try to select that; use it as an intermediary device.
* Uninstall NDI Tools, as it sometimes can cause issues or conflicts.




# Hosted your own TURN server?

For a guide on deploying your own TURN server on a Ubuntu server, see the below link: [https://github.com/steveseguin/vdo.ninja/blob/master/turnserver.md](https://github.com/steveseguin/vdo.ninja/blob/master/turnserver.md)

The benefits of a turn server include Increased security when actively used (less chance of IP leaking) and better network compatibility. Without a TURN server, about 10% of remote guests will not be able to connect with each other. In some cases, at the cost of added latency, a TURN server can also provide better video quality by means of forcing TCP data transfer.

I do offer a basic TURN server for VDO.Ninja users, but it is costly to operate and maintain. Deploying your own can offer better reliability and it frees up potential resources for other VDO.Ninja users. Please do not abuse it.

Google Cloud offers a free small server for life, so it’s possible to do this for free, so long as you keep it all private. GCP also often comes with a $300 free credit tier, even though GCP is a bit expensive for heavy usage in the long-run. It doesn't support IPv6 either, but it does have a good network backbone (\~20-cents per gig).

Twilio offers a paid TURN server service, which works well, but it's hard to setup for non-coders and it is twice the cost of Google to operating (40-cents per gig).

Another alternative to a TURN server is to bypass the NAT firewall that your OBS computer uses. You can do this in the network's router settings, normally by setting the DMZ to point to the IP address of your computer. This is dangerous, as it exposes you to the internet, but without a firewall you are less likely to need a STUN or TURN server.

Another option is to run OBS in the cloud on a virtual workstation, where you can open specific ports without the concern of a personal-computer hack. Some guests will still need a TURN server, but the likelihood is dramatically reduced.

You can also have remote guests who are needing a TURN server to install a VPN, like Speedify, which can bypass firewalls and other issues that might otherwise require a TURN server. Enabling TCP-mode within Speedify or other VPN service can also help combat packet loss, at the cost of added latency.

If going the VPN route, you also have the ability to secure your privacy/IP-address more securely; in some cases, more so than even a TURN server. See this article for more information there: [https://www.expressvpn.com/webrtc-leak-test](https://www.expressvpn.com/webrtc-leak-test)




# Improving vMix performance

I found a tip that may be worth adding to your vMix performance page, docs.vdo.ninja/common-errors-and-known-issues/vmix-high-cpu

In the performance settings, if you enable advanced settings at the bottom, there is a "high output performance mode" option. For users with Nvida 1080 cards and above, it seems to significantly reduce both render time and GPU usage with no obvious drawback. I assume it uses features not available at all on older cards, but vMix doesn't document what it does, so hard to say for sure. (The only official word was a release note "Added "High Output Performance Mode" in Settings -> Performance. Improves render time when outputting 4K60 video when used with high end graphics cards. (GeForce 1080+)" but for myself and everyone else reporting trying it on forums, it had a big impact at 1080p and slower fps as well,)




# iOS audio stops during phone calls

With using iOS devices (iPhones or iPads) , you may occasionally experience an issue where your microphone stops working. This typically occurs when there's an incoming call, text message, or other system notification on your device. Unfortunately, this is a known limitation with iOS devices imposed by Apple.

### Available Solutions

If you encounter this audio issue during a conference, here are some ways to resolve it:

1. **Mute and Unmute**: The simplest fix is to tap the mute button, then unmute yourself. This action reconnects your microphone and should restore your audio.
2. **Refresh from Control Room**: If you're still having issues, ask the room's director to refresh your audio. They can do this from their control panel.
3. **Rejoin the Conference**: If the above methods don't work, try leaving the conference completely and rejoining. This will re-establish all your media connections.
4. **Enable Do Not Disturb**: To prevent this issue, consider enabling Do Not Disturb mode on your iOS device before joining the conference. This will block incoming calls and notifications that might interrupt your audio.
5. **Use a Different Device**: If possible, consider joining from a non-iOS device, such as a desktop computer or Android device, which don't experience this particular issue.

Remember, if your audio cuts out, don't panic! Try these solutions, and you should be back to participating in no time. If problems persist, please join the [Discord ](https://discord.vdo.ninja)for further assistance.




# Is the VDO.Ninja server down?

The "V" in VDO.Ninja, in the top left, will go red as an indication that the client cannot talk to the VDO.Ninja server. It will _NOT_ try to reconnect automatically, although that is a coming feature I will add eventually.

If on mobile and you tab away from the site, the server connection may be lost.

If the O is red, then you will need to REFRESH the page to reconnect. I'll fix this hassle eventually.

However, if the server goes down, the video stream will NOT stop if already start, as the video stream does not go thru the server. If the server goes down it just means that no one new can connect to the stream anymore, but if already connected, you are fine. I may also fix this in the future, but I don't see the urgency for it.

The video stream happens over a direct peer connection. This connection can be pretty unstable as cellular phones are not the most reliable things in the world. If a video stream dies, it is not the server's fault, but a failure of the peers to hold a reliable connection open.

Auto-reconnecting does depend on the server though. When connected over a high quality LAN , two devices really shouldn't see their connection fail though, but if it happens often, please let me know.

There is a **backup** **server** at[ https://backup.vdo.ninja](https://backup.vdo.ninja) if the main VDO.Ninja does ever go down.




# Loading circle shows in OBS or browser

The loading circle will appear in a VDO.Ninja view link if a video does not auto-load within several seconds or so.

It will be removed once the video connects, and won't re-appear unless the browser source/page is refreshed.

You can hide this loading circle by default by adding [`&cleanoutput`](../advanced-settings/design-parameters/cleanoutput.md) to the URL of the view link.

example: [`https://vdo.ninja/?view=ABC123abc&cleanoutput`](https://vdo.ninja/?view=ABC123abc\&cleanoutput)

This will hide other non-essentially UI elements as well, such as any error messages. In most cases, when a view link is loaded into OBS, most non-essentially elements are hidden by default.

It is also possible to customize the loading circle with other images.




# Loss of audio when OBS minimized

Some users have reported their audio recording of VDO.Ninja stops or becomes choppy once OBS Studio is taken out of focus or minimized.

One solution is to run OBS Studio in Administrator mode. You can do this by first ensuring OBS is closed, and then holding SHIFT, right-click the OBS Studio icon; select `Run as administrator` from the menu that appears.

Another option is to use the [electron-capture.md](../steves-helper-apps/electron-capture.md "mention") to capture VDO.Ninja, instead of OBS browser source.




# Low frame rates

There are several reasons you may be experiencing low frame rates, including:

* If you are on MacOS using StreamLabs OBS, then the frame rates will be bad because of a bug in StreamLabs for Mac (consider the Electron Capture app instead).
* Try switching on "Enable Browser Source Hardware Acceleration" on in Advanced settings of OBS.
* If you are using Cellular / 4G, then the quality of the video may be poor due to the TURN server being in the USA or overloaded.
* Lights in your room are too dim maybe; try to make your room much brighter.
* Resolution is set to high, so selecting a lower resolution might help. This is especially true for H264 streams.
* Your Internet may be very slow or unstable. Try maybe Speedify.com and DO NOT use Wi-Fi.
* Make sure your CPU is not running near 100%. An overloaded computer or network will lag.
* Lower the resolution of OBS Ninja; select "Smooth and Cool" or 640x360 during camera selection.

Regardless, putting your own version of the HTML server up will not make it any faster.

To debug what the issue is, determine if it is faster when going from Chrome tab to Chrome tab on the same computer. If not, then it is nothing to do with servers.

If you are using a Mac with StreamLabs, you might be better off using the [Electron Capture app](https://github.com/steveseguin/electroncapture) instead.




---
description: If your microphone drops out after a few seconds
---

# Mic audio dropping out

### One possible solution:

One user had an issue where their microphone audio would drop out now and then; not just in VDO.Ninja, but in all browser-based web apps.

They resolved the issue by **disabling** certain WebRTC audio processing options in the browser&#x20;

**In Chrome**,

From `chrome://flags` we disable:\
\
`#enable-webrtc-allow-input-volume-adjustment`

`#chrome-wide-echo-cancellation`

_ℹ️ This also might be a useful option if using a USB mic that has the audio volume controls changing against your will, such as with a Blue Yeti._

**In Firefox**, we disable:

`media.getusermedia.aec_enabled`

`media.getusermedia.agc_enabled`

`media.getusermedia.noise_enabled`

`media.getusermedia.hpf_enabled`

### iPhone issues

iPhone 14 phones in particular have been pretty buggy with Audio, along with older versions of iOS across all iOS devices.

Make sure to update your iOS device if possible, use the newest version of VDO.Ninja (perhaps even the alpha version at [https://vdo.ninja/alpha/](https://vdo.ninja/alpha/)), and disable any audio processing in VDO.Ninja by adding [`&noap`](../general-settings/noaudioprocessing.md) to the URL.

### Bluetooth or microphones connected to a USB hub

It is not recommended to use Bluetooth audio devices with VDO.Ninja. In the past, there were drop outs when using AirPods on a battery-powered MacBook, for example. Constant Bluetooth range / connectivity issues can also cause VDO.Ninja to potentially lose the connection to the microphone.

USB Hubs are not all created equal, and some may cause USB devices to drop in and out. For this reason, connect your microphone and cameras directly to computer, bypassing USB hubs if possible.

### Inbound mobile calls or background notifications

Audio captured from a microphone may be paused or stopped if there is an inbound phone calls or system notifications. I suppose this is a mobile security consideration, but after a notification alert, the microphone may sometimes not be re-activivated, either due to a system-bug or other.

For this reason, disable notifications, inbound calls, etc, while streaming on mobile with VDO.Ninja.

### Packet loss or an over-stressed computer

Computers that are running at near 100% CPU load can fail to encode audio streams, audio drop outs may occur during a call as a result. Please consider reducing the CPU load on your system to avoid this issue.

Heavy network packet loss, such as a bad WiFi connection can also cause audio drop outs. Completely connection losses are possible also, particularly if behind a corporate firewall or VPN service that is throttling or restricting WebRTC services.




# Mic stops on MacOS when OBS opens

If the microphone stops working in VDO.Ninja when OBS Studio is open, on MacOS, considering using Safari instead of Chrome or other browser.

One user with this issue noted the problem resolved itself when they used Safari instead of Chrome.

They also noted that opening OBS with the scene first, then launching VDO.Ninja in the Chrome browser, also resolved the issue. Safari was indifferent to order.

Some users on Google noted that they re-selected their microphone permissions in the browser to resolve the issue as well, so there may be some system-level permissions issue at play here.

It's perhaps possible a virtual audio cable might also help, if the issue is a shared device issue. Using the monitor audio output of OBS as an input to the virtual audio cable, or using an application like Loopback for MacOS, might be a way to bypass the issue.




---
description: The mic's gain won't stay still or the auto-gain won't turn off
---

# Mic's volume keeps changing

Some microphones, like the Blue Yeti, Wave XLR, Samsun Q2U, or Scarlett Solo XLR interface, may have issues with Chrome (Chromium) and the mic's gain auto-changing on its own. This may cause clipping in certain cases or it may interfere with other applications that may also be using the microphone.\
\
You can also add [`&autogain=0`](../source-settings/autogain.md) to the VDO.NInja invite link to disable the auto-gain. You can also toggle the auto-gain from the VDO.Ninja settings menu, or if a guest, the room's director can remotely toggle the guest's auto-gain via: advanced options -> audio settings -> auto gain control. \
\
Disabling the auto-gain functionality in VDO.Ninja may cause the audio level to be rather low, so it will be up to you then to manually set the gain accordingly. VDO.Ninja offers manual gain if needed.\
\
An additional option to addressing this issue seems to be installing a browser extension that with disable auto-gain automatically within Chrome. ([https://chrome.google.com/webstore/detail/disable-automatic-gain-co/clpapnmmlmecieknddelobgikompchkk](https://chrome.google.com/webstore/detail/disable-automatic-gain-co/clpapnmmlmecieknddelobgikompchkk))&#x20;

If the above options do not work, another option perhaps is to use a single virtual audio cable for all your applications instead of access the microphone directly. In this case, you'd send the mic audio to that virtual audio device, which allows you to have a single point of control for gain. There's numerous virtual audio cables out there, including Voicemeeter and Virtual Audio Cable.

For more information on this topic, you can see discussions here, [https://support.google.com/chrome/thread/7542181?hl=en\&msgid=79691143](https://support.google.com/chrome/thread/7542181?hl=en\&msgid=79691143), and more recently here,  [https://support.google.com/chrome/thread/210106028/google-chrome-constantly-auto-adjusting-microphone-levels-solved](https://support.google.com/chrome/thread/210106028/google-chrome-constantly-auto-adjusting-microphone-levels-solved).




---
description: >-
  If you trying to add your video to OBS or Streamlabs, but instead of video you
  see buttons saying something like "Add camera" or "Share camera", double check
  your browser source links.
---

# No video in OBS, just an "Add camera" button

If you see the VDO.Ninja menu, instead of a video, it is typically caused by having your PUSH link used as a VIEW link in OBS or Streamlabs's browser source.

To fix, you should be able to just replace the `?push=` part of the URL with `?view=`.

A push link is for the sender to use, so to send video from your phone or computer to OBS.

A view link is used for viewing a video in OBS or other studio software.

VDO.Ninja will respond differently to whether a push or view link is provided, as each has a different role.

If you still see the VDO.Ninja menu or website, check to make sure your link is correct. Your links should start with `https://vdo.ninja/?`

If you forget the `?`, or have other errors in the URL, the website might load in an error state. This error state may sometimes be the VDO.Ninja website, perhaps with no images showing, or other graphical issues.

If still having problems after, ensure the stream ID value for both the view and the push parameters of the sender and viewer links are the same. You should have only at most one push-link open per stream ID as well; more than one will show an error that the stream ID is already in use.




---
description: >-
  Why are the resolution and framerate sometimes not the same as my OBS output
  settings?
---

# OBS Virtual Camera has low FPS

If you open an OBS Virtual Camera device in VDO.Ninja before starting the output in OBS, the OBS virtual camera will default to 1080p 30fps. If you start OBS first, it will use whatever is set as the Output resolution and framerate in OBS Studio's options, under Settings -> Video.\
\
So, make sure the set OBS to 60-fps and then start the OBS Virtual camera before starting Chrome and/or VDO.Ninja. If you don't do this, you may be capturing at 30-fps max.

.png>)

You may also have low frame rates if you are using the OBS virtual camera straight from OBS rather than by adding a filter to the video source. Filters may reduce the frame rate by 30% or so in my testing. Instead, considering opening two instances of OBS instead, if that is needed.

Of course, frame rates with VDO.Ninja can also be low if you don't have the video bitrate set high enough; for gaming, you might want to consider adding [`&videobitrate=20000`](../advanced-settings/video-bitrate-parameters/bitrate.md) to the view link. You can also try different video codecs, such as [`&codec=h264`](../advanced-settings/view-parameters/codec.md). If you are on a WiFi or weak Internet connection, that also can limit the frame rate of a stream due to heavy packet loss.&#x20;




---
description: OBS Virtual Camera Troubleshooting Guide
---

# OBS Virtual Camera not working

### Overview

OBS Virtual Camera issues affect content creators and remote workers across all platforms. Most problems stem from:

* **Hardware acceleration conflicts**
* **Permission restrictions**
* **Version incompatibilities**

The virtual camera functionality (built into OBS 26+ or available via plugins) faces increasing challenges from security-focused OS updates and application-specific restrictions, yet proven solutions exist for virtually every scenario encountered in 2023-2025.

## Windows Platform Solutions

#### Essential Requirements

* **Run OBS as Administrator** - Critical for proper DirectShow filter registration
* **Enable proper Windows permissions**
* **Check and clean registry entries**

### Common Issues & Fixes

**"Camera in use by another program" Error**

1. **Close all camera-consuming applications:**
   * Chrome/Edge browsers
   * Discord
   * Microsoft Teams
   * Windows Camera app
2. **Restart Windows Camera Frame Service:**
   * Open `services.msc`
   * Find "Windows Camera Frame Server"
   * Restart the service
3. **Disable browser hardware acceleration:**
   * Chrome/Edge: Settings → Advanced → System
   * Turn off "Use hardware acceleration when available"
   * **This resolves \~70% of browser-related Virtual Camera issues**

### **Virtual Camera Not Appearing**

1. **Check Registry for remnants:**
   * Open Registry Editor
   * Search for: "OBS Virtual", "VCAM", or "obs-virtualsource"
   * Look particularly in: `HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\DeviceClasses`
2.  **For stubborn registry entries:**

    ```cmd
    psexec -i -d -s c:\windows\regedit.exe
    ```

    This provides SYSTEM-level access for protected key removal

### **Windows 11 Specific Issues**

* Navigate to: Settings → Privacy & Security → Camera
* Enable **"Let desktop apps access your camera"**
* Note: OBS won't appear in the individual app list

### **Portable OBS Installation**

1. Extract portable version
2. Create `portable_mode.txt` in root directory
3. Run as administrator: `\data\obs-plugins\win-dshow\virtualcam-install.bat`

##

## macOS Platform Solutions

#### Critical Compatibility Note

⚠️ **macOS 14 (Sonoma) completely breaks OBS versions prior to 30.0**

* Virtual Camera won't function at all with OBS 29.1 or earlier
* Upgrade to OBS 30+ is **mandatory**, not optional

#### Permission Requirements

**Screen Recording Permissions**

* System Settings → Privacy & Security → Screen Recording
* Enable OBS

**Camera Extensions**

* System Settings → Privacy & Security → Login Items & Extensions → Camera Extensions
* Toggle ON the OBS extension (often disabled by default)

#### Application-Specific Fixes

**Discord & Slack Code Signing**

**Remove and re-sign helper applications:**

```bash
# Discord
sudo codesign --remove-signature "/Applications/Discord.app/Contents/Frameworks/Discord Helper (Renderer).app"
sudo codesign --sign - "/Applications/Discord.app/Contents/Frameworks/Discord Helper (Renderer).app"

# Slack (similar process)
sudo codesign --remove-signature "/Applications/Slack.app/Contents/Frameworks/Slack Helper (Renderer).app"
sudo codesign --sign - "/Applications/Slack.app/Contents/Frameworks/Slack Helper (Renderer).app"
```

⚠️ **Warning:** This breaks the application's original security signature

#### System Integrity Protection (SIP) Issues

**Symptoms:**

* Virtual Camera appears in selection menus
* Reverts to built-in cameras when activated

**Solutions:**

1.  **Temporary (NOT recommended):** Disable SIP through Recovery Mode

    ```bash
    csrutil disable
    ```
2. **Safer alternative:** Use web-based versions of problematic applications

## Linux Platform Solutions

#### Core Requirement: v4l2loopback Kernel Module

**Installation Steps**

1.  **Install required packages:**

    ```bash
    # Debian/Ubuntu
    sudo apt install v4l2loopback-dkms v4l2loopback-utils

    # Arch
    sudo pacman -S v4l2loopback-dkms

    # Fedora
    sudo dnf install v4l2loopback
    ```
2.  **Load module with proper parameters:**

    ```bash
    sudo modprobe v4l2loopback devices=1 max_buffers=2 exclusive_caps=1 card_label="OBS Virtual Camera"
    ```

    **⚠️ Critical:** The `exclusive_caps=1` parameter is essential for Chrome compatibility

#### Distribution-Specific Issues

**Arch Linux**

* **Problem:** v4l2loopback 0.14.0+ causes "Failed to start streaming" errors
* **Solution:** Downgrade to version 0.13.2

**Fedora**

* **Problem:** Secure Boot blocks unsigned kernel modules
* **Solutions:**
  1. Disable Secure Boot (easier)
  2. Implement MOK (Machine Owner Key) signing (complex)

**Ubuntu**

* **Problem:** Flatpak OBS lacks v4l2loopback integration
*   **Solution:** Use PPA version instead:

    ```bash
    sudo add-apt-repository ppa:obsproject/obs-studiosudo apt updatesudo apt install obs-studio
    ```

#### Wayland vs X11

**Wayland Requirements**

* Install appropriate xdg-desktop-portal:
  * `xdg-desktop-portal-wlr` for wlroots-based compositors
  * Built-in portals for GNOME/KDE
* Ensure PipeWire services are running

**X11**

* Generally provides more predictable Virtual Camera behavior
* Direct V4L2 device access without portal requirements

## Browser-Specific Issues

#### Hardware Acceleration (Primary Cause of Failures)

**70% of Virtual Camera detection failures** are caused by hardware acceleration conflicts

**Chrome/Chromium-Based Browsers**

1. Navigate to: Settings → Advanced → System
2. Disable "Use hardware acceleration when available"
3. Restart browser completely
4. Set OBS Virtual Camera as default when it appears

**Additional Chrome Fixes:**

* Clear cache and permissions: `chrome://settings/content/camera`
* Test in incognito mode to bypass extensions
* Consider using Edge (better Virtual Camera support despite same engine)

**Firefox**

* ✅ **Best browser for Virtual Camera compatibility**
* No hardware acceleration modification needed
* Recommended for flexible application choice

**Safari**

* Requires OBS 30.0+ for macOS 13+ compatibility
* May revert to built-in cameras during WebRTC use
* Known issues with Jitsi Meet

#### Browser Extension Conflicts

**Common culprits:**

* Privacy-focused extensions
* Ad blockers
* Camera/microphone blockers

**Testing method:** Use incognito/private browsing to isolate extension issues

## Application-Specific Workarounds

#### Discord

**Windows**

* **Start OBS Virtual Camera BEFORE launching Discord**
* Disable hardware acceleration in Discord settings
* Consider using Discord PTB for better compatibility

**macOS**

* Apply code signing modifications after each Discord update
* See macOS section for specific commands

#### Microsoft Teams

**Desktop Client Issues**

* **"New Teams" has worse support than Classic Teams**
* Browser version consistently outperforms desktop app

**Recommended Approach**

1. Use browser version when possible
2. If using desktop: Classic Teams > New Teams
3. Toggle camera on/off to initialize feed

#### Zoom

**Generally most reliable platform for Virtual Camera**

Tips for best results:

* Set Virtual Camera output type correctly (Program vs Source)
* Toggle background blur on/off to initialize video
* Restart Zoom if camera doesn't appear initially

#### Google Meet

* **Edge provides better support than Chrome** (despite same engine)
* Use web version exclusively
* Clear browser cache if issues persist

#### Skype

* Use desktop version (NOT Windows Store app)
* Enable NDI usage in settings
* Restart after enabling Virtual Camera

#### Slack

* Limited Virtual Camera support in desktop app
* **Use web version for reliability**
* Consider NDI-based workarounds for desktop

## Advanced Configuration & Performance

#### OBS Output Settings

**Resolution Configuration**

* **Match canvas resolution to content source** (avoid unnecessary scaling)
* Virtual Camera outputs at **30fps regardless of project settings**
* Custom resolutions can be typed directly (not just dropdown options)

**Recording Format**

* Change from MKV to MP4 if Virtual Camera isn't showing
* File → Settings → Output → Recording → Recording Format

#### GPU Hardware Acceleration

**NVIDIA Systems**

* Use NVENC encoding
* Reduces CPU usage from 40% to 10%
* Ensure OBS runs on same GPU as captured content

**Intel Systems**

* Enable Quick Sync Video (QSV)
* Excellent for laptops (preserves battery)

**Multi-GPU Configuration**

* Mismatched GPU assignments cause silent failures
* Set OBS to run on specific GPU via Windows Graphics Settings

#### Virtual Camera Versions

**Built-in (OBS 26+)**

**Pros:**

* Superior stability
* Better OBS update compatibility
* Less prone to crashes

**Cons:**

* No multiple instances
* Fixed 30fps output
* Limited customization

**Plugin Versions**

**Pros:**

* Multiple virtual cameras
* Custom framerates
* Advanced features

**Cons:**

* Frequent compatibility issues
* May crash applications (especially Discord)
* Requires more maintenance

## Memory & CPU Optimization

#### Common Performance Issues

**Memory Leaks**

**Biggest culprits:**

* Browser sources (several GB each)
* Multiple scenes active
* Extended streaming sessions

**Solutions:**

* Limit browser sources
* Close unnecessary scenes
* Restart OBS periodically

**CPU Overload**

**Optimization steps:**

1. Change x264 preset from "medium" to "veryfast"
2. Switch to hardware encoding (NVENC/QSV)
3. Reduce canvas resolution (1920x1080 → 1280x720)
4. Standardize audio to 48kHz (prevents resampling)
5. Set OBS priority to "Above Normal" in Task Manager

#### Frame Dropping & Freezing

**Common causes:**

* Inadequate system resources
* Thermal throttling
* Audio resampling overhead

**Quick fixes:**

* Lower output resolution
* Disable unnecessary filters/effects
* Check thermal management
* Match all audio sample rates

#### Software Conflicts

**Third-Party Virtual Cameras**

**Known conflicts with:**

* ManyCam
* XSplit VCam
* Snap Camera
* OBS VirtualCam plugins (when using built-in)

**Resolution:**

1. **Completely uninstall** conflicting software (not just close)
2. Clean registry entries
3. Restart system
4. Run OBS as administrator

## Conclusion

OBS Virtual Camera troubleshooting requires platform-specific approaches but follows predictable patterns across all systems. Hardware acceleration conflicts represent the single most common cause of failures, particularly in browsers and communication applications. **Administrative privileges on Windows, OBS 30+ on modern macOS, and proper v4l2loopback configuration on Linux** form the foundation for reliable Virtual Camera operation. When standard solutions fail, alternative approaches like NDI provide network-based video routing that bypasses traditional Virtual Camera limitations entirely.

The evolution from OBS 26's initial Virtual Camera implementation to current versions shows steady improvement in compatibility and stability, yet increasing OS security restrictions and application-specific requirements create new challenges. Success requires understanding both the technical mechanisms underlying Virtual Camera operation and the specific quirks of target applications. Armed with these troubleshooting techniques, users can diagnose and resolve virtually any Virtual Camera issue, ensuring reliable video streaming across all platforms and applications.




---
description: Mobile and laptop devices may overheat under prolong use
---

# Overheating

[VDO.Ninja](https://vdo.ninja/) offers a lot of power and unconstrained video quality. Some devices however will overheat if pushed for prolonged periods though, as they were not designed necessary for professional streaming video applications in mind.\
\
Still, there are steps you can take to minimize the heat generated by devices with software settings and configurations.

### Lowering the quality&#x20;

The viewer has control over the requested quality. 1080p video on a mobile device uses up a lot of power, including by data-transmission and the video encoding itself. Try using a lowering resolution, either by adding [`&quality=2`](../advanced-settings/video-parameters/and-quality.md) to the publisher's link or by adding [`&scale=50`](../advanced-settings/view-parameters/scale.md) to the viewer link.

The same goes for video bitrates; the default is around 2500-kbps, but perhaps try 1500-kbps instead. For example, `https://vdo.ninja/?view=MYSTREAM&codec=h264&scale=50&bitrate=1500`

### Hardware encoders on mobile devices

Some mobile devices have support for hardware-based H264 video encoding. An iOS device has three 720p30 hardware encoders, for example, while Android devices are hit and miss.

To reduce heat for mobile devices, try using [`&codec=h264`](../advanced-settings/view-parameters/codec.md) on the viewer side to request the video has h264 format. If the mobile publishing device supports it, it will use the hardware encoder for publishing. This will increase the chance for corrupted video, such as all-green flashes of video, but it should greatly reduce heat and power consumption.

Normally H264 will be used automatically if the hardware-device has a hardware-decoder, but this might not always be the case. Just double check, as VP8, VP9, and AV1 are rarely hardware-encoded. Keep in mind iOS devices are limited to 720p30 when using H264 hardware encoding, but can do 1080p30 with VP8 in software; life is full of trade-offs it seems.

When it comes to hardware encoding on laptops, H264 encoders sometimes kick-in, but the vast majority of the the time the browser will choose to still encode H264 video using a software-encoder. For the best chance of it working, use a Chromium-browser, like Chrome.

It should be noted that hardware encoders are finite in availability -- this means that they are often not something you can rely on when in a group-video call with multiple peers requesting video streams. If using an NVIDIA GPU, you might be limited to 2 or 3 hardware encoders, just like an iOS device, which doesn't work well if streaming to many viewers. \
\
The VP9 codec offers higher quality than most default codecs, but it also uses higher CPU load. AV1 may be even worse, so sometimes H264 is best. Just something to be aware of.\
\
Currently a web-browser does not allow a single video encoder to share video with multiple guests, at least not at low-latency. This is a limitation that will be addressed in the future, but it's a current limitation now.

### Meshcast.io and server-based restreaming

VDO.Ninja is peer-to-peer-based, which works great for linking one camera to one viewer. The more viewers though, as mentioned, the more load is created on that guest. Just the act of uploading data uses power, so mobile devices are also quite poor at restreaming to multiple viewers even if encoding video wasn't already an issue. This is why the video quality on mobile devices between guests is set very low by default.

[Meshcast.io](https://meshcast.io/) is by the same creator as VDO.Ninja, but it's a server-based solution to sharing low-latency video. It has a lower-maximum video quality, it isn't peer-to-peer-based, and it has numerous other short comings, but it does allow a mobile device to encode just one video stream, upload just one video stream, and still share that video with numerous viewers. Feel free to experiment with it, it's free, and if more quality and reliability is needed, there are paid options that are similar to it available. The cost of restreaming with a server-solution is about 15-cents per GB, depending on quality of the service. This is why Meshcast.io needs to limit it's video quality to afford a free-offering; server solutions are expensive!

### Group rooms, multiple-scenes, or multiple viewers

Every viewer of a stream adds to the heat and load experienced by the publisher of that stream. To reduce heat as much as possible, only allow one viewer of a stream to be active. Group-scenes, multiple-guests in a room, and multiple view-links each consistent as an active viewer. There are ways to optimize in these situations, but they may not be obvious. ([`&optimize=0`](../advanced-settings/video-bitrate-parameters/optimize.md), for example).

In the case of an iOS device, since it only has 3 hardware encoders, the device will switch to VP8-software mode or just stop working all together if those get exhausted. iOS devices are rather poor at software-encoding video, especially at higher resolutions, so be careful.

You can force-limit the number of connections and viewers with the [`&maxconnections=1`](../source-settings/and-maxconnections.md) parameter, added to the publisher's URL. If you are accidentally viewing the video stream multiple times, this will help prevent more than one viewer from having access.

### Start with a full-battery

Charging a mobile phone creates heat. If you start charging your device after you've already started streaming, that will increase the heat. Try starting with the phone already at a 100% full-charge to avoid even more unnecessary heat.

### Smartphone add-on heatsink and fan

Professional cameras do often include a small fan inside them to reduce heat. Consider buying a heatsink that can be mounted onto the back of your smartphone, with an optional fan to turn on if it starts getting hot. These are not super common, probably not super effective, but they can be had for not much money.

 (1) (1) (1) (1) (1) (1) (1) (1).png>)

Sometimes a thick protective case can insulate a smartphone, making it hotter than needed, too.

I've done a YouTube video demoing how cooling your smartphone can reduce heat and also improve performance, as a hot phone my throttle the performance. See below:

{% embed url="https://www.youtube.com/shorts/kH2Y3kAysv4" %}

### Web apps are intentionally limited on mobile devices

It is not possible to change between apps, screen-share, or turn off the display when using a web-app, like VDO.Ninja. You can turn down the screen brightness manually on your phone though, which will be nearly as effective.

Also, If you use `?push=STREAMIDGOESHERE&cleanoutput&nopreview&chroma=000&view` as a publishing link, you can hide pretty much everything on the screen, and if using an OLED display, this should reduce power usage. This is a great option if you wanted to set your phone up as a dedicated webcam and were worried about the screen generating heat.

### Native mobile app of VDO.Ninja

There are native Android and iOS app versions of VDO.Ninja, but they are very limited at the moment. They can be used to turn a phone into a dedicated webcam, and that's about the only they are good at. The Android app supports screen-sharing, which is the main advantage of using it.

Until the native apps are further developed, they are not great options for most users. They may still however use less CPU and may generate less heat though, just due to how basic they are in function.

Download the mobile app versions here: [https://docs.vdo.ninja/getting-started/native-mobile-app-versions](https://docs.vdo.ninja/getting-started/native-mobile-app-versions)

Please contact steve at `steve@seguin.email` or via discord ([discord.vdo.ninja](https://discord.vdo.ninja)) if you'd like to contribute to development of these native versions. The cost, time, and skill requirements for their continued development are quite steep.

### Laptops and MacBooks

Older 2011-era Apple notebooks are prone to overheating. Even newer generation Macbooks can overheat if stressed. Normally these systems throttle the CPU to be MUCH slower when they get too hot, so it may appear like there is a network issue.&#x20;

Ensure you are not running a laptop at 100% CPU load, make sure it has plenty of cool ventilation, ensure the fans are clean and not full of dust, start with a full battery and keep the computer plugged in

 (1) (1) (1) (1) (1) (1) (1) (1).png>)

### Raspberry Pi, NVIDIA Jetson, and dedicated hardware-encoders

VDO.Ninja has limited support for hardware encoders. Hardware encoders greatly reduce heat, but they are often poorly suited for low-latency video that requires tolerant packet-loss capabilities and dynamic resolutions. Green/purple/grey coloring of video, lost frames, and distorted video blocks are common when using hardware-encoders at very-low latencies.&#x20;

There is support for the Raspberry Pi, both software-encoder and hardware-encoder options, but the hardware-encoded option is the most limited and challenging. The current project supporting this offering is here: [https://github.com/steveseguin/raspberry\_ninja](https://github.com/steveseguin/raspberry_ninja)

Like with the native mobile app versions, the capabilities of this option is very limited. It does not support group-rooms and it does not yet support multiple viewers. Since many are using the Raspberry Pi wirelessly, it must also be said that it has very poor support of packet loss recovery -- the video will often not be smooth, especially if the WiFi signal is not very strong.&#x20;

Using a Chromium browser with a Raspberry Pi, in software-encoded mode, will probably give more reliable results, but also generate a lot of heat and limit the maximum video resolution a lot.

 (1) (1) (1) (1) (1) (1) (1).png>)

Just as a consideration though, the NVIDIA Jetson development boards support higher resolutions and seem to have better support for dynamic video and packet loss recovery. These products are a bit more expensive, but tend to work better than a Raspberry Pi when it comes to encoding HD video. I have a support for the Hardware-encoding capabilities of a Jetson here, buried away alongside the files for the Raspberry Pi: [https://github.com/steveseguin/raspberry\_ninja](https://github.com/steveseguin/raspberry_ninja) It's pretty basic support also currently, but has a lot of potential.

In the future, more professional video-centric hardware encoding options with built-in LTE/5G transmitters will support VDO.Ninja in a basic publish-only mode. This advancement will be due to the adoption of community standards for publishing low-latency video, although don't hold your breath for progress here.




---
description: >-
  When a relay candidate is selected, the connection is being forwarded
  (securely) via a hosted TURN relay server, rather than directly via peer to
  peer. This can add latency and limit the video quality
---

# Relay candidate being selected

There's many reasons why one client might not be able to make a direct connection with another client, resulting in their connections being relayed thru a TURN server, or perhaps failing entirely. Being in relay mode can sometimes hurt quality, add latency, and use up limited Internet bandwidth.

Some common reasons, with some solutions, are listed below.

### Cellular connections

If on cellular, some cellular providers will configure the system to not support peer to peer networking or UDP-traffic. Some others will also throttle UDP-traffic, which is what VDO.Ninja uses, and they may stop the UDP-traffic entirely after a few seconds or moments.

* Use a VPN service, such as Speedify, and consider enabling TCP encapsulation mode if UDP throttling is an issue. If you host a VPN service yourself, perhaps near your studio host computer, you can minimize performance and latency concerns
* Change networks

### Browser issues, settings, or extension

A common cause is a browser setting or extension that is causing the issue.

* Try a different browser, such as Firefox, Chrome, or Edge
* Update your browser
* Try incognito mode
* Disable your browser extensions or disable security options; some can block WebRTC
* Allow IP leaking in your browser settings or extension
* Ensure WebRTC is not disabled in your browser
* De-Googled browsers or highly secured/privacy focused browsers can cause issues
* You are using Safari and rejected microphone permissions

### Other common causes with potential solution

These issues can be hard to judge, especially if they are issues on the remote guest's side

* Corporate firewalls blocking WebRTC or UDP traffic
  * Ask your IT department for a solution, perhaps be given an isolated network space.
  * Use a VPN, preferably something hosted close by to reduce performance issues
  * Host your own TURN / STUN server, close to or within the corporate network, and specify it to be used within VDO.Ninja.
* pfSense firewalls will block WebRTC or UDP traffic.
  * Modify your firewall settings to allow those two options.
* Symmetrical firewalls, such as with some fiber internet services, may cause issues.
  * Contact your ISP if this is the case.
* You are using Safari and you have rejected the microphone permissions
  * Safari, such as on iPhone, will require microphone permissions to allow private IP address sharing. Rejecting that will force the TURN servers into use.
  * To avoid this, provide VDO.Ninja permissions to the microphone always, via the Safari settings.
* Strict security software installed
  * Try from a different computer on the same network to see if its a local software issue
* If using WHIP / WHEP, some third party applications may not support NAT traversal, lacking STUN server support, as it can be a lot of adding coding work. In these cases, VDO.Ninja might use a TURN server to assist things along, but it's far from ideal.
  * Host your own TURN server locally, and specify it in VDO.Ninja.
  * Reach out to the developers / support staff and ask for help
* STUN servers are being block. The STUN servers are hosted by Google, so if they are blocked, TURN might be the fallback.&#x20;
  * You can specify your own STUN servers if needed via URL parameters
* Endless other reasons...

### Doubled up NAT firewalls

In the following example diagram. we see a Main Router, a travel router, smartphone, production laptop, and a gaming desktop.&#x20;

<figure><figcaption><p>An example diagram, for reference</p></figcaption></figure>

The smartphone and the production laptop will be able to make a direct peer to peer connection, obtaining HOST candidates, since they are connected to the same router.

The gaming desktop however will struggle to make a peer to peer connection with the laptop on the other router, since they are on different networks. As a result, the connection might end up going thru the relay server, on the Internet, which is a disappointing result given the opportunity for a much better connection.

To fix such a scenario, some options:

* **RECOMMENDED SOLUTION:** Connect all devices to the main router instead.
  * Or alternatively, remove the main router, and connect all devices to the travel router instead, if feasible.
* **RECOMMENDED SOLUTION:** Replace the travel router with an ethernet switch, and if needed, add a wireless access point for the smartphone to connect to.
* Enable and point the travel router's DMZ at the production laptop's local IP address; this makes the travel router transparent to the gaming desktop. Just be sure to disable the DMZ mode when done.
* Move all devices to the same router, using the main router or the travel router\* for all devices.\
  \
  \*Assuming you connect the gaming laptop to the travel router instead, another issue might occur, and that is any VDO.Ninja user you try to connect to on the Internet may end up in relay mode with you. We can solve this issue potentially by putting our main router into bridge mode, which is often available as an option on cable modems in its gateway settings.

The recommended solutions have the benefit of ensuring all the clients, even clients on the Internet, can establish a peer to peer connection with any other client on the network. This wouldn't be the case for example if we simply used the DMZ mode, as the smartphone would not be able to connect to clients on the Internet in a direct p2p mode.

### Ports used by VDO.Ninja

TCP 443 and 3478 UDP are the most important ports to have open, if behind a strict firewall. These allow for WebSockets, STUN, and TURN, but they alone will not allow for direct peer to peer traffic.

The actual media in direct peer to peer WebRTC (RTP/RTCP packets) is sent over random high-numbered UDP ports. These ports are negotiated by the ICE (Interactive Connectivity Establishment) process, which uses the STUN/TURN servers to help figure out how the peers can connect to each other.

If you want to allow peer to peer traffic, and are dealing with something more complex than a NAT firewall, like pfSense Firewall, UDP ports 49152–65535 are commonly suggested to opened to allow peer to peer traffic. You might need to open lower as well though, along with port TCP 443 and UDP 3478.

These high-numbered UDP ports used are dynamically chosen by the browser, and there isn't much control on VDO.Ninja's side to control that. Since you are also dealing with peer to peer mode, unless you know the IP address of each guest you intend to connect to, you can't easily unblock based on IP address either. This isn't the case if using a TURN relay server of course, but that's not direct p2p then.

### Final comments and advice

Identifying which client is the problem can go a long way to troubleshooting.

Don't be afraid to try from different networks, computers, browsers, or other remote clients.

Advanced users can always just deploy their own TURN server locally or nearby, and specify it via VDO.Ninja. Hosting it yourself can reduce latency, improve performance, and improve security (no IP leaking). Using relay mode doesn't need to be a bad thing!

Join the Discord if still stuck and need help: [https://discord.vdo.ninja ](https://discord.vdo.ninja)




---
description: When screen-sharing, your local preview and output is black
---

# Screen-share is just a black video

<figure><figcaption><p>Google Chrome's HWA setting</p></figcaption></figure>

If the video preview when screen sharing is black, try disabling or enabling the browser's hardware acceleration. This can be found in the Google settings -> system menu.

If sharing a Netflix, Prime Video, or other content that is protected by content-protection, such as DRM/HDCP, the screen share may be black also. You can try screen sharing using the window, display, or tab methods to see if one works where the others fail, or you can try display grabbing with OBS Studio instead, but VDO.Ninja itself doesn't offer methods intended to bypass content copy protection.




# There are black borders around the video in OBS.

If a black border appears around the video, check that the custom CSS settings in the browser source has not been modified from the default setting:

```css
body { background-color: rgba(0, 0, 0, 0); margin: 0px auto; overflow: hidden; }
```

If you changed the default CSS settings, then you'll need to change them back to get rid of any background.

Also, ideally the width/height in OBS Browser source should be the same aspect ratio as the video. 1280x720 (not 800x600) This will fit the window to the video.

_original issue thread:_ [_Reddit: Advice on adding to OBS_](https://www.reddit.com/r/OBSNinja/comments/g1xyoi/advice\_on\_adding\_to\_obs/)




---
description: old iPhone errors, such as "cannot verify server identity" or
---

# Very old iPhone support

An iPhone 5s /w iOS 11 (or newer) is the technical minimum requirement for [VDO.Ninja](https://vdo.ninja), as Apple's webKit lacks the proper webRTC support in older iOS versions. Older iPhones/iPads can't update to newer iOS versions, so they are out of luck. iPhone 3G, 3Gs, 4, 4s, and iPhone 5 are not supported as a result, and many older iPads are also not supported.

I'd strongly recommend at least iOS 16 be used either way, as older versions of iOS have serious limitations and bugs. Starting with iOS 13 things started to be at least usable though, so an iPhone 6s is the recommended minimum, but don't expect a bug-free experience.

If using the native iOS app of VDO.Ninja, while I used to support iOS 11 with it, newer releases of the native app may require a newer iOS version. If using an iPhone 6 for example then, while it may not work with the native app, it might still at least work with the Safari web-app version.

Older Android phones tend to work usually though, as I think Google added support for WebRTC earlier on than Apple did, but you might be limited in terms of maximum quality or face heat issues on such old phones.




---
description: When the video turns into a rainbow puke with distorted colors
---

# Video stream looks corrupted

{% hint style="info" %}
Update: This issue of rainbow puke impacted OBS v25 and older, but is no longer an issue for most users.

If having issues with the video being very low quality, this is often due to high packet loss caused by weak WiFi or other network issue. More info: [https://www.youtube.com/watch?v=je2ljlvLzlY](https://www.youtube.com/watch?v=je2ljlvLzlY)\

{% endhint %}

{% hint style="warning" %}
**DO NOT USE WIFI**. Have everyone connect to stable wired Internet whenever possible.
{% endhint %}

### Video is smeared or "pixelated"

"Pixelation" (as seen here: [https://imgur.com/oKEPOvu](https://imgur.com/oKEPOvu)) is a difficult issue to troubleshoot as there are several potential upstream configurations which can ultimately lead to high packet loss which is the primary cause. Here are some potential fixes and configurations that may assist in lowering packet loss:

* Change the video codec or video encoder used: h264, VP8, and VP9 are options. VP9 seems to handle packet loss the best within OBS, but it also creates the most CPU load. VP8 handles packet loss the worst in OBS.
* Use Speedify.com (in AUTO or TCP mode).
* Use the Electron Capture app instead of OBS to capture video. The Electron Capture app uses a newer version of Chromium, which works far better than OBS when dealing with packet loss related issues.
* Lowering the framerate or resolution, especially for those using H264, can provide smoother video, and perhaps with less distortion.
* You can increase the jitter buffer size by using the [`&buffer`](../advanced-settings/view-parameters/buffer.md) URL parameter; such as "[https://obs.ninja?view=abs\&buffer=300](https://obs.ninja/?view=abs\&buffer=300)". This only works if using Chrome/Chromium v76 or newer though; OBS v25 currently uses Chromium v75 and so is not yet compatible.
* You connect two peers via TCP, instead of UDP, which will ensure there is no packet loss. This option is for more advanced users and requires a compatible TURN server (or VPN). Please use your own TURN servers for this option if so, as the bandwidth costs can be quite high for me.
* You can scale down the video while viewing with [`&scale=50`](../advanced-settings/view-parameters/scale.md) to potentially reduce stutter and reduce the frequency of frame corruption.
* Normally the video should "fix itself" after a moment of so, but if not that is likely a bug in the browser used for decoding. If in OBS you can toggle the visibility of the element to try to trigger a resolution. I've also provided a "SEND KEYFRAME" button in the hidden stats menu that lets the publish do this from their end.
* Mentioning this again, but connect over wired ETHERNET if possible and avoid wireless connections, including WiFi networks. DSL connections are also often quite poor. Do so for both OBS and the video-connected device for optimal results. Even 4G LTE is better than Wi-Fi in many cases.
* Do not watch a 4K Netflix or Youtube video while streaming; it will increase network congestion and can cause packet loss and buffer-bloat.
* If you have LOW QUALITY video, or low resolution or low bitrates, that perhaps can be adjusted. Please see below re: [bitrates and resolutions](https://github.com/steveseguin/obsninja/wiki/FAQ#bnr)
* Ensure your computer and remote computer are not maxing out their CPU power. If they are, have them lower the resolution and bitrate.
* If using an SFU server, like Janus or MediaMTX, or if using WHIP from OBS, increase the keyframe rate, ensure the PLI is working, and perhaps consider switching the server to work in TCP mode. It's also possible to try to set a keyframe rate with VDO.Ninja, however this is a last resort.

### Green or pink or wrong colors

* try using \&codec=av1 or perhaps vp8, vp9, or h264.  Sometimes a device, like a smartphone/Samsung will not encode the video in a way that the viewer supports
* Try a different browser; sometimes Firefox is problematic or sometimes its the solution.
* Try a different resolution. Some smartphones only work with 640x480, at least on specific cameras, while others will work with 1920x1080 or 1280x720, but fail with lower resolutions
* If the video works for a bit, and then stops, or just spins as if loading, try \&codec=vp8, as perhaps the h264 encoder is unable to handle those high resolutions. This is especially try when screen sharing on mobile.

### Colors slightly off

* If colors aren't perfect, try disabling hardware acceleration in OBS (obs browser source hardware acceleration)
* Use \&codec=av1 on the view link, as this codec seems to handle colors better than h264/vp8
* Use the Electron Capture app instead of OBS browser source; window capturing may be required
* Use a different graphics card (AMD sometimes work better than NVidia) or update graphics drivers
* avoid HDR mode and reset any color filters you may have applied to your system/monitor
* Try different browsers; Safari, Firefox, and Chromium may handle colors different
* Increase the video bitrate; lower bitrate videos will have worse colors




# Video lag grows over time

Video lag that goes over time typically hints at a CPU being overloaded; it might not be able to handle the capture resolution or the load required to encode video for several viewers at once.

\
Some users report this issue happens when using the Streamlabs Virtual Camera, but not when using their webcam or screen share. For others, it might commonly happen if using an older laptop, like an Intel-based Apple MacBook, where they thermal throttle performance after a short while.

## Solutions:

### Reduce quality

Using `&quality=2` and a reduced bitrate by viewers can lower the load

### Meshcast

Using Meshcast (\&meshcast) or self-hosting your own MediaMTX server (\&mediamtx) can allow the publisher to relay their video thru a broadcast server, reducing the number of encodes on that computer to one; rather than potentially serveral

### Get a faster computer and plug-in

Laptops that run on battery power will run at reduced performance, so make sure you are plugged into the AC wall outlet. If that doesn't help, try running your apps in performance mode (rather than battery saver), and if that still doesn't work, consider getting a new computer.  8-core or faster is suggested, but it will depend on your needs.

### If the issue is only with the Streamlabs or OBS Virtual camera

Loading the virtual camera into the Electron Capture app ([https://electroncapture.app](https://electroncapture.app)) will give you the built-in option to full-window the virtual camera. This makes it super easy to screen share the window using VDO.Ninja, and this should bypass any performance problems caused by trying to load the virtual camera directly as a webcam source.\
\
When opening the Electron Capture app, it will auto-detect a virtual camera device, and offer you the option to full-window it.

<figure><figcaption></figcaption></figure>

For reference, these are the devices that get auto-detected by the Electron Capture app:

```
    "OBS Virtual Camera"
    "Streamlabs Desktop Virtual Webcam"
    "vMix Video"
    "Blackmagic"
    "NDI Video
```





---
description: >-
  If the OBS Virtual Camera is not appearing in Chrome or your browser after
  installing OBS on MacOS, you may need to enable screen recording permissions.
---

# Virtual camera not working on Mac

If using OBS Virtual Camera or other virtual camera on MacOS (Apple) system, please note that there are a list of applications that are not supported.

### Apps that will **not** work

* Bluejeans Events
* Safari
* Tencent Meeting
* FaceTime
* Photo Booth

Please see the follow official guide for more details on these and other problematic apps.

{% embed url="https://obsproject.com/wiki/MacOS-Virtual-Camera-Compatibility-Guide" %}
Official documentation
{% endembed %}

### General tips to using the Virtual Camera

If using Windows or if you have just installed OBS, please restart your browser fully or restart the computer first, to ensure its properly loaded and available to all applications.\
\
The Google Chrome usually works with most virtual cameras. If you are having problems with it, you can also try another browser.\
\
Please also be sure to START the virtual camera before selecting or opening it in VDO.Ninja. If you open it in VDO.Ninja before starting it, the resolution and/or frame rate may be wrong.

## Enabling permissions for Virtual Camera on MacOS

If the OBS Virtual Camera is not appearing in Chrome or your browser after installing OBS on MacOS, you may need to enable screen recording permissions.

1.  Open your System Preferences; you can find this via the Apple logo in the top left corner of your desktop.\

    <figure><figcaption></figcaption></figure>

2.  Click Privacy & Security and then Screen Recording.\

    <figure><figcaption></figcaption></figure>
3. For OBS, enable the permission.\
   \
   &#xNAN;_&#x49;f OBS isn't listed, click the + button, enter your system's password, and navigate to OBS in the Application settings. Select it and enable._\

4.  Quit and relaunch OBS.\

    <figure><figcaption><p>If OBS isn't listed, press the + button, navigate to it, and select it</p></figcaption></figure>




---
description: Some ideas on how to reduce total system load on a vMix system using VDO.Ninja
---

# vMix High CPU

## vMix CPU Load Optimization Guide

vMix is a powerful studio mixer software, although some users find the CPU load can get high during operation. This guide provides optimization techniques to reduce resource usage, primarily focused on vMix but potentially applicable to other studio mixing software.

### Browser Source Optimizations

* Browser sized at 1920x1080 can stress vMix out; try 1280x720 or lower to reduce the total load.
* Ensure GPU hardware acceleration is enabled; particularly for the browser source.
* Using the H264 codec may reduce CPU; adding `&codec=h264` to the view link may help.
* Disabling de-interlacing, sharpening, or aliasing of the browser source might free up some load.

### Alternative Capture Methods

* Electron Capture or Vingester.app can be used instead of the vMix browser source; they can use window capture, which can reduce the CPU load.
* If you have a spare computer, Vingester.app has a VDO.Ninja to NDI output option, which can perhaps help with distributing load if the browser source is causing issues.

### Frame Rate & Resolution Adjustments

* Lowering the frame rate of the browser source and incoming VDO.Ninja videos might help reduce CPU load. `&maxframerate=30`, for example, on the guest link can help cap the frame rate.
* The director of a room can adjust settings of incoming videos via the video settings options under advanced settings. This includes the max resolution, frame rate, and aspect ratio of incoming videos.

### Hardware & Driver Optimizations

* Updating your graphics card drivers can sometimes help.
* In the performance settings, if you enable advanced settings at the bottom, there is a "high output performance mode" option. For users with Nvida 1080 cards and above, it seems to significantly reduce both render time and GPU usage with no obvious drawback. I assume it uses features not available at all on older cards, but vMix doesn't document what it does, so hard to say for sure. (The only official word was a release note "Added "High Output Performance Mode" in Settings -> Performance. Improves render time when outputting 4K60 video when used with high end graphics cards. (GeForce 1080+)" but for myself and everyone else reporting trying it on forums, it had a big impact at 1080p and slower fps as well,)

### VDO.Ninja Specific Optimizations

* If acting as a VDO.Ninja director, consider hosting the director on a different computer than vMix. If not possible, consider using `&meshcast` with the director's link to use `&meshcast` to help reduce the CPU load when in larger group rooms.
* Try to use your local camera as a source in vMix, rather than bringing your local video into vMix with VDO.Ninja. Using a virtual camera, like Snapcamera, OBS Virtual Camera, Manycam, or such can allow a webcam to be accessed using the browser and vMix at the same time.
* Avoid using multiple group scene link, unless solo-view links. Instead, consider using the VDO.Ninja mixer app to use a single group scene link, switching between different layouts using the mixer interface. (The Mixer app is relatively new, as of May 2022, so still undergoing feature enhancements).

### Additional Techniques

* Consider using a dedicated streaming PC for more demanding productions
* Close unnecessary background applications to free up system resources
* If possible, run vMix from an SSD rather than a traditional hard drive
* Monitor resource usage with Windows Task Manager to identify bottlenecks
* For network-intensive setups, ensure you have adequate bandwidth and a stable connection

There are additional other options available to reduce CPU / GPU / Network load when using VDO.Ninja; this list is specific to vMix issues.




---
description: >-
  Some laptops will put the webcam to sleep for a moment to save power, causing
  freezing
---

# Webcam freezes after a time

If using a laptop with a USB camera, it's possible the the system is putting the camera to sleep for a split second; just enough to cause the video to freeze. This is definitely a possible cause if on a laptop, but might not be an issue for a desktop user. Enabling performance mode in the Windows power options might help things, but you can also disable USB power savings selectively.

One place to is in the Windows Power Options settings, which you can find in the Power and Sleep settings pane.

 (1) (1).png>)

You can also try disabling the "Allow the computer to turn off this device to save power" options in the Windows Device Manager for each USB device/host controller. (uncheck them)

 (1) (1).png>)

If the problem isn't resolved, you can still reload the camera with the refresh button in the VDO.Ninja settings menu when it happens. This just reloads the camera and should fix the problem until it happens again.

The director of a room can also refresh a camera remotely of a guest, when it freezes, via the video settings of the guest.

If it's a common occurrence, you can load the camera into OBS or SnapCamera and then bring the video into VDO.Ninja as a virtual camera device. While VDO.Ninja does try to automatically reconnect devices when they become disconnected, it sometimes isn't alerted by the browser that the camera has glitched. OBS or Snapcamera might handle these conditions better.

Another reason for a camera freezing randomly is that it may be a bad USB 3.0 cable or a USB 3.0 hub that is overloaded with other USB devices already. Plug any camera directly into the back of the computer, on a dedicated USB 3.0 port, with a high quality USB 3.0 or better cable. Unplug other unneeded USB devices.

If this doesn't work, it probably isn't related to your camera, and may be instead related to your network.

For more reasons why a video may freeze during a stream, see the following:

{% content-ref url="video-freezes-mid-stream.md" %}
[video-freezes-mid-stream.md](video-freezes-mid-stream.md)
{% endcontent-ref %}




# Can't screen-share from certain devices

The Screen sharing feature is highly dependent on the operating system of the device whose screen you are trying to capture.

* Chrome browser used on a PC is most compatible, fully supporting screen sharing with audio.
* Firefox on PC supports screen sharing, but it cannot screen share with audio.
* Safari on iOS does not yet support it officially, although it does support it with the "technical builds" designed for developers. Until Apple officially supports, there isn't much I can do there easily.
* Android does not support it and it is doubtful that it will in the near future.

In either case, you can use Native mobile apps to solve this problem, as the native apps let you screen share using iOS and Android. However, the native apps are pretty basic right now, and may lack many features and may even lack system-audio capture.

There's other tricks as well to get screen sharing working on mobile, such as using QuickTime via USB.

{% content-ref url="../steves-helper-apps/native-mobile-app-versions.md" %}
[native-mobile-app-versions.md](../steves-helper-apps/native-mobile-app-versions.md)
{% endcontent-ref %}

{% content-ref url="../guides/screen-share-your-iphone-ipad.md" %}
[screen-share-your-iphone-ipad.md](../guides/screen-share-your-iphone-ipad.md)
{% endcontent-ref %}




---
description: Global hotkey support via MIDI input and more
---

# \&midi

General Option! ([`&push`](../source-settings/push.md), [`&room`](../general-settings/room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&hotkeys`

## Details

You can use a MIDI controller, virtual or real, to issue commands to VDO.Ninja. This option is compatible with an Elegato Streamdeck, allowing for both control over things like mute, but also control over remote guests if a director.

A web-based dashboard for issuing MIDI commands from a virtual MIDI device can be found here: [https://vdo.ninja/midi](https://vdo.ninja/midi). It can also offer debugging information, listing MIDI event data in the browser's developer console, helping to identity what certain MIDI buttons do.

The MIDI capabilities of VDO.Ninja go beyond just controlling VDO.Ninja though. Options to seamlessly send and receive MIDI commands with remote computers at very low latency is also possible.

More information, details, guides, and tools can be found closer to the bottom of this page.

{% hint style="warning" %}
Currently a Chromium-browser, like Google Chrome, is recommended when using the MIDI features. Other browsers may not be compatible at this time.
{% endhint %}

{% hint style="info" %}
**Notice:** The VDO.Ninja's MIDI API is still constantly evolving, so check back for updates if you face problems or to discover new available features and options.
{% endhint %}

### Options for \&midi={value}

{% hint style="warning" %}
There are two MIDI standards; one where value 33 is note A0, and the more common standard where value 33 is note A1. VDO.Ninja uses the A1 standard. Decrease your octave by one if having problems, such as if using TouchOSC.
{% endhint %}

<table><thead><tr><th width="160">Value</th><th>Description</th></tr></thead><tbody><tr><td>&#x26;midi=N</td><td>Description of MIDI </td></tr><tr><td><code>1</code></td><td>Hotkeys using A3 to G4 notes </td></tr><tr><td><code>2</code></td><td>Hotkeys using A1 to G2 notes</td></tr><tr><td><code>3</code></td><td>Hotkeys using Note C1 + velocities</td></tr><tr><td><code>4</code></td><td><p>Hotkeys using control-change inputs.</p><p></p><p>Designed mainly for the director to control multiple guests, as well as themselves.</p></td></tr></tbody></table>

### **\&midi=1**

<table><thead><tr><th width="209">MIDI message</th><th>Function</th></tr></thead><tbody><tr><td>Note G3</td><td>Toggle Chat</td></tr><tr><td>Note A3</td><td>Toggle Mute</td></tr><tr><td>Note B3</td><td>Toggle Video Output</td></tr><tr><td>Note C4</td><td>Toggle Screen Share</td></tr><tr><td>Note D4</td><td>Hang up</td></tr><tr><td>Note E4</td><td>Raise Hand Toggle</td></tr><tr><td>Note F4</td><td>Record Local Video Toggle</td></tr><tr><td>Note G4</td><td>Enable the Director’s audio [director only]</td></tr><tr><td>Note A4</td><td>Stop the Director’s Audio [director only]</td></tr><tr><td>Note B4</td><td>Toggle the Local Speaker Output</td></tr></tbody></table>

### **\&midi=2**

| MIDI message | Function                                     |
| ------------ | -------------------------------------------- |
| Note G1      | Toggle Chat                                  |
| Note A1      | Toggle Mute                                  |
| Note B1      | Toggle Video Output                          |
| Note C2      | Toggle Screen Share                          |
| Note D2      | Hang up                                      |
| Note E2      | Raise Hand Toggle                            |
| Note F2      | Record Local Video Toggle                    |
| Note G2      | Enable the Director’s audio \[director only] |
| Note A2      | Stop the Director’s Audio \[director only]   |
| Note B2      | Toggle the Local Speaker Output              |

### **\&midi=3**

<table><thead><tr><th width="232">MIDI message</th><th>Function</th></tr></thead><tbody><tr><td>Note C1 + Velocity 0</td><td>Toggle Chat</td></tr><tr><td>Note C1 + Velocity 1</td><td>Toggle Mute</td></tr><tr><td>Note C1 + Velocity 2</td><td>Toggle Video Output</td></tr><tr><td>Note C1 + Velocity 3</td><td>Toggle Screen Share</td></tr><tr><td>Note C1 + Velocity 4</td><td>Hang up</td></tr><tr><td>Note C1 + Velocity 5</td><td>Raise Hand Toggle</td></tr><tr><td>Note C1 + Velocity 6</td><td>Record Local Video Toggle</td></tr><tr><td>Note C1 + Velocity 7</td><td>Enable the Director’s audio [director only]</td></tr><tr><td>Note C1 + Velocity 8</td><td>Stop the Director’s Audio [director only]</td></tr><tr><td>Note C1 + Velocity 9</td><td>Toggle the Local Speaker Output</td></tr></tbody></table>

### **\&midi=4**

<table><thead><tr><th width="209">MIDI message</th><th>Function</th></tr></thead><tbody><tr><td>Command = 110</td><td>with values accepted from 0 to 8 for local toggle options.</td></tr><tr><td>Command = 110+N</td><td>where N is the guest’s order in the control room.</td></tr></tbody></table>

In this case, for hotkeying remote guests as a director:

<table><thead><tr><th width="209">MIDI message</th><th>Function</th></tr></thead><tbody><tr><td>Value 0</td><td>Opens the Transfer Popup</td></tr><tr><td>Value 1</td><td>Add/remove from scene 1</td></tr><tr><td>Value 2</td><td>Mute guest in scene</td></tr><tr><td>Value 3</td><td>Mute guest everywhere</td></tr><tr><td>Value 4</td><td>Hang-up the guest</td></tr><tr><td>Value 5</td><td>Toggle Solo Chat with this guest</td></tr><tr><td>Value 6</td><td>Toggle the remote speaker</td></tr><tr><td>Value 7</td><td>Toggle the remote display</td></tr><tr><td>Value 8</td><td>Fixes Rainbow Puke of this guest in scenes</td></tr><tr><td>Value 12 to 18</td><td>Add/remove from scene 2 to 8</td></tr></tbody></table>

All the above hotkey mappings are purely experimental at this time and will change based on user feedback. These mappings should allow a user to use a StreamDeck with VDO.Ninja.

### Configuring MIDI device and channel

By default, any MIDI device on any MIDI channel can trigger the \&midi actions if their command and values match.&#x20;

Starting with version 20 of VDO.Ninja, you can filter inputs based on channel and device using `&mididevice` and `&midichannel`.

#### \&mididevice

This parameter can take any number from 1 and up.  It's based on the MIDI device's list index order. You can check the developer console of the browser with \&midi added to get a list of those midi devices and the list.  The first item in the list can be used using `&mididevice=1` and the second will be `&mididevice=2`, etc. &#x20;

If you don't specify a MIDI device, all devices will be used.  This \&mididevice filter does not apply to \&midiin or \&midiout.

#### \&midichannel

MIDI supports channel 1 to 16. Prior to VDO.Ninja v20, channel 1 was the only channel that worked, but in v20, any channel will be treated as a trigger by default.&#x20;

By using \&midichannel=1, you can again set VDO.Ninja to only trigger on inputs sent over channel 1. You can specify any single channel to trigger on though, from 1 to 16, if that level of control is needed.

This command is not compatible with \&midiout or \&midiin.&#x20;

## Elgato Streamdeck support

You can configure a Streamdeck to issue MIDI commands, via the use of a MIDI plugin for Streamdeck. This allows you to send hotkey commands from your Streamdeck to VDO.Ninja locally, on the same computer, or even remotely, via the MIDI remote control feature.

You'll need to find a MIDI plugin within the Streamdeck store, or add one from source. Normally you can just search for MIDI and have some options appear.

For macOS, one Streamdeck plugin available is [https://github.com/tsbkelly/Streamdeck-Midibutton](https://github.com/tsbkelly/Streamdeck-Midibutton)

For PC, there's this one [https://trevligaspel.se/streamdeck/midi/index.html](https://trevligaspel.se/streamdeck/midi/index.html)

 (1) (1) (1) (1).png>)

You will also need a Virtual MIDI loopback interface on your computer, if intending to send MIDI commands to VDO.Ninja.  There's free options available, such as:

{% embed url="https://www.nerds.de/en/loopbe1.html" %}

{% embed url="https://www.tobias-erichsen.de/software/loopmidi.html" %}

See below for a community-created video guide on setting up the Streamdeck with a mac and VDO.Ninja. Let me know if this documentation could use more details.

{% embed url="https://youtu.be/uidN3bLLiVk" %}

## Remote MIDI control

{% hint style="info" %}
This is available for version 19 and higher.
{% endhint %}

This lets you route all MIDI messages from one computer to another computer, with the purpose of remote trigger the VDO.Ninja hotkeys.

```
https://vdo.ninja/beta/?midiremote=4&director=ROOMNAMEHERE
https://vdo.ninja/beta/?room=ROOMNAMEHERE&midiout=1&vd=0&ad=0&push&autostart&label=MIDI_CONTROLLER
```

* \&midiremote={reference \&midi's values; 1 to 4}

{% embed url="https://www.youtube.com/watch?v=rnZ8HM9FL4I" %}
Remote controlling demo
{% endembed %}

{% content-ref url="../director-settings/midiremote.md" %}
[midiremote.md](../director-settings/midiremote.md)
{% endcontent-ref %}

## MIDI pass-through mode

{% hint style="info" %}
This is available for version 18 and higher.
{% endhint %}

This lets you route all MIDI messages from one computer to another computer, going from local MIDI device input to the remote MIDI device output. Example usage:

Starting with VDO.Ninja v20, this will feature will also mirror the channel input, matching the channel with the output. The only control a user has really in configuring it is which device is the input and which device is the output.

```
https://vdo.ninja/?view=Nwz2C7d&midiin=1
https://vdo.ninja/?midiout=0&push=Nwz2C7d
```

* \&midiin={midi output device index; defaults to all} (or \&midipull / \&mi) -- allows for receiving of remote midi. Device indeces starts at 1, where an index of 0 implies "all".
* \&midiout={midi input device index; defaults to all} (or \&midipush / \&mo) -- allows for sending of remote midi.  Device indices starts at 1, where an index of 0 implies "all".

{% content-ref url="midiout.md" %}
[midiout.md](midiout.md)
{% endcontent-ref %}

{% content-ref url="midiin.md" %}
[midiin.md](midiin.md)
{% endcontent-ref %}

It's important to not send and receive between two tabs locally if from the same midi device, as that will create a feedback loop; computer won't like it.

Check the console log or [https://vdo.ninja/midi](https://vdo.ninja/midi) to see which midi device is what device index.

 (1).png>)

While the original MIDI timestamp is transmitted to the remote computer also, it currently isn't included with the output MIDI event itself. I'm just not sure what to use it for currently, but let me know if you need it.

Remote midi transfer does need a VDO.Ninja peer connection to send the MIDI data over. If you don't want to create a connection that includes video and/or audio, you can disable media inputs by using `&vd=0&ad=0`, which disables any audio or video input options.

You can also disable playback of video or audio tracks by using `&novideo&noaudio.`

You can have multiple inputs and outputs per connection.

## Video Guides

{% embed url="https://www.youtube.com/watch?v=uidN3bLLiVk" %}
https://www.youtube.com/watch?v=uidN3bLLiVk
{% endembed %}

{% embed url="https://www.youtube.com/watch?v=mdAzAZo65Mc" %}
https://www.youtube.com/watch?v=mdAzAZo65Mc
{% endembed %}

## Related

{% content-ref url="and-mididevice.md" %}
[and-mididevice.md](and-mididevice.md)
{% endcontent-ref %}

{% content-ref url="and-mididevice.md" %}
[and-mididevice.md](and-mididevice.md)
{% endcontent-ref %}

{% content-ref url="and-midichannel.md" %}
[and-midichannel.md](and-midichannel.md)
{% endcontent-ref %}




---
description: Provides users a clean way of window capturing websites
---

# Electron Capture

{% embed url="https://github.com/steveseguin/electroncapture" %}
[https://github.com/steveseguin/electroncapture](https://github.com/steveseguin/electroncapture)
{% endembed %}

Created for [VDO.Ninja](https://vdo.ninja) users, it can provide users a clean way of window capturing websites. In the case of [VDO.Ninja](https://vdo.ninja), it may offer a more flexible and reliable method of capturing live video than the browser source plugin built into OBS.

 (1).png>)

## Why ?

On some systems the OBS Browser Source plugin isn't available or doesn't work all that well, so this tool is a viable alternative. It lets you cleanly screen-grab just a video stream without the need of the Browser Source plugin. It also makes it easy to select the output audio playback device, such as a Virtual Audio device: i.e.) [https://vb-audio.com/Cable/](https://vb-audio.com/Cable/) (Windows & macOS; donationware).

The app can also be set to remain on top of other windows, attempts to hide the mouse cursor when possible, provides accurate window sizes for 1:1 pixel mapping, and supports global system hotkeys (`CTRL+M` on Windows, for example).

Windows users may find it beneficial too, as it offers support for VDO.Ninja's [`&buffer`](https://docs.vdo.ninja/viewers-settings/buffer) audio sync command and it has robust support for video packet loss. In other words, it can playback live video better than OBS can, with fewer video playback errors and with better audio/video sync. If you have a spare monitor, it may at times be worth the hassle to use instead of OBS alone.

The Electron Capture app uses recent versions of Chromium, which is more resistant to desync, video smearing, and other issues that might exist in the native OBS browser source capture method. [More benefits listed here](https://github.com/steveseguin/electroncapture/blob/master/BENEFITS.md)

Lastly, since playback is agnostic, you can window-capture the same video multiple times, using one copy in a mixed-down live stream, while using a window-capture to record a clean full-resolution isolated video stream.

## Updates

{% content-ref url="../updates/updates-electron-capture-app.md" %}
[updates-electron-capture-app.md](../updates/updates-electron-capture-app.md)
{% endcontent-ref %}




---
description: >-
  A low latency video CDN (content delivery network), which can be used to host
  larger group rooms in VDO.Ninja
---

# Meshcast.io

{% embed url="https://meshcast.io" %}
[https://meshcast.io/](https://meshcast.io/)
{% endembed %}

This is a free to use service that can work in conjunction with VDO.Ninja. It's a low latency video CDN (content delivery network), which can be used to host larger group rooms in VDO.Ninja. It's not designed for mass broadcast, not at present anyways, but it can handle upwards of 100-viewers without taxing your CPU or network.

{% embed url="https://www.youtube.com/watch?v=-7QsLChfdsE" %}
[https://youtu.be/-7QsLChfdsE](https://youtu.be/-7QsLChfdsE)
{% endembed %}

{% content-ref url="../newly-added-parameters/and-meshcast.md" %}
[and-meshcast.md](../newly-added-parameters/and-meshcast.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/meshcast-parameters/" %}
[meshcast-parameters](../advanced-settings/meshcast-parameters/)
{% endcontent-ref %}

## Updates

{% content-ref url="../updates/updates-meshcast.io.md" %}
[updates-meshcast.io.md](../updates/updates-meshcast.io.md)
{% endcontent-ref %}




---
description: Where do I find the native mobile app versions?
---

# Native mobile app versions

VDO.Ninja is primarily a web/browser-based app, however there are also basic mobile app versions available that support simple one-way audio and video publishing. Some users may prefer them, however they are feature limited.

{% embed url="https://play.google.com/store/apps/details?id=flutter.vdo.ninja" %}
Android
{% endembed %}

{% embed url="https://apps.apple.com/us/app/vdo-ninja/id1607609685" %}
iOS
{% endembed %}

At present, the native mobile app versions of VDO.Ninja are fairly basic, but they can be useful for a couple of reasons.

* The native Android app supports screen-sharing, while the browser-based version of VDO.Ninja does not.
* More camera types are listed on the Android native app version; some wide-angle lenses appear that do not appear in the browser-based version.
* Sometimes the native mobile app will work when the browser-based versions do not.
* Additional UVC/HDMI support is available experimentally for Android.

There are some limitations to the native mobile app versions though.

* You can only publish with the mobile apps; you cannot view or listen to remote guests
* UVC camera and mic support is not fully supported yet, but we're working on it. UVC devices are supported via the Raspberry Pi and NVIDIA Jetson devices however (see bottom).
* The native app requires a modern version of Android, while the web-based version of VDO.Ninja has been tested with Android 5.1 using Chrome.
* Older iPhones cannot screen share

### UVC / USB support

Some users with iPhone 15 Pro devices or newer mention USB devices working with VDO.Ninja, perhaps via Safari, but I do not own one to test with.

As per Android, this is a custom version of VDO.Ninja that supports USB video input (such as HDMI to USB). It's basic, and USB audio capture doesn't work, and Android 14 support hasn't been added yet, but give it a go.

{% embed url="https://drive.google.com/file/d/1L8meslXPEzivocH3wz48abNtJ926hQUr/view?usp=drive_link" %}
Andorid APK with USB-support; beta
{% endembed %}

## Download the Android app

You have a few different ways to download and install the Android app for VDO.Ninja. Installing the Google Play Store version is recommended, as it can auto-update with patches and new features automatically.

#### The **Google Play Store**  hosted version is here:&#x20;

{% embed url="https://play.google.com/store/apps/details?id=flutter.vdo.ninja" %}
_(It will auto-update when I push new releases.)_
{% endembed %}

You can also download and install the Android APK file manually:

{% embed url="https://drive.google.com/file/d/1M0kv5nWLtcfl2JOnsAGiG1zUmkeIVLyZ/view?usp=sharing" %}
Download the APK directly from Google Drive, without using the Google Play store\
&#xNAN;_(Manually installing will requires manual updating, as well.  APK last updated May 12, 2022)_
{% endembed %}

Lastly, you can also download the source-code for the Android app, allowing you to build and install the app yourself.

{% embed url="https://github.com/steveseguin/vdon_flutter/" %}
GitHub repository for the app
{% endembed %}

## Download the iOS app

The native iOS app for VDO.Ninja is again available on the Apple App Store.&#x20;

{% embed url="https://apps.apple.com/us/app/vdo-ninja/id1607609685" %}
Download from the Apple App Store - It's Free
{% endembed %}

The native App Store app is very basic, but It does support the ability to stream your camera's output to a remote computer, with the option to enable the Torch light.\
\
While screen share support is available in-app, it currently only works when the app is open for some users, making it a bit useless if you need to switch apps. If you're looking to screen-share from an iPhone or iPad with VDO.Ninja, other ways to do it exist.  See this guide here:&#x20;

{% embed url="https://docs.vdo.ninja/guides/screen-share-your-iphone-ipad" %}
How to screen capture your iPhone or iPad with VDO.Ninja
{% endembed %}

Also note, screen sharing on iOS will not work if using iOS 15 or older. Please upgrade to iOS 17 or newer if using the native app.

## USB / Lightning based audio

USB-based microphones do not work normally.  You can solve this with a TRRS adapter in cases where USB or lightning fails.  I have a video about it here:

{% embed url="https://www.youtube.com/watch?v=BBus_S8iJUE" %}

## Other Problems?

A common problem when using the native application is that the video doens't play when screen sharing.\
\
Try adding \&codec=vp8 to the view-link, as sometimes the phone's h264 harware encoder fails or is unable to support the input video resolution.

If on iOS, screen sharing won't work on older versions of iOS. Please update to the newest version.

You cannot capture the desktop/system audio when screen sharing -- just the microphone's audio. I realize many users want this addressed, however at present I figured out how to get this working.

## Raspberry Ninja

If the mobile app versions of VDO.Ninja do not achieve what you want, there is a Linux / Windows WSL / Apple and embedded-friendly version of VDO.Ninja called Raspberry Ninja.\
\
It supports publishing and viewing videos, VDO.Ninja to NDI support, raw stream recording, built-in multiviewer SFU broadcasting,  and doesn't require a browser. It will work with hardware encoders, CSI-based cameras, and can work on even an extremely basic Raspberry Pi Zero W.

{% embed url="https://raspberry.ninja" %}
Check out Raspberry Ninja if you need more flexibility and don't want to use the browser
{% endembed %}

## Updates

{% content-ref url="../updates/updates-native-mobile-apps.md" %}
[updates-native-mobile-apps.md](../updates/updates-native-mobile-apps.md)
{% endcontent-ref %}

## Related

{% content-ref url="../guides/improving-quality-of-the-native-app.md" %}
[improving-quality-of-the-native-app.md](../guides/improving-quality-of-the-native-app.md)
{% endcontent-ref %}




---
description: Video streaming quality test
---

# Speed and Quality Tests

{% embed url="https://vdo.ninja/alpha/check" %}
[https://vdo.ninja/alpha/check](https://vdo.ninja/alpha/check)
{% endembed %}

## VDO.Ninja Speed and Quality Testing Tools

VDO.Ninja offers specialized testing tools to evaluate your connection quality for video streaming, focusing on metrics critical for WebRTC performance that standard speed tests don't measure.

### Speed Test

**URL:** [**https://vdo.ninja/speedtest**](https://vdo.ninja/speedtest)

The Speed Test provides real-time feedback on your WebRTC connection quality:

* Tests your camera or screen-sharing streaming performance
* Visualizes critical metrics with live graphs:
  * Bitrate (kbps)
  * Buffer delay (ms)
  * Packet loss percentage
* Allows testing against different global regions
* Provides detailed logs of connection statistics
* Supports variable bitrate testing (low/high/default)

This tool is ideal for quick diagnostics and troubleshooting your own setup before important streams.

### Automated Check Test for pre-testing guests

**URL:** [**https://vdo.ninja/check**](https://vdo.ninja/check)

The Check Test runs comprehensive automated tests of a user's system and connection:

* Conducts network bandwidth measurements via Cloudflare
* Tests camera and microphone access
* Performs automated testing at increasing bitrates (2500 → 4000 → 6000 kbps)
* Takes approximately 90 seconds to complete
* Automatically stores results on the server for up to 7 days
* Generates shareable results links

Pre-checking guests days before a live stream is crucial for identifying and resolving technical issues in advance, preventing embarrassing on-air failures and giving production teams adequate time to implement solutions without the pressure of an imminent broadcast.

#### Key Features:

* **Shareable Results**: After completion, provides a link to results that can be shared with stream organizers
* **Pre-assigned IDs**: Use `?id=xxx` parameter to pre-assign test IDs (example: `https://vdo.ninja/check?id=exampleGuest123`)
* **Screening Tool**: Ideal as a pre-tech-check for guests before important streams

### Results Viewer

**URL:**[ **https://vdo.ninja/results?id=xxx**](https://vdo.ninja/results?id=xxx)

View comprehensive test results including:

* Average video bitrate
* Buffer delay (video latency)
* Packet loss statistics
* CPU/network limitation indicators
* Browser and device information
* Codec support details

### Why Packet Loss Matters

Packet loss is critical for WebRTC video quality but is not measured by standard speed tests. Even small amounts of packet loss can cause:

* Video freezing
* Audio dropouts
* Quality degradation
* Increased latency

The VDO.Ninja tests specifically measure packet loss percentages, with ideal results being under 0.1% and problematic levels exceeding 1%.

These tools are essential for properly evaluating streaming readiness, especially when screening multiple participants before important broadcasts.

<figure><figcaption></figcaption></figure>

Testing regions for VDO.ninja/check\
[https://vdo.ninja/regions](https://vdo.ninja/alpha/regions)

There is also another Speed Test option here:\
[https://vdo.ninja/speedtest](https://vdo.ninja/speedtest)

## Updates

{% content-ref url="../updates/updates-speed-test.md" %}
[updates-speed-test.md](../updates/updates-speed-test.md)
{% endcontent-ref %}




---
description: Useful tools that could help you make your stream better
---

# Tech Demonstrations

<table><thead><tr><th width="197">Tool</th><th width="549">Description</th></tr></thead><tbody><tr><td><a href="https://vdo.ninja/examples/">Overview</a></td><td>Overview of all the Tech Demonstrations</td></tr><tr><td><a href="https://vdo.ninja/examples/p2p.html">P2P</a></td><td>How to use VDO.Ninja as a data transport tunneling service</td></tr><tr><td><a href="https://vdo.ninja/twitch">Twitch</a></td><td>How to have a Twitch live chat side-by-side with VDO.Ninja on the same screen (viewing Twitch chat while using VDO.Ninja on mobile)</td></tr><tr><td><a href="https://vdo.ninja/examples/youtube.html">YouTube</a></td><td>How to have a YouTube live chat side-by-side with VDO.Ninja on the same screen</td></tr><tr><td><a href="https://vdo.ninja/examples/dual.html">Dual</a></td><td>How to have two VDO.Ninja windows (or any windows really) open on the same page; Picture-in-Picture style</td></tr><tr><td><a href="https://vdo.ninja/examples/multi.html?rooms=room1xx,room2xx,room3xx">Multiple Rooms</a></td><td>How to have multiple director rooms open in a single tab; note the URL's <code>?rooms=xx,yy</code> command</td></tr><tr><td><a href="https://versus.cam/">versus.cam</a></td><td>How to use the IFRAME API to transport audio and video to the parent frame in Chrome</td></tr><tr><td><a href="https://vdo.ninja/examples/addtoscene.html">Add to scene</a></td><td>How to use the IFrame API to add/remove guests to a scene remotely</td></tr><tr><td><a href="https://vdo.ninja/examples/bigmutebutton.html">Big Mute Button</a></td><td>Mobile-friendly big-button for muting yourself easily</td></tr><tr><td><a href="https://vdo.ninja/examples/sensors.html">Sensors</a></td><td>How to transmit sensor and video data from a phone to a computer, drawing it to canvas.</td></tr><tr><td><a href="https://vdo.ninja/examples/sensoroverlay.html">Sensor Overlay</a></td><td>Overlay the incoming speed from remote mobile sensor data onto your video</td></tr><tr><td><a href="https://vdo.ninja/midi">MIDI</a></td><td>Demonstrates the MIDI API for VDO.Ninja</td></tr><tr><td><a href="https://vdo.ninja/examples/draggable.html">Draggable</a></td><td>Demonstrates how to drag multiple windows around, if you wanted to create a custom layout of elements. (experimental)</td></tr><tr><td><a href="https://vdo.ninja/examples/chatoverlay.html">Chat overlay</a></td><td>Example of a chat-only interface for VDO.Ninja; maybe dockable into OBS even.</td></tr><tr><td><a href="https://vdo.ninja/examples/iframe.outbound-stats.html">iFrame outbound stats</a></td><td>iframe.outbound-stats.html demonstrates how to get stats from VDO.Ninja using the IFRAME API</td></tr><tr><td><a href="https://vdo.ninja/examples/changepass.html">Change password</a></td><td>Lets you create passwords and related HASH values for VDO.Ninja rooms</td></tr><tr><td><a href="https://vdo.ninja/webhid">WebHID</a></td><td>WebHID demonstrates how to interface with a USB device, like a Streamdeck (mouse/keyboard not supported)</td></tr><tr><td><a href="https://vdo.ninja/examples/zoom.html">Zoom</a></td><td>A tool for letting you publish into VDO.Ninja, but then full-screen the window once setup, allowing for window-capturing into zoom.</td></tr><tr><td><a href="https://vdo.ninja/examples/obs_remote/index">OBS Remote</a></td><td>Also hosted on GitHub elsewhere, but it's an example of how to remotely control OBS using VDO.Ninja's tunneling abilities</td></tr><tr><td><a href="https://vdo.ninja/alpha/examples/overlay">Overlay</a></td><td>Create a sample of how to apply a custom full-page overlay on top of VDO.Ninja</td></tr><tr><td><a href="https://vdo.ninja/examples/powerpoint">PowerPoint Remote Control</a></td><td>Remote PowerPoint Web control via VDO.Ninja (IFrame API)</td></tr><tr><td><a href="https://vdo.ninja/examples/rotated.html">Rotate website</a></td><td>Lets you rotate a specific website 90, 270, or 180 degrees</td></tr><tr><td><a href="https://vdo.ninja/examples/waitingroom?room=TESTROOM123">Waiting room</a></td><td>Prompts a guest who is joining a room with a message if the director is not there yet</td></tr><tr><td><a href="https://vdo.ninja/alpha/examples/obsremote">OBS Remote Control</a></td><td>A code example of how to use the IFRAME API of VDO.Ninja to remotely control OBS</td></tr><tr><td><a href="https://vdo.ninja/alpha/examples/ptz">PTZ Remote Controller</a></td><td>Remotely control the pan tilt of a camera</td></tr></tbody></table>




---
description: Focus on ease of use and high-bitrate / e-sports streams
---

# Versus.cam

{% embed url="https://versus.cam/" %}

Versus.cam is the upcoming and standalone replacement for the [vdo.ninja/monitor](https://vdo.ninja/monitor) page. Versus.cam has some interesting features that are specific to the upcoming version of VDO.Ninja, so at the moment it only works in conjunction with [vdo.ninja/alpha](https://vdo.ninja/alpha/).

### Details

* It contains a larger and dedicated graph per scene/view link than what the [vdo.ninja/beta/'s ](https://vdo.ninja/beta/)director room has under scene-stats. Both color code to indicate packet loss, where red is bad, and green is good.&#x20;
* It is setup to use a group room by default, with a very simple interface to login and get started without visiting VDO.ninja itself.&#x20;
* Despite having a group room by default, it works with standalone push/view links as well, via the "Add a stream manually" button, which lets you include normal view links that exist outside rooms.
* All the scene links and invite links are preconfigured for E-Sports , where video is set to pull around 20-mbps for smooth 1080p60 game play. The idea is, if you choose to use this page for creating links, it's all already setup to be used for ingestion.
* The room is configured so that guests cannot see or talk to each other. All guests can do is text-chat with the versus host.

 (2) (2).png>)

* Versus.cam is compatible with a director and the director room, so you can use a director room AND the Versus.cam room at the same time, without conflict.
* A new feature that Versus.cam has, that will also soon be coming to the normal VDO.Ninja directors' room, is the ability to **dynamically change the resolution and bitrate of remote scenes**. This works by means of the [`&remote`](../general-settings/remote.md) control feature, which is preconfigured in the links already, so no director is needed when using versus. This will then also work with non-room links, so long as [`&remote`](../general-settings/remote.md) is included in their URL.
* I don't intend to add many advanced features to this site.
* It's designed to be very simple, elegant, and hyper focused on a single use case and user type.
* E-Sports and one-way ingestion of very high quality video. I'll likely be making more scenario-specific interfaces in the future like this, to make VDO.Ninja easier and less cluttered for common use cases.
* Versus.cam is built using the VDO.Ninja IFRAME API, which I hope demonstrates the flexibility of it.
* Versus.cam is only supported by Chrome/Chromium-based browsers; it isn't yet compatible with Firefox/Safari (they lack the features needed for it to operate).

[Please report bugs](https://discord.gg/qWDshMsTar). It's a first release, using the alpha version of VDO.Ninja, so bugs are kind of expected.

{% embed url="https://youtu.be/I12ASNWHPPI" %}
[https://youtu.be/I12ASNWHPPI](https://youtu.be/I12ASNWHPPI)
{% endembed %}

## Updates

{% content-ref url="../updates/updates-versus.cam.md" %}
[updates-versus.cam.md](../updates/updates-versus.cam.md)
{% endcontent-ref %}




# Whiteboard

## VDO.Ninja Whiteboard: Live Streaming Collaboration Tool

### Overview

VDO.Ninja Whiteboard is a powerful, browser-based drawing tool that integrates with VDO.Ninja's peer-to-peer streaming technology. It allows you to create and share live drawings, diagrams, or annotations with viewers in real-time without requiring any downloads, installations, or accounts.

### **You can access it here:**[ **https://vdo.ninja/whiteboard**](https://vdo.ninja/whiteboard)

<figure><figcaption><p>Example Masterpiece</p></figcaption></figure>

### Key Features

* **Live Whiteboard Streaming**: Share your drawings in real-time with anyone through a simple view link
* **Multiple Publishing Options**: Stream via VDO.Ninja P2P, WHIP, or directly to Twitch
* **End-to-End Encryption**: When using the VDO.Ninja mode, all streams are encrypted peer-to-peer
* **Drawing Tools**: Includes brush, text tool, eraser, fill tool, and color picker
* **No-Install Browser Based**: Works entirely in your browser with no plugins required
*   **Free and Open Source**: Use it without cost or limitations\

    <figure><figcaption><p>Menu setup</p></figcaption></figure>

### How It Works with VDO.Ninja

The whiteboard leverages VDO.Ninja's P2P data channels and media streaming capabilities to broadcast your canvas to viewers securely and efficiently.

#### Technical Integration

1. **Embedding VDO.Ninja**: The whiteboard creates a hidden iframe that loads VDO.Ninja with specific parameters:

```javascript
function createAndAppendIframe(config) {
    let url = new URL("./index.html", window.location.href);
    
    if (config.mode === 'vdo') {
        if (config.room) url.searchParams.set("room", config.room);
        if (config.push) url.searchParams.set("push", config.push);
        if (config.password) url.searchParams.set("password", config.password);
    }
    
    url.searchParams.set("framegrab", "");
    url.searchParams.set("view", "");

    const iframe = document.createElement("iframe");
    iframe.style.width = "0";
    iframe.style.height = "0";
    iframe.src = url.toString();
    
    document.body.appendChild(iframe);
    return iframe;
}
```

2. **Canvas Streaming**: The whiteboard captures the canvas content and sends it to the VDO.Ninja iframe:

```javascript
async function startStreaming() {
    const iframe = document.querySelector('iframe');
    if (!iframe) return;

    // Using modern MediaStreamTrackProcessor API when available
    if (typeof MediaStreamTrackProcessor === 'function') {
        const { tracks } = await createCanvasStream();
        
        // Send frames to the VDO.Ninja iframe
        const processor = new MediaStreamTrackProcessor(track);
        const reader = processor.readable.getReader();
        
        // Read and send each frame
        // ...
    } else {
        // Fallback to sending canvas as data URL
        frameGenerator = setInterval(() => {
            const imageData = canvas.toDataURL('image/webp');
            iframe.contentWindow.postMessage({
                type: 'canvas-frame',
                frame: imageData
            }, '*');
        }, 1000/10); // 10 fps
    }
}
```

3. **View Link Generation**: When using VDO.Ninja mode, it generates a view link that can be shared with viewers:

```javascript
const viewUrl = new URL("./", window.location.href);
if (push) viewUrl.searchParams.set("view", push);
if (room) viewUrl.searchParams.set("room", room);
if (password) viewUrl.searchParams.set("password", password);
document.getElementById('viewLink').value = viewUrl.toString();
```

### How to Use the Whiteboard

1. **Access the Tool**: Open the whiteboard in any modern browser
2. **Choose Publishing Mode**:
   * VDO.Ninja (P2P): For secure, peer-to-peer streaming
   * WHIP: For streaming to any WHIP-compatible service
   * Twitch: For direct streaming to Twitch
   * Playground: For local drawing with no streaming
3. **Configure Your Stream**:
   * For VDO.Ninja mode, enter an optional Stream ID and/or Room Name
   * Set a password if desired for privacy
4. **Start Drawing**: Use the brush, text, eraser, and fill tools to create your content
5. **Share the View Link**: Copy and share the generated view link with anyone you want to see your whiteboard

### Benefits of Using VDO.Ninja Integration

* **Low Latency**: Direct peer-to-peer connections provide near real-time sharing
* **Privacy**: End-to-end encryption ensures your whiteboard sessions remain private
* **Firewall Friendly**: Works through NATs and firewalls without port forwarding
* **Scalability**: Multiple viewers can connect simultaneously
* **Cost Effective**: No server costs as data transfers directly between peers
* **Cross-Platform**: Works on any device with a modern browser

### Use Cases

* Remote teaching and tutoring
* Live diagramming during video conferences
* Virtual brainstorming sessions
* Real-time collaboration on design concepts
* Creating explanatory drawings for live streams
* Adding visual annotations to presentations

The VDO.Ninja Whiteboard combines the power of HTML5 Canvas with VDO.Ninja's peer-to-peer streaming technology to provide a versatile, secure, and accessible tool for real-time visual communication.




---
description: >-
  Awesome tools made by the community that help with common VDO.Ninja-related
  tasks
---

# Community contributed tools

There's some tools out there made by the greater community that can help with common [VDO.Ninja](https://vdo.ninja/) related-tasks. If you want your project listed here, please get in contact with us at the discord ([discord.vdo.ninja](https://discord.vdo.ninja)).

| Tool                                                                                                                              | Description                                                                                                                                       | Author                                                                                       |
| --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| [Linkgen](https://linkgen.vdo.ninja/)                                                                                             | Wizard style links generator                                                                                                                      | [@jcalado](https://github.com/jcalado/)                                                      |
| [Invite Generator](https://invite.vdo.ninja/)                                                                                     | Toggle style links generator                                                                                                                      | [@jcalado](https://github.com/jcalado/)                                                      |
| [Trampoline](https://rse.github.io/vdo-ninja-trampoline/)                                                                         | Another awesome link generator for VDO.Ninja                                                                                                      | [Dr. Ralf S. Engelschall](https://github.com/rse)                                            |
| [Vingester](https://github.com/steveseguin/vingester)                                                                             | Ingest web pages as NDI-multicasted streams                                                                                                       | [Dr. Ralf S. Engelschall](https://github.com/rse)                                            |
| [Cheat Sheets](https://github.com/steveseguin/obsninja/blob/quickstart/README.md)                                                 | Quick start guides and cheat sheets                                                                                                               | [Chris Marquardt](https://chrismarquardt.com/)                                               |
| [Show Manager](https://github.com/knmurphy/show-manager-obsn)                                                                     | Excel based link configuration tool                                                                                                               | [@knmurphy](https://github.com/knmurphy)                                                     |
| [Pro Audio Matrix](https://docs.google.com/spreadsheets/d/1onfIh1hNR1Gh\_mthkhmezzWNUMYKMGKPrwx7T428\_hc/edit#gid=0)              | Detailled sheet of how to use [`&proaudio`](../advanced-settings/audio-parameters/and-proaudio.md) and [`&stereo`](../general-settings/stereo.md) | ?                                                                                            |
| [Cheat Sheet 2](https://docs.google.com/spreadsheets/d/15xPoTeLnOufB2VCRm-Aj-uP9KCMWMiLTxxypcwEyVsc/edit?usp=sharing)             | A simple Google Sheets list of most common parameters                                                                                             | qdaps on Discord                                                                             |
| [Cheat Sheet 3](https://docs.google.com/spreadsheets/d/1rNPus\_c6fLwNIKOr1WCZZVMRWtlNJttUNtvvelInuRU)                             | A Google Sheets list of all available parameters                                                                                                  | JK14 on Discord                                                                              |
| [URL Configurator](https://drive.google.com/file/d/1A7qiFACoCxk9J-uTv9yyZa5yQWzFol8l/view?usp=sharing)                            | Excel based URL Link Configurator                                                                                                                 | JK14 on Discord                                                                              |
| [Layout String Generator](https://docs.google.com/spreadsheets/d/1cHBTfni-Os3SAITsXrrNJ3qVCMVjunuW3xugvw1dykw/edit#gid=151839312) | For [`&layouts`](../advanced-settings/director-parameters/and-layouts.md) parameter                                                               | JK14 on Discord                                                                              |
| [API / IFRAME sandbox page](https://vdo.ninja/alpha/iframe)                                                                       | API / IFRAME Sandbox page for developer using VDO.Ninja                                                                                           | Sam MacKinnon on Discord                                                                     |
| [Companion Module](https://github.com/bitfocus/companion-module-vdo-ninja)                                                        | Remote control VDON via this plugin for Companion                                                                                                 | [Bryce](https://github.com/bitfocus/companion-module-vdo-ninja/commits?author=bryce-seifert) |
| [VirtualCam Filter](https://github.com/exeldro/obs-virtual-cam-filter)                                                            | Select any source in OBS to be the virtual cam output                                                                                             | [Exeldro](https://obsproject.com/forum/members/exeldro.128836/)                              |
| [Source Record](https://obsproject.com/forum/resources/source-record.1285/)                                                       | Record a source in OBS that is different than the output                                                                                          | [Exeldro](https://obsproject.com/forum/members/exeldro.128836/)                              |
| [OBS Audio Monitor](https://obsproject.com/forum/resources/audio-monitor.1186/)                                                   | Plugin for OBS; adds Audio Monitor dock and filter                                                                                                | [Exeldro](https://obsproject.com/forum/members/exeldro.128836/)                              |
| [Win Cap Audio](https://obsproject.com/forum/resources/win-capture-audio.1338/)                                                   | Capture audio from specific window in OBS                                                                                                         | [bozbez](https://obsproject.com/forum/members/bozbez.344203/)                                |
| [Browser to RTMP](https://github.com/steveseguin/browser-to-rtmp-docker)                                                          | A docker container that lets you output a VDO.Ninja to RTMP                                                                                       | [aws-samples](https://github.com/aws-samples/amazon-chime-meeting-broadcast-demo)            |
| [Atrium Vertical](https://obsproject.com/forum/resources/aitum-vertical.1715/)                                                    | Allow OBS to publish both Portrait (vertical) and Landscape (16:9) video at the same time.                                                        | [Aitum](https://obsproject.com/forum/members/aitum.441032/)                                  |

The video engineering and live streaming community is pretty amazing, so thank you all for being so awesome. ♥




---
description: >-
  WHIP allows you to publish to supported sites, like Twitch, directly from
  VDO.Ninja
---

# WHIP and WHEP tooling

Using the newly added WHIP ingest end point at Twitch, you can now publish directly from VDO.Ninja to Twitch. Low-latency, no downloads needed, and free.

WHIP is a bit like the classic RTMP publishing, but it's far more advanced, includes AV1 video codec support, and can even work within your browser. Best of all, VDO.Ninja supports it. VDO.Ninja can both act as a host for WHIP publishers, such as OBS Studio, or it can publish video via WHIP to WHIP broadcasting hosts, such as Twitch, Janus, Mediamtx, Pion, Cloudflare, and many more.

WHEP, on the other hand, is generally used to playback video using the same technology, rather to publish it. VDO.Ninja also supports WHEP playback and hosting, with advanced statistic panels, recording, and buffering options.&#x20;

### Our WHIP page for making WHIP / WHEP easy

To make using WHIP and WHEP more accessible, VDO.Ninja has a hosted page with common tools for making use of it, such as publishing a video or screen share to Twitch.

{% embed url="https://vdo.ninja/whip" %}
[https://vdo.ninja/whip](https://vdo.ninja/whip)
{% endembed %}

This is the future! To try it out, visit [https://vdo.ninja/whip](https://vdo.ninja/whip), enter your Twitch stream token in the correct field, GO, and then select your camera in VDO.Ninja as normal.\
\
.png>).png>)

### Alpha version of WHIP support and features

The alpha version of VDO.Ninja has the cutting edge available to it, often with even more advanced features and fixes that have not yet made it available to the production stable release.

Check out the alpha version here: [https://vdo.ninja/alpha/whip](https://vdo.ninja/alpha/whip)

### WHIP ingest from OBS Studio or other

While VDO.Ninja can act as a host for incoming WHIP requests (published to `https://whip.vdo.ninja/YOURTOKENHERE`), many such publishing clients do not support NAT traversal or STUN server support yet.&#x20;

OBS Studio v30 does not, for example, so it may not work if publishing to someone who is behind a firewall. Still, even in those cases, the WHIP ingest feature will still work when:

* on the same Local Area Network as the publisher,&#x20;
* if hosting VDO.Ninja on a cloud server with public IP address available,&#x20;
* if your UDP ports are being forwarded (UDP ports 4096-65535)
* of if your local IP address is set to the DMZ mode target within your router's network settings.\

While it's possible OBS v31 fixes this issue, I do have a custom version of OBS that also has proper VDO.Ninja WHIP support [available for Win64 here.](https://backup.vdo.ninja/OBS_VDO_Ninja.zip) \[[fork](https://github.com/steveseguin/obs-studio)]  This version should let you publish WHIP via VDO.Ninja across the Internet, regardless of Firewall. (This OBS binary was last built November 2024.)\

For other WHIP publishing clients, such as Gstreamer's whip element, VDO.Ninja will already work with them in most cases, even across firewalls. Not all though.

I welcome support and engagement from other developers to work through these issues, so please reach out if you'd like to speak.

In terms of ideal settings for OBS's WHIP output into VDO.Ninja, below you can find a link to some recommended encoder options, to ensure smoothest playback

{% content-ref url="../guides/obs-whip-output-settings.md" %}
[obs-whip-output-settings.md](../guides/obs-whip-output-settings.md)
{% endcontent-ref %}

For more help, join the Discord

{% embed url="https://discord.vdo.ninja" %}
Contact me on Discord
{% endembed %}

### Using WHIP + WHEP to host your own Meshcast service

For more advanced users, you can use VDO.Ninja's WHIP/WHEP support, with your own WHIP/WHEP compatible broadcasting host, to provide your own Meshcast functionality within VDO.Ninja.

The [Meshcast service](meshcast.io.md) long offered by VDO.Ninja works like a WHIP/WHEP host, offloading video distribution via the hosted servers, thus avoiding the need for multiple p2p streams. As a result, it was pretty easy to add support for generic WHIP/WHEP hosting alternatives.

Currently a guide on using Cloudflare as the host is available, located here, [https://vdo.ninja/cloudflare](https://vdo.ninja/cloudflare), with guides for other self-hosted providers becoming available all the time.

For the highly technical and curious, please note that if your WHIP server's response header includes a WHEP URL in it, where the WHIP stream can be viewed from, VDO.Ninja will automatically provide that URL to connected viewers to use as the main video source.

ie: WHEP: [`https://whep.urdomain.com/yourstreamtoken`](https://whep.urdomain.com/yourstreamtoken)

### Demo video, showing us publishing from VDO.Ninja to Twitch

{% embed url="https://youtu.be/_RHBsAJmfGs?si=653vhKBJesct_cmS" %}
[https://youtu.be/\_RHBsAJmfGs?si=653vhKBJesct\_cmS](https://youtu.be/_RHBsAJmfGs?si=653vhKBJesct_cmS)
{% endembed %}

### The VDO.Ninja Mixer app supports WHIP out also

The VDO.Ninja [Mixer App](mixer-app.md) ([https://vdo.ninja/alpha/mixer](https://vdo.ninja/alpha/mixer)) supports WHIP output, with an option to publish directly to Twitch as well. If OBS is too much for you, and you need just a simple studio and mixing controls, this could be a great option for you.

### `&publish` URL option

While still a work in progress, some of the features of the [https://vdo.ninja/whip](https://vdo.ninja/whip) page, primarily the WHIP publishing features, are also slowly being added as an integral part of VDO.Ninja itself.

While this may change in the future, adding `&publish` to the URL of a VDO.Ninja (v24) will let you select a screen to capture and publish to a WHIP endpoint. This may also be added as built-in menu option at some point as well, allowing you to select any screen, page, or element to publish via WHIP.

### Raspberry Ninja also now supports WHIP output

[Raspberry.Ninja](raspberry.ninja/) isn't just for Raspberry Pis, but works on a Linux system really, along with Windows WSL.

If you want low-level controls over AV1 codec encoding and other facets of WHIP publishing that can't be obtained via the browser, check it out. It of course also supports VDO.Ninja, has a built-in SFU for VDO.Ninja, and lots more!

{% embed url="https://raspberry.ninja" %}

## Related

{% content-ref url="../advanced-settings/whip-parameters/" %}
[whip-parameters](../advanced-settings/whip-parameters/)
{% endcontent-ref %}

{% content-ref url="../guides/obs-whip-output-settings.md" %}
[obs-whip-output-settings.md](../guides/obs-whip-output-settings.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/whip-parameters/and-whip.md" %}
[and-whip.md](../advanced-settings/whip-parameters/and-whip.md)
{% endcontent-ref %}

## Updates

{% content-ref url="../updates/updates-whip-whep.md" %}
[updates-whip-whep.md](../updates/updates-whip-whep.md)
{% endcontent-ref %}




---
description: Auto-hides the control bar after a few moments of the mouse being idle
---

# \&autohide

Sender-Side Option! ([`&push`](../source-settings/push.md))

## Details

`&autohide` auto-hides the control bar after a few moments of the mouse being idle.

You can also toggle the control bar with `SHIFT + ALT + C`.

## Related

{% content-ref url="../advanced-settings/settings-parameters/and-controlbarspace.md" %}
[and-controlbarspace.md](../advanced-settings/settings-parameters/and-controlbarspace.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/design-parameters/cleanoutput.md" %}
[cleanoutput.md](../advanced-settings/design-parameters/cleanoutput.md)
{% endcontent-ref %}




---
description: Starts any screen-share paused
---

# \&sspaused

Viewer-Side Option! ([`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md), [`&room`](../general-settings/room.md))

## Aliases

* `&sspause`
* `&ssp`

## Details

`&sspaused` starts any screen-share paused (0-kbps bitrate for audio and video). A play button overlay can be clicked to start it playing as normal.

 (1) (2) (1).png>)

## Related

{% content-ref url="../newly-added-parameters/and-screensharebitrate.md" %}
[and-screensharebitrate.md](../newly-added-parameters/and-screensharebitrate.md)
{% endcontent-ref %}

{% content-ref url="../source-settings/screensharequality.md" %}
[screensharequality.md](../source-settings/screensharequality.md)
{% endcontent-ref %}




---
description: List of apps and helper tools Steve has created to be used with VDO.Ninja
---

# Steve's helper apps & tools

* [#electron-capture](steves-helper-apps.md#electron-capture "mention")
* [#youtube-twitch-chat-and-social-comment-overlays-plugin](steves-helper-apps.md#youtube-twitch-chat-and-social-comment-overlays-plugin "mention")
* [#meshcast.io](steves-helper-apps.md#meshcast.io "mention")
* [#caption.ninja](steves-helper-apps.md#caption.ninja "mention")
* [#raspberry-ninja](steves-helper-apps.md#raspberry-ninja "mention")
* [#native-mobile-app-versions-for-vdo.ninja](steves-helper-apps.md#native-mobile-app-versions-for-vdo.ninja "mention")
* [#social-stream](steves-helper-apps.md#social-stream "mention")
* [#versus.cam](steves-helper-apps.md#versus.cam "mention")

## Electron Capture

[https://github.com/steveseguin/electroncapture](https://github.com/steveseguin/electroncapture)

Created for [VDO.Ninja](https://vdo.ninja) users, it can provide users a clean way of window capturing websites. In the case of [VDO.Ninja](https://vdo.ninja), it may offer a more flexible and reliable method of capturing live video than the browser source plugin built into OBS.

.png>)

### Why ?

On some systems the OBS Browser Source plugin isn't available or doesn't work all that well, so this tool is a viable alternative. It lets you cleanly screen-grab just a video stream without the need of the Browser Source plugin. It also makes it easy to select the output audio playback device, such as a Virtual Audio device: ie) [https://vb-audio.com/Cable/](https://vb-audio.com/Cable/) (Windows & macOS; donationware).

The app can also be set to remain on top of other windows, attempts to hide the mouse cursor when possible, provides accurate window sizes for 1:1 pixel mapping, and supports global system hotkeys (`CTRL+M` on Windows, for example).

Windows users may find it beneficial too, as it offers support for VDO.Ninja's [`&buffer`](https://docs.vdo.ninja/viewers-settings/buffer) audio sync command and it has robust support for video packet loss. In other words, it can playback live video better than OBS can, with fewer video playback errors and with better audio/video sync. If you have a spare monitor, it may at times be worth the hassle to use instead of OBS alone.

The Electron Capture app uses recent versions of Chromium, which is more resistant to desync, video smearing, and other issues that might exist in the native OBS browser source capture method. [More benefits listed here](https://github.com/steveseguin/electroncapture/blob/master/BENEFITS.md)

Lastly, since playback is agnostic, you can window-capture the same video multiple times, using one copy in a mixed-down live stream, while using a window-capture to record a clean full-resolution isolated video stream.

## Chat Overlay

[https://chat.overlay.ninja](https://chat.overlay.ninja)

This Chrome browser extension turns your social chat and comments section into selectable social overlays for OBS Studio or other studio production software.

This chat overlay extension will forward the selected chat message over a web-socket connection to a secondary webpage, which can be used in OBS-Studio as a simple browser source. This makes capturing the chat messages from a live video stream very easy and fast -- no Chroma keying or window-capturing needed. It also makes customizing the style pretty easy, with no Chrome extension development needed.

**Supported sites as of August 2022 (requests welcomed)**

* glimesh.tv (pop-out chat)
* youtube.com (pop-out chat)
* twitch.tv (pop-out chat)
* restream.io (go here: [https://chat.restream.io/chat](https://chat.restream.io/chat))
* trovo.live (pop-out chat)
* Instagram (posts) (trigger it with a button)
* Instagram Live (click on chat messages)
* Twitter (works with tweets and replies)
* Facebook Live chat (no pop up option; does not support Mobile/4G/LTE - wifi or ethernet only)
* Crowdcast.io
* Zoom.us (text chat and polls)
* polleverywhere.com ([https://www.polleverywhere.com/discourses/xxxxx](https://www.polleverywhere.com/discourses/xxxxx) question page)
* Trovo (open the chat pop-up page: [https://trovo.live/chat/xxxxxx](https://trovo.live/chat/xxxxxx))

📺 Video demoing how to install and use here: [https://youtu.be/UOg3RvHO-xk](https://youtu.be/UOg3RvHO-xk)

.png>)

## Meshcast.io

[https://meshcast.io](https://meshcast.io)

This is a free to use service that can work in conjunction with VDO.Ninja. It's a low latency video CDN (content delivery network), which can be used to host larger group rooms in VDO.Ninja. It's not designed for mass broadcast, not at present anyways, but it can handle upwards of 100-viewers without taxing your CPU or network.

{% embed url="https://www.youtube.com/watch?v=-7QsLChfdsE" %}
[https://youtu.be/-7QsLChfdsE](https://youtu.be/-7QsLChfdsE)
{% endembed %}

## Caption.Ninja

### Caption

[https://caption.ninja/](https://caption.ninja/)

Although VDO.Ninja supports captions, sometimes you need something simple yet flexible. Caption.Ninja lets you use the browser's built in speech-to-text service to provide overlay captions for your live stream.\
\
Captions are streamed via a web-socket service to your OBS or other studio software, where they can be shown over your video.

Transcriptions can be saved by means of copy and paste when done, multiple languages are supported, and even **manual** user-entered captions support is provided at [https://caption.ninja/manual](https://caption.ninja/manual)

### Translation

[https://caption.ninja/translate](https://caption.ninja/translate)

Added a "translation" component to caption.ninja, so you can convert speakers to a single language for overlay on stream. I tried this before, but only now do I think I have it working okay. There's two ways to use it:

1\. You can go here to explore and tinker.[ https://caption.ninja/translate](https://caption.ninja/translate) which offers a bit of a menu to play with, but is sender's side-based translation (works in a single page, but you can't translate to more than one language)

2\. And then there's the normal way of using caption.ninja, which offers viewer-side translation and scrolling support, so you can use this mode to have different languages as outputs instead of just one (assuming the viewer supports the translation code).

[https://caption.ninja/?room=ufv3QaH\&lang=en-US](https://caption.ninja/?room=ufv3QaH\&lang=en-US) (to capture as english) and [https://caption.ninja/overlay?room=ufv3QaH\&translate=fr](https://caption.ninja/overlay?room=ufv3QaH\&translate=fr) (viewer-side, which converts to french).

I welcome feedback.

## Raspberry Ninja

[https://raspberry.ninja](https://raspberry.ninja)

Turn your Raspberry Pi or Nvidia Jetson into a Ninja-cam with hardware-acceleration enabled! Publish live streaming video to VDO.Ninja on the cheap at very high resolutions! The script for the Nvidia Jetson ($69 and up) is setup to plug in a $10 1080p30 HDMI to USB adapter and go, while the Raspberry Pi is setup as a quick-deploy image that can work with the official Raspicam.\

.png>)

## Native mobile app versions for VDO.Ninja

Mobile native app versions of VDO.Ninja can be found behind the link below. These are mainly backup options for when the browser-based versions fail to work or lack a certain feature due to system restrictions.

{% content-ref url="getting-started/native-mobile-app-versions.md" %}
[native-mobile-app-versions.md](getting-started/native-mobile-app-versions.md)
{% endcontent-ref %}

## Social Stream

[https://socialstream.ninja](https://socialstream.ninja)

Consolidate your live social messaging streams, including Youtube, Twitch, and more, into a single chat stream that can be docked into OBS and be used to to select featured chat messages as an overlay.

Very much like Chat Overlay Ninja, except is purely for live chat and has a focus on consolidation of chat messages, instead of just featured chat. Has many features and supported sites at this point.

 (1) (1) (1).png>)

{% embed url="https://social.overlay.ninja" %}
[https://github.com/steveseguin/social\_stream#readme](https://github.com/steveseguin/social\_stream#readme)
{% endembed %}

## Versus.cam

[https://versus.cam/](https://versus.cam/)

Versus.cam is the upcoming and standalone replacement for the [vdo.ninja/monitor](https://vdo.ninja/monitor) page. Versus.cam has some interesting features that are specific to the upcoming version of VDO.Ninja, so at the moment it only works in conjunction with [vdo.ninja/alpha](https://vdo.ninja/alpha/).

### Details

* It contains a larger and dedicated graph per scene/view link than what the [vdo.ninja/beta/'s ](https://vdo.ninja/beta/)director room has under scene-stats. Both color code to indicate packet loss, where red is bad, and green is good.&#x20;
* It is setup to use a group room by default, with a very simple interface to login and get started without visiting vdo.ninja itself.&#x20;
* Despite having a group room by default, it works with standalone push/view links as well, via the "Add a stream manually" button, which lets you include normal view links that exist outside rooms.
* All the scene links and invite links are preconfigured for E-Sports , where video is set to pull around 20-mbps for smooth 1080p60 game play. The idea is, if you choose to use this page for creating links, it's all already setup to be used for ingestion.
* The room is configured so that guests cannot see or talk to each other. All guests can do is text-chat with the versus host.

.png>)

* Versus.cam is compatible with a director and the director room, so you can use a director room AND the Versus.cam room at the same time, without conflict.
* A new feature that Versus.cam has, that will also soon be coming to the normal VDO.Ninja directors' room, is the ability to **dynamically change the resolution and bitrate of remote scenes**. This works by means of the [`&remote`](general-settings/remote.md) control feature, which is preconfigured in the links already, so no director is needed when using versus. This will then also work with non-room links, so long as [`&remote`](general-settings/remote.md) is included in their URL.
* I don't intend to add many advanced features to this site.
* It's designed to be very simple, elegant, and hyper focused on a single use case and user type.
* E-Sports and one-way ingestion of very high quality video. I'll likely be making more scenario-specific interfaces in the future like this, to make VDO.Ninja easier and less cluttered for common use cases.
* Versus.cam is built using the VDO.Ninja IFRAME API, which I hope demonstrates the flexibility of it.
* Versus.cam is only supported by Chrome/Chromium-based browsers; it isn't yet compatible with Firefox/Safari (they lack the features needed for it to operate).

Please report bugs. It's a first release, using the alpha version of VDO.Ninja, so bugs are kind of expected.

{% embed url="https://youtu.be/I12ASNWHPPI" %}
[https://youtu.be/I12ASNWHPPI](https://youtu.be/I12ASNWHPPI)
{% endembed %}




---
description: >-
  Does not use webRTC's video streaming protocols; rather it uses a custom-made
  protocol
---

# \&chunked

Sender-Side Option! ([`&push`](../source-settings/push.md))

## Options

Example: `&chunked=2000`

| Value           | Description                           |
| --------------- | ------------------------------------- |
| (integer value) | bitrate in kbps (default around 2000) |

## Details

### Chunked video transfer mode

[Version 20](../releases/v20.md) introduces the option to enable a chunked-video transfer mode, which is similar to how Twitch or YouTube Live broadcasts videos, but using a different and newer technology. This still uses VDO.Ninja's peer to peer connections to distribute video to viewers, except it does not use WebRTC's video streaming protocols; rather it uses a custom protocol over WebRTC data-channels.

The upsides of this mode is that packet loss on a network connection impacts the video stream less, so the quality can be higher. It also makes it easier to record the stream to disk on the viewer's end with no added quality loss and with lower CPU usage. This is because recording a chunked-stream to disk does not require any transcoding on the viewers-end; it just writes the encoded chunks directly to a WebM media container on your disk.

In theory, this mode also allows a video stream to be only encoded once, and then it can be shared with multiple viewers. There is an experimental `&retransmit` option that lets you push this concept even further, where you can broadcast chunked video from peer-to-peer-to-peer-and so on, without any additional transcoding.

Chunked mode is a bit similar to the previously released [`&webp`](../advanced-settings/view-parameters/webp.md) broadcast mode, which streamed a series of images as a custom-made video protocol over the WebRTC data-channels, but the [`&webp`](../advanced-settings/view-parameters/webp.md) mode had poor compression, low quality, and would drop frames if the connection couldn't keep up. This new chunked option though uses cutting edge features in modern browsers to allow for high bitrates and advanced video-encoder controls; it uses encoded video chunks rather than still image frames.

The downsides of the chunk-transfer mode is that if the connection stalls out long enough, the video will be forced to pause and buffer. It also has a buffer, which is currently around 1 second by default. The chunked-transfer mode might be suitable for doing remote recordings of interviews where the highest quality is desirable, but it may not be suitable for live and interactive chat if on a bad connection.

The default and normal WebRTC video and audio sending modes used by VDO.Ninja are largely handled by the browser, with few encoder and controls for apps like VDO.Ninja to control. The chunked mode offers lower-level access to the encoder on the other hand, but it's up to the app then to handle the sending, buffering, recovery, and all other aspects of streaming video. It's quite hard to do well, so `&chunked` mode isn't yet the best solution for all users; the normal mode has broader support and is better tested by the global community.

#### Random notes

* The option to save the chunked stream as a viewer is to use `&chunked=2` on the sender side. Using just `&chunked` will just enable viewing, and not saving, of the video.
* `&chunked=2` and [`&maxvideobitrate`](../advanced-settings/video-bitrate-parameters/and-maxvideobitrate.md) will likely get changed up and moved to the viewer side eventually; currently doing this just for convenience of development/testing. Multiple viewers is not recommended. There seems to be an issue with audio clicking that I'm trying to solve currently.
* Using [`&buffer`](../advanced-settings/view-parameters/buffer.md) on the viewer side can vary the buffering amount, however setting it too low may cause the stream to fail if it faces a buffer underrun event. You can change the buffer dynamically by right-clicking a video as a viewer, and changing the buffer listed value there.

#### Info and issues about using the chunked transfer mode

* It does not work with Meshcast.
* Chunked transfer is supported in recent Chromium-based browsers, including OBS v27.2 and newer.
* Audio and video sync isn't always guaranteed.
* If screen sharing your entire display, and assuming that display supports higher than 60-fps, chunked mode will support the higher frame rate. I've tested 120-fps on my gaming monitor, using chunked mode while screen sharing the entire display. Adding [`&fps=120`](../advanced-settings/video-parameters/and-fps.md) to the sender's URL will configure the chunked mode to both capture and publish at 120-fps. It will error out if not supported however.
* While support for alpha-channels (RGBA/transparencies) has been added to chunked mode, it's up to the browser to provide video encoders that support alpha-channels. VDO.Ninja as of v24 will look for any compatible alpha-enabled encoders when `&alpha` along with the `&chunked` parameter, but fall back to the normal RGB mode if none are found.

## Related

{% content-ref url="../advanced-settings/settings-parameters/and-nochunked.md" %}
[and-nochunked.md](../advanced-settings/settings-parameters/and-nochunked.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/settings-parameters/and-retransmit.md" %}
[and-retransmit.md](../advanced-settings/settings-parameters/and-retransmit.md)
{% endcontent-ref %}




---
description: OpenH264 software encoding will be used
---

# \&h264profile

Viewer-Side Option! ([`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md), [`&room`](../general-settings/room.md))

## Options

Example: `&h264profile=42e01f`

| Value                                        | Description                                                                                                                                    |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| (no value given)                             | disables hardware h264 encoding -> OpenH264 software encoding will be used, if H264 is used. This is the same as setting the value to `42e01f` |
| `42e01f`                                     | advanced users can also pass a 6-character h264 profile ID to the parameter to get used instead. This one triggers OpenH264.                   |
| `42001f` \| `420029` \| `42a01e` \| `42a014` | just some examples of other h264 profiles you can try; these often will use the external hardware encoder on Windows systems.                  |
| `0` \| `false` \| `off` \| `default`         | has the h264 profile be left as the default browser default when the sender is an android                                                      |

## Details

`&h264profile` if added to the viewer-side will tweak the h264 profile type.

Open264 software encoding can actually use less CPU than the Windows-selected hardware encoder, and in some cases will suffer from less video glitching. For this reason, it's the default profile ID that gets used when `&h264profile` is added without a value.

Without using `&h264profile`, it's up to the system to decide what profile is used, and whether hardware encoding or software encoding is used. There is no way to force hardware to be used at this time, but you can force software, which may actually use less CPU and will avoid video glitching that hardware encoders sometime have.

Hardware encoders can sometimes cause the video to puke, turn all green, pink, or grey, especially at lower resolutions. It really depends on the hardware and driver being used by the sender, so if you really want to use H264, but it's glitching, adding `&h264profile` and enabling software-encoding can help there.

Advanced users can also pass a 6-character h264 profile ID to the parameter to get used instead. This flag will not force H264 to be used, but rather configures it in case h264 gets used. You can still use [`&codec`](../advanced-settings/view-parameters/codec.md) to set the codec to h264.

Example: `https://vdo.ninja/?view=xxx&h264profile=42e01f&codec=h264&stats`

<div align="left">

</div>

## Related

{% content-ref url="../advanced-settings/view-parameters/codec.md" %}
[codec.md](../advanced-settings/view-parameters/codec.md)
{% endcontent-ref %}




---
description: Combines a bunch of flags together; no video, no audio, GUI, etc.
---

# \&datamode

General Option! ([`&push`](../source-settings/push.md), [`&room`](../general-settings/room.md), [`&view`](../advanced-settings/view-parameters/view.md), [`&scene`](../advanced-settings/view-parameters/scene.md))

## Aliases

* `&dataonly`

## Details

The `&datamode` parameter just combines a bunch of flags together; no video, no audio, GUI, etc. It just auto connects with data-channels only open. Useful for MIDI or sensor-data modes or the like, as it lets you connect without user-interaction or pop-up requests.

## Sample code and example

If looking to use VDO.Ninja for sending data via p2p in your application, there are some projects already doing so, but also provided is a code snippet.

#### Minimal code example

While this code snippet doesn't actually use the `&datamode` parameter, as it was created before it, it achieves the same result using [`&videodevice=0`](../source-settings/videodevice.md) and such.

[https://gist.github.com/steveseguin/15bba03d1993c88d0bd849f7749ea625](https://gist.github.com/steveseguin/15bba03d1993c88d0bd849f7749ea625)

#### Another p2p data sending example - remotely control OBS Studio

[https://github.com/steveseguin/sample-p2p-tunnel](https://github.com/steveseguin/sample-p2p-tunnel)

A remote control page, that works anywhere online, and another page to forward those remote commands into local websocket commands for OBS Studio's websocket API. You can use this to also return the video output of OBS, if you wanted to add that integration as well; the code is free to use as you see fit.

#### Social Stream Ninja

[Social Stream](../steves-helper-apps/social-stream-ninja/) is used by thousands of users as a free way to send text messages and image data using VDO.Ninja's p2p data function. The p2p nature of this setup keeps latency and internet usage low when the two connections are on the same LAN, but also provides a NAT firewall bypass for sending messages across the Internet, without the need for websocket servers.

{% embed url="https://socialstream.ninja" %}

### Update in [v23](../releases/v23.md)

The [`&datamode`](and-datamode.md) option was tweaked to work a bit better now when using it to both connect via push and view modes. Data-only mode is an advanced option; it's a bit like doing `&audiodevice=0&videodevice=0&webcam&autostart&hidemenu`, but a bit cleaner and disables a few other common functions that might be considered bloat. Useful perhaps if you want to use only the data-channels of VDO.Ninja, for remote control only operations or sending files.

## Related

{% content-ref url="../midi-settings/midi.md" %}
[midi.md](../midi-settings/midi.md)
{% endcontent-ref %}




---
description: >-
  Defines how webcam and screenshare of a guest in a room interacts which each
  other
---

# \&screensharetype

Sender-Side Option! ([`&push`](../source-settings/push.md))

## Aliases

* `&sstype`

## Options

Example: `&screensharetype=3`

<table><thead><tr><th width="196">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>1</code></td><td>Replaces the webcam screen with the screen share</td></tr><tr><td><code>2</code></td><td>Creates a totally new connection for the screen share</td></tr><tr><td><code>3</code> (default)</td><td>Reuses the existing connection, adding a second video track</td></tr></tbody></table>

## Details

This parameter can be used to specify which type of screen sharing logic is used.

* `screensharetype=1` replaces the webcam screen with the screen share
* `screensharetype=2` creates a totally new connection for the screen share
* `screensharetype=3` reuses the existing connection, adding a second video track; also doesn't show the local screen share window

The default `&screensharetype` for screen-sharing is `3` when in a room.

As a viewer or scene link, to specify only loading the `&screensharetype=3` screen share, you can now use `&view=xxxx:s`, where `:s` is appended to the end of the stream ID. This tells the system to ignore the webcam/mic feed, and just send over the screen share. You can do `&view=xxxx,xxxx:s` to target both webcam and screen share though. I may change this syntax over time, but for now it works. The solo-links in the director's room has this `:s` applied already where needed.

{% hint style="info" %}
If using `&screensharetype=3` the parameter [`&screenshareid`](../source-settings/screenshareid.md) doesn't do anything.
{% endhint %}

{% hint style="warning" %}
The type-3 screen share is still not fully cooked for use in scenes, etc, and it won't yet \
work with [`&meshcast`](and-meshcast.md), [`&novideo`](../advanced-settings/video-parameters/and-novideo.md) or [`&noaudio`](../advanced-settings/view-parameters/noaudio.md).
{% endhint %}

## Related

{% content-ref url="../source-settings/screenshareid.md" %}
[screenshareid.md](../source-settings/screenshareid.md)
{% endcontent-ref %}

{% content-ref url="../advanced-settings/screen-share-parameters/and-smallshare.md" %}
[and-smallshare.md](../advanced-settings/screen-share-parameters/and-smallshare.md)
{% endcontent-ref %}

{% content-ref url="../source-settings/screenshare.md" %}
[screenshare.md](../source-settings/screenshare.md)
{% endcontent-ref %}




---
description: Orders guest's by their stream ID in the director's room
---

# \&orderby

Director Option! ([`&director`](../viewers-settings/director.md))

## Options

Example: `&orderby=label`

<table><thead><tr><th width="177">Value</th><th>Description</th></tr></thead><tbody><tr><td><code>label</code></td><td>will sort based on the display name (<a href="../general-settings/label.md"><code>&#x26;label</code></a>) of each video, if the label is set, instead of by stream ID.</td></tr><tr><td>(no value given)</td><td>orders guest's by their stream ID in the director's room</td></tr></tbody></table>

## Details

`&orderby` is a director's URL parameter. While the default ordering of guests in the director's room is by time of joining, if you use `&orderby` it instead orders by guest's stream ID. I'll be adding different ordering options later, but for now it's just by stream ID (case ignored; a to z, etc).

You can still manual reorder a guest, but when you shift someone up or down the list, they will be ignored by the ordering from there on. This order is different than the mix-order; this order is largely cosmetic and only impacts the MIDI mix order IDs really.

#### Update in [v23.md](../releases/v23.md "mention")

I updated `&orderby` to work with non-director view links, such as with scenes or guests.

Previously `&orderby` only worked with the director's view to sort the positioning of control boxes, based on the _stream ID_, but now it can apply to the auto-mixer.

The _mix order_, or [`&order=N`](../source-settings/order.md), of each guest takes priority over the name when sorting. By default all guests have a mix order of 0, mind you. You can change it dynamically as a guest, via the mix-order option in each guest's control box, or pre-assign it via URL with `&order=N` on the guest invite.

#### Sort by label

I also added `&orderby=label` as an option, which will sort based on the display name ([`&label`](../general-settings/label.md)) of each video, if the label is set, instead of by stream ID.

This option doesn't apply to the director's view at the moment, but it does work when used with respect to the auto-mixer (guests/scenes).

The label sort ignores letter casing, while the default stream ID includes letter casing in the sorting logic.

## Related

{% content-ref url="../source-settings/order.md" %}
[order.md](../source-settings/order.md)
{% endcontent-ref %}




---
description: General information about group rooms and how they work.
---

# Common questions re: Rooms

For a more in-depth guide on how to setup a group chat room, [please see this getting started guide.](https://docs.vdo.ninja/getting-started/rooms)\
\
The group chat feature in VDO.Ninja creates a virtual room where multiple devices can connect to share audio and video. It offers echo-cancellation and text-chat support as well, along with an easy to use screen share function.

Each room has a main director, whom can manage the guests from the control room, easily accessing individual sources for integration into OBS.  Only one main director can exist in a room at a time, however that main director can invite co-directors.

* Guests have their own link to join the chat room. They will be able to see all of those in the chatroom, including themselves. Settings to restrict what sources each group member can see or hear are also available.&#x20;
* Guests by default will be assigned a random stream ID each time they re-join a room with the invite link provided to them. This stream ID can be made permanent though if the invite link given to the guest specifies the stream ID in the URL using the `&push` parameter.  For more information on this, see [https://docs.vdo.ninja/guides/how-to-get-permanent-links](https://docs.vdo.ninja/guides/how-to-get-permanent-links).\

* The 'director' will be able to view the chat room, without joining it themselves, and they will have controls provided that will let them modify aspects of how the room shows up in their OBS.&#x20;
  * For example, directors will be able to mute certain people so they can't be heard or seen in OBS.
* The director will be provided isolated direct links to each of those video streams in the group room, allowing for fine-grain mixing control in OBS. These are called "solo links" in the director's room.\

* Text-chat is available to those in the group chat. You can upload files to other guests in the room, pop out the chat, and see certain events listed in the chat feed. The chat is peer to peer based, so it does not go through a server and is end-to-end encrypted by default.\

* Passwords are available to keep rooms secure, but are optional. Passwords are not stored on any server; they are used for client-side end-to-end encryption. Setting a password is strongly advised, as it both encrypts the peer to peer initial connection handshake, but it also scrambles the room name and stream IDs.
* Stream IDs are not unique to a room, but are global.  Using a password however "salts" the stream ID, and also the room name, so if you are intending to use a basic stream ID, such as "guest\_1", then adding a password to your room would make it highly unlikely that you'd ever have a collision with someone else using the same stream ID value.\

* Guests present in the Group Chat room will see and hear all other present guests video/audio streams; by default anyways. There are ways to change this, both via invite-link options, but also via having a guest be assigned to a group; an option the director has.\

* The video quality of those in a group room will appear low to guests, but this is to ensure more bandwidth and CPU resources are made available for the OBS's access to the stream. You can increase the quality, but with potentially detrimental results.
* Group rooms are not restricted in size, although more than 10 guests can start to be challenging.
  * For larger rooms, using `&broadcast` mode or `&meshcast` may be needed to avoid overloading the CPU or network of you and/or your guests
* Group rooms cease to exist when everyone leaves a room. Settings for a room are stored client-side, in your URL parameters or browser cache/storage, so when everyone closes their browser or leaves the room, the room ceases to exist.

Using OBS VirtualCam (or the Mac equivalent), you can let your guests view the OBS live stream itself with sub-100ms of latency. In this case, each guest only needs to view one video stream, the main mixed OBS stream, freeing up group resources to allow for even larger group rooms. This is usually called [`&broadcast`](../advanced-settings/view-parameters/broadcast.md) mode.

{% embed url="https://www.youtube.com/watch?v=m1cIT1kdlEo" %}




# Fail safes and Backups

Low-latency Live streaming is inherently challenging, and as more remote streams that are added to a live production, the more likely a problem will occur.

[VDO.Ninja](https://vdo.ninja/) acknowledges these risks and attempts to mitigate them when possible.

## Back-up site

If the main website and service goes down, [https://backup.vdo.ninja](https://backup.vdo.ninja) is a backup deployment of VDO.Ninja. It is independent of the main service, so if the main site is down for whatever reason, the backup site should still be up. \
\
Both the backup and main site share the same DNS provider; DNS server 1.1.1.1 should be used if there are DNS issues.

There's also the Github version of the code hosted at [https://steveseguin.github.io/vdo.ninja/](https://steveseguin.github.io/vdo.ninja/), if just the website goes down.&#x20;

## Fixed versions

VDO.Ninja does update the application code every few weeks, and with new code comes potentially new bugs and/or feature changes.\
\
To mitigate any surprises, past versions of the app remain hosted long after a new release. For example, version 18 can be found at [https://vdo.ninja/v18/](https://vdo.ninja/v18/) with **the current previous version being listed on the main site**. Most new releases become bug-free within a few days of their release, thanks to prompt user bug reports.

## Redundant relay servers

There are multiple TURN servers, which help support guests that are unable to connect directly via P2P. These are hosted in around the globe. They definitely are not cheap to host, yet are essential for a simplified and reliable user experience.

## Self-hosting

The option to self-host VDO.Ninja is available, to different degrees of isolation. Refer to the[ GitHub repo](https://github.com/steveseguin/vdo.ninja) for [installation instructions](https://github.com/steveseguin/vdo.ninja/blob/master/install.md). \
\
Hosting just the website code is the easiest option, providing further customization support, but hosting also the STUN, TURN, and handshake server will provide total hosting independence.

### Third-party managed hosting

While self-hosting on your own servers works, you can also host VDO.Ninja on unaffliated third party services.&#x20;

* The website code for VDO.Ninja can be forked and hosted by GitHub Pages for free or any website provider really.
* There are companies that offer hosted STUN and TURN services for a fee.
* VDO.Ninja's handshake server is of an agnostic design and can be replaced with a third-party websocket provider, such as piesocket.com

## Debugging tools

Speed-tests and Debug tools are provided, either via the `Left-Click + CTRL` (command) options or at [https://vdo.ninja/speedtest](https://vdo.ninja/speedtest) . These can be useful to diagnose problems, such as whether Packet Loss is a culprit to low-quality video, and remotely determining who is at fault.

## Active free support

There is active support on the [DISCORD channel](https://discord.gg/sk4caKg), Reddit, and limited support via email: steve@seguin.email If paid support is requested, there are capable users in the community who can be recommended.

## Listed known issues

On the main website, currently known issues will be listed, often with links to solutions.

As a side note, most issues are the fault of guests being connected over Wi-Fi, instead of being connected via wired Ethernet. Wi-Fi has horrible packet loss issues, and Packet Loss can kill the quality of live streams. Considering switching to Ethernet if possible, and if using OBS, perhaps consider VP9 or H264 as a codec; those codecs have less packet loss issues.

**Always prep and practice ahead of live-streams**, and make sure to have practiced game-plans and backup solutions for every possible outcome. It will reduce stress and ensure a calm and collected response to issues that inevitably happen. Low-latency live streaming can be challenging, even with the best of tools.




# Feature Requests

Please feel free to make feature requests or submit bug reports; feedback of any kind is greatly appreciated. Development is largely based on user-feedback.

The best way to track submissions is to make them feature requests and bug reports directly to the GitHub repository here: [https://github.com/steveseguin/obsninja/issues](https://github.com/steveseguin/obsninja/issues)

You can also submit bug reports or feature requests elsewhere, though they are more likely to be lost or missed:

**Developer/Maintainer**: [steve@seguin.email](mailto:steve@seguin.email)\
**Discord**: [https://discord.vdo.ninja](https://discord.vdo.ninja)\
**Reddit**: [https://www.reddit.com/r/VDONinja/](https://www.reddit.com/r/VDONinja/)




# Logos and media assets

For a collection of [VDO.Ninja](https://vdo.ninja/) media assets, there is a Google Drive containing them below. \
\
You're welcome to use them for purposes of promoting or crediting VDO.Ninja. For other uses, please use common sense as to what might be appropriate or reach out and ask.\
\
[https://drive.google.com/drive/folders/1gYfxKEvFbKl\_UgHBT5PeGc5PJ-8yrGqW?usp=sharing](https://drive.google.com/drive/folders/1gYfxKEvFbKl\_UgHBT5PeGc5PJ-8yrGqW?usp=sharing)\
\
You can also find stickers and mugs (0% commission rate set) using the logos here: [https://www.redbubble.com/shop/ap/88897940](https://www.redbubble.com/shop/ap/88897940)

Media assets were created and contributed to VDO.Ninja by the community. Thank you.





# Project Contact Info

## Project Information and Support Links

**Web service URL**: [https://VDO.Ninja](https://obs.ninja)\
P**roject development URL**: [https://github.com/steveseguin/vdo.ninja](https://github.com/steveseguin/vdo.ninja)\
D**eveloper/maintainer**: [steve@seguin.email](mailto:steve@seguin.email)\
D**onations**: [via GitHub Sponsors](https://github.com/steveseguin/obsninja/wiki/Sponsor-%E2%9D%A4)

### Community Support

**Discord**: [https://discord.vdo.ninja](https://discord.vdo.ninja)\
**Reddit**: [https://reddit.com/r/vdoninja](https://reddit.com/r/vdoninja)




# Where can I report a bug?

It is most helpful to report bugs via the official [GitHub](https://github.com/steveseguin/obsninja). We also monitor the [Reddit](https://www.reddit.com/r/VDONinja/) and [Discord](https://discord.gg/qWDshMsTar) channels, though it is easier to miss reports that occur there.




---
description: '"VeeDeeOh"'
---

# What does VDO stand for?

VDO is the loose phonetic spelling of the world _video_.  "VeeDeeOh".  It is not an abbreviation.





# Where can I get support?

The preferred support mechanism is via [Reddit](https://www.reddit.com/r/VDONinja/) or [Discord](https://discord.gg/feenJm8HTa), which offer community-assisted support. Development issues, feature requests, and bugs are tracked on [GitHub](https://github.com/steveseguin/obsninja). For mission critical support issues, or business-related inquiries, you can contact Steve directly.




---
description: >-
  The use cases of VDO.Ninja are many; they go far beyond the original scope of
  the project
---

# Use cases

* To allow your mobile device to be used as a wireless remote camera.
* To pull in other people's video and audio for podcasting/broadcast (guest appearances).
* For sharing high-quality and low-latency audio and video across the Internet and within LANs.
* Bring a friend's remote game stream into your OBS and do side-by-side gaming together.
* For VR chat applications.
* For high-quality audio streaming, including remote DJing.
* Wirelessly stream video from any pro camera using just a $10 Raspberry Pi and HDMI adapter.
* For sending any streaming-data peer-to-peer over the Internet in a few lines of code, including JSON.
* To allow you to publish to YouTube with your smartphone even though you don't yet have enough followers to broadcast to YouTube with the YT mobile yet.
* To watch movies with friends, via screen sharing, privately, and with low-enough latency to talk on the phone together while watching it.
* Use as a remote low-latency teleprompter feed.
* Recording remote or local video at high quality without needing any downloads.
* Remotely streaming MIDI device output, such as MIDI keyboards or production control boards.
* Controlling OBS remotely from any computer on the Internet using [VDO.Ninja](https://vdo.ninja/) as a p2p bridge.
* Recording remote participates during interviews directly to their own computer; perfect recordings.
* Applying green screens, digital face effects, and other advanced video filters to video streams.
* Real-time closed-captions and transcriptions.
* For whatever other reason you might come up with.




# Why use VDO.Ninja over other solutions?

In some cases, the functionality of [VDO.Ninja](https://vdo.ninja) may overlap with existing solutions. However, in its primary function as an ultra-low latency peer-to-peer video bridge to OBS, it has many benefits and advantages over other methods:

* **100% free.** There's **no downloads** required, **no personal data collected**, and **no sign-in** needed.
* Compatible with most modern browsers and mobile devices.
* **Free support** offered via email, Discord, Reddit and numerous written guides.
* **Video data is peer-to-peer**, so unlike Skype, your video data does not go thru the NSA's spying servers.
* **Video can be transferred over a LAN directly**, so if using your phone as a webcam, you can crank the bitrates up to 40-mbps if you want, and your bandwidth won't be affected.
* **Low latency**. I'm talking as low as 30-ms, and normally it never goes higher than 200-ms.
* **Adjustable resolutions and video bitrates** (1920x1080p60 @ 30-mbps -- or even custom resolutions). 4K @ 30fps is possible, but CPU intensive.
* **Control over audio denoise**, **echo-cancellation**, and **auto-gain** is available, along with custom audio bitrates, and **stereo-sound**. It is an exceptional tool for podcasters and live streaming DJs.
* You can **parameterize many aspects of VDO.Ninja** such as total bitrate usage, bitrate per viewer usage, auto-select a device, autostart a session, removing the preview window.
* The interface is **open-source**, so you can white-label, stylize, tweak, and deploy the website code however you want.
* **Reusable invite links**, meaning OBS Browser Sources don't need to be recreated or changed once created and shared.
* Playback of video has been tested to work on using Amazon's Firestick's with Silk browser, along with a Tesla's Model 3's infotainment display.
* **No plugins needed for OBS** -- just drag the selected link into OBS (v25 or newer on PC\*) and it auto generates the OBS Browser source with the correct resolution. (\*[macOS](https://github.com/steveseguin/obsninja/wiki/FAQ#MacOS) users need to update to OBS v26.1.2 to access support for VDO.Ninja natively.)
* **QR Code support for invite links**, which allows for easy ingestion of mobile devices without needing to use the keyboard.
* **Browser-based control of OBS scenes**.
* **No overlays or windows to crop** -- VDO.Ninja auto-fills the window and if there is a black border, it becomes a transparent layer.
* **Group rooms available** with a Director able to control participants, the options presented to them, and even an autojoin experience.
* **Group chat rooms** have an "auto-mix" mode, making for easy management of dynamic group chat sessions.
* Those in a **group-chat can also be split up into individual streams**, so the Director has control to treat them like different sources in OBS, switching and mixing as they want.
* **Free TURN servers** are hosted for VDO.Ninja users, which normally are quite costly, but are kindly subsidized by community sponsors and by Steve, the developer of the application. [Sponsor ❤](getting-started/sponsor.md)&#x20;
* **Tally-light** support is offered when VDO.Ninja is used in conjunction with OBS.
* Group rooms and streams can be **password protected** and given extra security.
* The group-room director has a **"push to talk"** capability, along with text-chat being available.
* Support for **ISO feed recording** via the Director's Control Room.
* With little dependence on video servers, at peak usage hours video quality does not suffer.
* VDO.Ninja is a **project of passion**, **built by creators for creators**, and we like to think it shows.
