Open app

Stream video end-to-end

This guide covers sending live video from a device via the Python SDK and consuming it through the WebSocket API — device to browser.

Step 1 — Send frames from the device

Install the video extras (OpenCV headless + Pillow + NumPy):

pip install "plexus-python[video]"

Frame by frame

Use send_video_frame() when you need frame-level control — preprocessing, annotation, or custom capture logic:

import cv2
from plexus import Plexus

px = Plexus(api_key="YOUR_API_KEY", source_id="robot-01")

cap = cv2.VideoCapture(0)
while True:
    ret, frame = cap.read()
    if ret:
        px.send_video_frame(frame=frame, camera_id="front")

From a URL

Use stream_camera() to pull from any FFmpeg-supported source — an RTSP feed, HLS stream, or a video file path. Requires FFmpeg on $PATH:

stop = px.stream_camera(url="rtsp://192.168.1.10/stream", camera_id="front")

# ... do other work ...

stop.set()  # stop streaming

send_video_frame() JPEG-encodes ndarrays at quality=85. stream_camera() frames are encoded by FFmpeg and only re-encoded (at that quality) if a frame exceeds ~750 KB; the gateway hard limit is 1 MB.

Step 2 — Open the video stream

Connect to the video WebSocket, send an auth frame, then receive frames:

const ws = new WebSocket(
  "wss://api.plexus.company/v1/sources/robot-01/video/stream?camera_id=front"
);

ws.onopen = () => {
  ws.send(JSON.stringify({ type: "auth", api_key: "plx_..." }));
};

ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);

  if (msg.type === "init") {
    // lists which devices (source IDs) are currently online — camera
    // availability is learned from arriving video_frames
    console.log(msg.online_sources);
  }

  if (msg.type === "video_frame") {
    // msg.frame   — base64 JPEG
    // msg.camera_id, msg.width, msg.height, msg.timestamp
  }
};

The server sends one init frame immediately after auth, then video_frame frames as they arrive. The auth frame must be the first frame you send — the socket closes with 4001 if it doesn't arrive within 10 seconds.

Step 3 — Render in a browser

Draw each frame onto a <canvas>:

<canvas id="feed"></canvas>
const canvas = document.getElementById("feed");
const ctx = canvas.getContext("2d");

ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  if (msg.type === "video_frame") {
    const img = new Image();
    img.onload = () => {
      canvas.width = msg.width;
      canvas.height = msg.height;
      ctx.drawImage(img, 0, 0);
    };
    img.src = `data:image/jpeg;base64,${msg.frame}`;
  }
};

Notes

  • Live relay only — no history, no replay. Frames are dropped silently if the consumer can't keep up.
  • Multiple cameras — repeat the param: ?camera_id=front&camera_id=rear.
  • Timeout — add ?timeout=60 to have the server close after 60 s (code 4008). Reconnect to continue.

See Live streams for the full frame reference and close codes.