VDO.Ninja Developer API Sandbox

Your API Key: Loading...

Connecting...

Your Ninja Link: Loading...

You can append VDO.Ninja parameters to this link, treating it like a normal VDO.Ninja link.

Companion Module IFrame API Docs
WebSocket API
HTTP API
Server-Sent Events
HTTP POST
Camera Controls
MIDI Integration
Guest Controls
API Reference
WebSocket API Request Builder
Common Controls (WebSocket)
Layout Controls (WebSocket)

WebSocket API Code Example

JavaScript
// Connect to WebSocket API
const socket = new WebSocket("wss://api.vdo.ninja:443");

// Track connection state
socket.onopen = function() {
  console.log("Connected to VDO.Ninja API");
  // Join with your API ID
  socket.send(JSON.stringify({ "join": "YOUR_API_ID" }));
};

// Handle messages
socket.onmessage = function(event) {
  if (event.data) {
    const data = JSON.parse(event.data);
    console.log("Received:", data);
  }
};

// Reconnection logic (crucial for production)
socket.onclose = function() {
  console.log("Connection closed, attempting to reconnect...");
  setTimeout(() => {
    // Implement reconnection logic here
  }, 1000);
};

// Example commands
function sendCommand(action, value = null, target = null) {
  const msg = { action };
  if (value !== null) msg.value = value;
  if (target !== null) msg.target = target;
  
  if (socket.readyState === WebSocket.OPEN) {
    socket.send(JSON.stringify(msg));
  } else {
    console.error("Socket not connected");
  }
}

// Command examples:
// sendCommand("mic", "toggle");
// sendCommand("camera", false);
// sendCommand("soloVideo", "toggle");
// sendCommand("layout", 2);
// For directors - target a guest:
// sendCommand("mic", "toggle", "1"); // Target guest in slot 1
HTTP GET API Request Builder
https://api.vdo.ninja/YOUR_API_ID/action/target/value
Common Controls (HTTP)
Group Controls (HTTP)

HTTP API Code Example

JavaScript
// HTTP GET API Example
function sendHTTPRequest(apiID, action, target = "null", value = "null") {
  // Construct URL
  const url = `https://api.vdo.ninja/${apiID}/${action}/${target}/${value}`;
  
  // Send request
  fetch(url)
    .then(response => {
      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`);
      }
      return response.text();
    })
    .then(data => {
      // Handle response (could be text or JSON)
      try {
        const jsonData = JSON.parse(data);
        console.log("Response JSON:", jsonData);
      } catch (e) {
        console.log("Response text:", data);
      }
    })
    .catch(error => {
      console.error("Error:", error);
    });
}

// Usage examples:
// sendHTTPRequest("YOUR_API_ID", "mic", "null", "toggle");
// sendHTTPRequest("YOUR_API_ID", "camera", "null", "false");
// sendHTTPRequest("YOUR_API_ID", "joinGroup", "null", "1");

// For directors targeting a specific guest
// sendHTTPRequest("YOUR_API_ID", "mic", "1", "toggle"); // Target guest in slot 1
// sendHTTPRequest("YOUR_API_ID", "addScene", "2", "1"); // Add guest 2 to scene 1
Server-Sent Events (SSE) Listener

SSE provides a one-way communication channel to receive events from VDO.Ninja without sending requests.

Disconnected

SSE API Code Example

JavaScript
// Server-Sent Events (SSE) Example
function connectToSSE(apiID) {
  // Create EventSource connection
  const eventSource = new EventSource(`https://api.vdo.ninja/sse/${apiID}`);
  
  // Connection opened
  eventSource.onopen = function() {
    console.log("SSE connection established");
  };
  
  // Listen for messages
  eventSource.onmessage = function(event) {
    try {
      const data = JSON.parse(event.data);
      console.log("SSE event:", data);
      
      // Handle different types of events
      if (data.type === "state_update") {
        // Handle state updates
        updateUI(data.state);
      } else if (data.type === "guest_joined") {
        // Handle guest joining
        console.log(`Guest joined: ${data.guestID}`);
      }
      // Add more event handlers as needed
      
    } catch (e) {
      console.error("Error parsing SSE event:", e);
    }
  };
  
  // Handle errors
  eventSource.onerror = function(error) {
    console.error("SSE connection error:", error);
    
    // Close connection
    eventSource.close();
    
    // Implement reconnection logic
    setTimeout(() => {
      console.log("Attempting to reconnect SSE...");
      connectToSSE(apiID);
    }, 3000);
  };
  
  // Return EventSource instance (for later disconnection if needed)
  return eventSource;
}

// Usage:
// const sseConnection = connectToSSE("YOUR_API_ID");
// 
// // To disconnect later:
// // sseConnection.close();
HTTP POST API Request Builder

Although HTTP GET is the primary API method, POST can be useful for complex data or when query parameters need to be hidden.

HTTP POST API Code Example

JavaScript
// HTTP POST API Example
function sendPOSTRequest(apiID, data) {
  // Construct URL
  const url = `https://api.vdo.ninja/${apiID}`;
  
  // Configure request
  const options = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
  };
  
  // Send request
  fetch(url, options)
    .then(response => {
      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`);
      }
      return response.json();
    })
    .then(data => {
      console.log("Response:", data);
    })
    .catch(error => {
      console.error("Error:", error);
    });
}

// Usage examples:
// sendPOSTRequest("YOUR_API_ID", {
//   action: "mic",
//   value: "toggle"
// });
//
// sendPOSTRequest("YOUR_API_ID", {
//   action: "layout",
//   value: [
//     {"x":0,"y":0,"w":50,"h":100,"slot":0},
//     {"x":50,"y":0,"w":50,"h":100,"slot":1}
//   ]
// });
//
// For directors targeting a specific guest:
// sendPOSTRequest("YOUR_API_ID", {
//   action: "sendDirectorChat",
//   target: "1", 
//   value: "You're live in 5 seconds!"
// });
Camera Controls (PTZ)

Remote control compatible camera hardware using pan, tilt, zoom, focus, and exposure commands.

Zoom

Absolute Zoom:
0.5

Focus

Pan & Tilt

Exposure

Exposure Level:
0.5

PTZ Controls Code Example

JavaScript
// Camera Control (PTZ) Example
function sendCameraCommand(apiID, action, value, value2 = null, target = null) {
  // Using WebSocket (preferred for responsive camera control)
  if (socket && socket.readyState === WebSocket.OPEN) {
    const command = { action, value };
    if (value2 !== null) command.value2 = value2;
    if (target !== null) command.target = target;
    
    socket.send(JSON.stringify(command));
  } 
  // Using HTTP as fallback
  else {
    let url = `https://api.vdo.ninja/${apiID}/${action}`;
    
    if (target !== null) {
      url += `/${target}`;
    } else {
      url += `/null`;
    }
    
    url += `/${value}`;
    
    // value2 can't be directly used in the standard HTTP API, so it's ignored here
    
    fetch(url)
      .then(response => response.text())
      .then(data => console.log("Response:", data))
      .catch(error => console.error("Error:", error));
  }
}

// Usage examples:
// Relative adjustments
// sendCameraCommand("YOUR_API_ID", "zoom", 0.1);       // Zoom in
// sendCameraCommand("YOUR_API_ID", "zoom", -0.1);      // Zoom out
// sendCameraCommand("YOUR_API_ID", "focus", 0.1);      // Focus farther
// sendCameraCommand("YOUR_API_ID", "pan", -0.1);       // Pan left
// sendCameraCommand("YOUR_API_ID", "tilt", 0.1);       // Tilt up

// Absolute adjustment (for zoom)
// sendCameraCommand("YOUR_API_ID", "zoom", 0.75, "abs");  // Set zoom to 75%

// Targeting a specific guest's camera (for directors)
// sendCameraCommand("YOUR_API_ID", "zoom", 0.1, null, "2");  // Zoom guest 2's camera in
MIDI Integration

Control VDO.Ninja using MIDI controllers with various mapping options.

MIDI access not initialized
No MIDI message received

Default MIDI Mappings

VDO.Ninja supports several MIDI mapping schemes, which can be configured using the midiHotkeys parameter.

Standard Mapping (midiHotkeys=1)
  • G3: Toggle chat
  • A3: Toggle mic
  • B3: Toggle video
  • C4: Toggle screenshare
  • D4: Hangup
  • E4: Raise hand
  • F4: Toggle recording
  • G4: Director audio
  • A4: Director hangup
  • B4: Toggle speaker
Alternate Mapping (midiHotkeys=2)
  • G1: Toggle chat
  • A1: Toggle mic
  • B1: Toggle video
  • C2: Toggle screenshare
  • D2: Hangup
  • E2: Raise hand
  • F2: Toggle recording
  • G2: Director audio
  • A2: Director hangup
  • B2: Toggle speaker
CC-Based Controls (midiHotkeys=3)

Uses note C1 with different velocity values:

  • C1 + velocity 0: Toggle chat
  • C1 + velocity 1: Toggle mic
  • C1 + velocity 2: Toggle video
  • C1 + velocity 3: Toggle screenshare
  • C1 + velocity 4: Hangup
  • C1 + velocity 5: Raise hand
  • C1 + velocity 6: Toggle recording
  • C1 + velocity 7: Director audio
  • C1 + velocity 8: Director hangup
  • C1 + velocity 9: Toggle speaker
PTZ MIDI Controls

Use MIDI to control camera:

  • C5 + velocity (0-127): Zoom (absolute)
  • D5 + velocity (0-127): Focus
  • E5 + velocity (0-127): Pan
  • F5 + velocity (0-127): Tilt
  • G5 + velocity (0-127): Exposure

MIDI API Code Example

JavaScript
// MIDI Integration Example
function initializeMIDI() {
  // Check if Web MIDI API is supported
  if (!navigator.requestMIDIAccess) {
    console.error("Web MIDI API not supported in this browser");
    return Promise.reject("MIDI not supported");
  }
  
  // Request MIDI access
  return navigator.requestMIDIAccess({ sysex: false })
    .then(midiAccess => {
      console.log("MIDI Access granted");
      
      // Get MIDI inputs
      const inputs = midiAccess.inputs.values();
      const devices = [];
      
      // Setup devices
      for (let input = inputs.next(); input && !input.done; input = inputs.next()) {
        devices.push(input.value);
        setupMIDIDevice(input.value);
      }
      
      // Listen for device connection/disconnection
      midiAccess.onstatechange = function(e) {
        console.log("MIDI state change:", e.port.name, e.port.state);
      };
      
      return { midiAccess, devices };
    })
    .catch(error => {
      console.error("Failed to get MIDI access:", error);
      throw error;
    });
}

function setupMIDIDevice(inputDevice) {
  // Set up MIDI message handler
  inputDevice.onmidimessage = function(message) {
    // Extract MIDI data
    const command = message.data[0];
    const note = message.data[1];
    const velocity = message.data[2];
    
    console.log(`MIDI message - Command: ${command}, Note: ${note}, Velocity: ${velocity}`);
    
    // Handle Note On messages (144 = Note On, channel 1)
    if (command === 144 && velocity > 0) {
      handleNoteOn(note, velocity);
    }
    // Handle Note Off messages (128 = Note Off, channel 1)
    else if (command === 128 || (command === 144 && velocity === 0)) {
      handleNoteOff(note);
    }
    // Handle Control Change messages (176 = CC, channel 1)
    else if (command === 176) {
      handleControlChange(note, velocity);
    }
  };
}

function handleNoteOn(note, velocity) {
  // Convert MIDI note number to note name (e.g. 60 = C4)
  const noteName = getNoteNameFromNumber(note);
  
  // Example mapping for midiHotkeys=1
  switch (noteName) {
    case "G3":
      sendCommand("toggleChat");
      break;
    case "A3":
      sendCommand("mic", "toggle");
      break;
    case "B3":
      sendCommand("camera", "toggle");
      break;
    case "C4":
      sendCommand("togglescreenshare");
      break;
    case "D4":
      sendCommand("hangup");
      break;
    // Add more mappings as needed
  }
}

function handleNoteOff(note) {
  // Handle note off events if needed
}

function handleControlChange(cc, value) {
  // Map control change messages to actions
  switch (cc) {
    case 20: // Example CC for zoom
      const zoomValue = value / 127; // Normalize to 0-1 range
      sendCommand("zoom", zoomValue, "abs");
      break;
    case 21: // Example CC for focus
      const focusValue = (value - 64) / 64; // Normalize to -1 to 1 range
      sendCommand("focus", focusValue);
      break;
    // Add more CC mappings as needed
  }
}

// Helper function to convert MIDI note number to note name
function getNoteNameFromNumber(noteNumber) {
  const notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
  const octave = Math.floor(noteNumber / 12) - 1;
  const noteName = notes[noteNumber % 12];
  return noteName + octave;
}

// Usage:
// initializeMIDI()
//   .then(midi => console.log("MIDI ready with devices:", midi.devices))
//   .catch(error => console.error("MIDI setup failed:", error));
Guest Controls (Director Mode)

These controls allow directors to manage remote guests via the API.

Guest Mic Volume:
100

Guest Control Code Example

JavaScript
// Guest Control Example (Director Mode)
function controlGuest(apiID, target, action, value = null, method = "websocket") {
  if (method === "websocket") {
    // WebSocket method
    if (socket && socket.readyState === WebSocket.OPEN) {
      const msg = {
        target: target,
        action: action
      };
      
      if (value !== null) {
        msg.value = value;
      }
      
      socket.send(JSON.stringify(msg));
      console.log("Sent guest command via WebSocket:", msg);
    } else {
      console.error("WebSocket not connected");
    }
  } else if (method === "http") {
    // HTTP method
    const targetStr = target || "null";
    const valueStr = value !== null ? value : "null";
    const url = `https://api.vdo.ninja/${apiID}/${action}/${targetStr}/${valueStr}`;
    
    fetch(url)
      .then(response => response.text())
      .then(data => console.log("Guest command response:", data))
      .catch(error => console.error("Error sending guest command:", error));
  }
}

// Usage examples:
// controlGuest("YOUR_API_ID", "1", "mic", "toggle");      // Toggle mic for guest 1
// controlGuest("YOUR_API_ID", "2", "camera", false);      // Turn off camera for guest 2
// controlGuest("YOUR_API_ID", "3", "addScene", 1);        // Add guest 3 to scene 1
// controlGuest("YOUR_API_ID", "1", "sendDirectorChat", "You're live in 10 seconds");
// controlGuest("YOUR_API_ID", "2", "volume", 85);         // Set guest 2 volume to 85%
// controlGuest("YOUR_API_ID", "4", "forward", "room123"); // Transfer guest 4 to room123
VDO.Ninja API Reference

Complete reference for all supported API commands, parameters, and response formats.

API Overview

The VDO.Ninja API supports multiple communication methods:

  • WebSocket API: Real-time bidirectional communication (preferred for most uses)
  • HTTP GET API: Simple REST-style requests, compatible with hotkey systems
  • HTTP POST API: For complex data structures like layout objects
  • Server-Sent Events (SSE): One-way communication channel for receiving updates
  • MIDI Integration: Control via MIDI devices using various mapping schemes

For integrations with BitFocus Companion, check out the official Companion module.

For custom embeds, refer to the IFrame API Documentation.

Command Reference

The following tables list all available commands, their parameters, and what they do.

Self Controls

Action Target Value Details
speaker null true/false/toggle Control local speaker (audio playback)
mic null true/false/toggle Control local microphone
camera null true/false/toggle Control local camera (same as video)
video null true/false/toggle Control local camera (alternate command)
volume null true/false/0-100 Control playback volume of all audio tracks (true=100%, false=0%)
record null true/false Start/stop recording the local video stream
bitrate null true/false/integer Control video bitrate (true=reset, false=pause, integer=kbps)
panning null true/false/0-180 Control stereo panning (90=center)
reload null null Reload the current page
hangup null null Disconnect current session
togglehand null null Toggle raised hand status
togglescreenshare null null Toggle screen sharing
forceKeyframe null null Force keyframe ("rainbow puke fix")
sendChat null string Send chat message to all connected users
getDetails null null Get detailed state information
soloVideo null true/false/toggle Highlight video for all guests (director only)

Layout Controls

Action Value Details
layout integer/object/array Switch to layout by index (0=auto-mix, 1-8=custom layouts) or set custom layout with object

Group Controls

Action Value Details
group 1-8 Toggle in/out of specified group
joinGroup 1-8 Join specified group
leaveGroup 1-8 Leave specified group
viewGroup 1-8 Toggle preview of specified group
joinViewGroup 1-8 Preview specified group
leaveViewGroup 1-8 Stop previewing specified group

Camera Control (PTZ)

Action Value Value2 Details
zoom decimal value abs/true (optional) Adjust zoom (positive=in, negative=out, or absolute with Value2)
focus decimal value n/a Adjust focus (positive=far, negative=near)
pan decimal value n/a Adjust pan (positive=right, negative=left)
tilt decimal value n/a Adjust tilt (positive=up, negative=down)
exposure 0-1 n/a Set exposure level (0=dark, 1=bright)

Guest Controls (Director Mode)

Action Target Value Details
forward guest slot/ID room name Transfer guest to specified room
addScene guest slot/ID 0-8 or scene name Toggle guest in/out of specified scene
muteScene guest slot/ID scene (optional) Toggle guest's mic in scenes
mic guest slot/ID true/false/toggle Control guest's microphone
camera guest slot/ID true/false/toggle Control guest's camera
video guest slot/ID true/false/toggle Control guest's camera (alternate command)
hangup guest slot/ID null Disconnect guest
soloChat guest slot/ID null Toggle one-way solo chat with guest
soloChatBidirectional guest slot/ID null Toggle two-way solo chat with guest
speaker guest slot/ID null Toggle guest's speaker
display guest slot/ID null Toggle guest's display (ability to see video)
group guest slot/ID 1-8 Toggle guest in/out of specified group
forceKeyframe guest slot/ID null Trigger keyframe for guest (fix rainbow artifacts)
soloVideo guest slot/ID null Toggle highlighting guest's video
sendChat guest slot/ID message text Send private chat message to guest
sendDirectorChat guest slot/ID message text Send message and overlay it on guest's screen
volume guest slot/ID 0-200 Set guest's microphone volume
startRoomTimer guest slot/ID seconds Start countdown timer for guest
pauseRoomTimer guest slot/ID null Pause timer for guest
stopRoomTimer guest slot/ID null Stop timer for guest
mixorder guest slot/ID -1 or 1 Adjust guest's position in the mixer (-1=up, 1=down)

Response Formats

Responses from the API depend on the method used:

  • HTTP GET: Responses include simple text values like true, false, null, fail, or a specific value. For object responses like getDetails, you'll receive JSON.
  • WebSocket: Responses are JSON objects containing the result along with the original request parameters and any custom data fields you included.
  • HTTP POST: Responses are JSON objects with similar structure to WebSocket responses.
  • SSE: Events are JSON objects containing state updates and other notifications.

Custom Layout Format

When using the layout command, you can provide a custom layout object or array:

Layout Object Example
// Single layout example
{
  "action": "layout",
  "value": [
    {"x": 0, "y": 0, "w": 50, "h": 100, "slot": 0},
    {"x": 50, "y": 0, "w": 50, "h": 100, "slot": 1}
  ]
}

// Using URL parameter to define multiple layouts
// ?layouts=[[{"x":0,"y":0,"w":100,"h":100,"slot":0}],[{"x":0,"y":0,"w":50,"h":100,"slot":0},{"x":50,"y":0,"w":50,"h":100,"slot":1}]]

// Layout properties:
// x, y: Position (percentage of container)
// w, h: Width and height (percentage of container)
// slot: Guest slot number (0-indexed)
// c: Crop to fit (true/false)
// z: Z-index (layer)

// To switch layouts:
// {"action": "layout", "value": 0} // Auto-mix
// {"action": "layout", "value": 1} // First custom layout
// {"action": "layout", "value": 2} // Second custom layout
API Request/Response Logger