A native Elgato Stream Deck plugin for controlling VDO.Ninja pages through the existing VDO.Ninja &api remote-control system.
The goal is simple: open a VDO.Ninja director, guest, mixer, or camera page with a private API key, then use Stream Deck keys and dials for production controls such as mic/camera toggles, guest targeting, scene membership, mixer layouts, slots, PTZ, volume, bitrate, and custom API commands.
Status: beta/development. The plugin is usable for testing, but it has not been marketplace-released yet.
New to Stream Deck or VDO.Ninja? Start with the plain-language setup guide.
The key layout is an illustrative production profile, but the key colours and badges are the ones the plugin actually renders: a green field with a check for on or ready, dark red with a cross for off or unavailable, grey for inactive, and amber for a custom command. The property-inspector image reflects the current interface; labels may vary with the selected action.

&api=YOUR_PRIVATE_KEY.getDetails, partial details updates, and guest list ordering.For a slower, screenshot-free walkthrough with troubleshooting, see Set Up VDO.Ninja on Stream Deck.
Connection Status onto any key.Generate secure key, enter your VDO.Ninja room name, then click Open VDO.Ninja.Test connection. A green status means it is ready.guest position means the G1, G2, and G3 order shown by the VDO.Ninja director; it is not a mixer destination slot.The setup panel collapses after configuration so each action’s settings stay easy to reach. VDO.Ninja requires no account. Treat the generated connection key like a password, and use a different key for every page you want to control separately.
| Action | Controls | Feedback |
|---|---|---|
| Connection Status | API key, API host, setup links, QR code, connection test | Connected/no-page/timeout/error state |
| Local Control | Mic, camera, speaker, record, screen share, hand, force keyframe, reload, hangup | On/off state where VDO.Ninja reports it |
| Select Guest | Fixed guest, next, previous, first held, clear selected guest | Selected target state/title |
| Guest Command | Guest mic, camera, speaker, display, volume, group, transfer, activate held guest, hangup, solo modes, chat overlays, refresh/recover/keyframe | Target-aware titles and known guest states |
| Guest Scene | Toggle or force guest into any scene ID/name | Scene membership feedback |
| Mixer Control | Layout selection, assign guest to mixer slot, unset slot, legacy-safe mute/unmute all guests, guarded transfer-all | Mixer key states, slot feedback, all-muted feedback |
| PTZ Key | Local zoom/pan/tilt/focus/exposure; guest zoom/pan/tilt/focus/autofocus | Target-aware PTZ titles |
| PTZ Dial | Stream Deck + relative PTZ control with inversion, acceleration, rate limiting, and press actions | Current control/status title |
| Value Dial | Local volume, panning, bitrate, buffer delay, guest volume | Clamped value feedback |
| Custom Command | Any VDO.Ninja { action, target, value, value2 } payload |
OK/alert result feedback |
The command registry was checked directly against the last pre-v30.1 source (v29.4) and the current v30.2 source. Existing API names and value semantics are not redefined.
Guest Scene uses the legacy addScene / addScene2–addScene8 paths. Named-scene force-on/off uses live scene state plus the old toggle command, so it does not require the newer value2 scene extension.Mute all guests fans out the long-standing targeted mic command and excludes directors and screen-share pseudo-guests; it does not require the newer muteAllGuests wrapper.Activate Guest is the one current-only control. It requires VDO.Ninja v30.2+ because older pages have no native &api queue-activation handler. An older page rejects it and the plugin shows an alert without changing any legacy behavior.Very old builds can only support commands that existed in those builds; the plugin does not emulate missing browser features or PTZ handlers.
Use a director URL with a private API key:
https://vdo.ninja/?director=ROOM&api=YOUR_PRIVATE_KEY
Then add Stream Deck actions for guest mic/camera control, scene toggles, transfer, and mixer actions.
For slot workflows, use the mixer app or enable slot mode:
https://vdo.ninja/mixer?director=ROOM&api=YOUR_PRIVATE_KEY
https://vdo.ninja/?director=ROOM&api=YOUR_PRIVATE_KEY&slotmode=1
layout=0 means auto layout. Mixer slot assignment uses user-facing destination slot numbers: 1 is mixer slot 1, and 0 unsets the guest’s slot assignment.
Local PTZ needs the controlled camera page opened with &ptz and the browser PTZ permission approved:
https://vdo.ninja/?push=CAMERA_ID&api=YOUR_PRIVATE_KEY&webcam&autostart&ptz
Guest PTZ is sent from a director or mixer page, but the guest publisher must be loaded with &ptz and grant browser camera-control permission.
&api=KEY value.cd plugin
npm install
npm run build
npx @elgato/cli@1.7.4 link ninja.vdo.streamdeck.sdPlugin
npx @elgato/cli@1.7.4 restart ninja.vdo.streamdeck
The generated plugin bundle lives at:
plugin/ninja.vdo.streamdeck.sdPlugin/
No physical Stream Deck is needed for the basic checks:
cd plugin
npm test
npm run check
npm run build
npx @elgato/cli@1.7.4 validate ninja.vdo.streamdeck.sdPlugin --no-update-check
npx @elgato/cli@1.7.4 pack ninja.vdo.streamdeck.sdPlugin --dry-run -f --no-update-check
pack refuses to run when a .streamDeckPlugin file from an earlier build is already there, so -f keeps the dry run repeatable.
Current automated coverage includes command payload generation, settings normalization, custom value parsing, session-state handling, selected guest targeting, manifest image wiring, and VDO API transport behavior.
Interactive testing still requires the Stream Deck desktop app with hardware or Stream Deck Mobile.
Every push to main runs the same checks on Node.js 20 and uploads an installable .streamDeckPlugin build. Tags beginning with v also publish that package to the matching GitHub release.
plugin/
manifest.json Stream Deck manifest
src/ TypeScript plugin source
ui/action-settings.html Property inspector UI
imgs/ Generated action, key, encoder, and marketplace icons
scripts/icon-set.mjs Icon palette and shape specs (the source of truth)
scripts/generate-icons.mjs Renders the specs to SVG and anti-aliased PNG
scripts/copy-assets.mjs Assembles the .sdPlugin bundle
docs/
README.md Index of the documentation set
assets/ README preview images
*.md Design notes, API maps, and implementation audits
Icons are generated, not hand-edited. Change scripts/icon-set.mjs and run npm run assets; a test fails the build if the manifest and the generated files fall out of sync.
value2, such as absolute PTZ or all-stream buffer updates, use the WebSocket payload path so secondary values are preserved.Documentation index — every guide, reference, and audit, grouped by what you need.
Most-used entry points: