Skip to main content
← Back to Quickstart Guides

Browser-Based Streaming

No downloads, instant streaming from any browser

20 minutes
Beginner to Advanced
Zero Install
6+
Streaming Modes
<1s
Stream Start
All
Major Browsers
E2E
Encrypted

Streaming Capabilities

Everything you can do with browser streaming

Webcam Streaming

Beginner

Stream your webcam with configurable resolution and audio

Screen Sharing

Beginner

Share your entire screen, window, or browser tab

Picture-in-Picture

Intermediate

Overlay webcam on screen share for presenter mode

Canvas Streaming

Advanced

Stream games, animations, or custom graphics

Virtual Backgrounds

Advanced

Replace or blur your background in real-time

Multi-Source

Advanced

Combine multiple video sources into one stream

Quick Start: Webcam Streaming

Stream your webcam in 5 lines of code

import { WaveClient } from '@wave/browser-sdk';

const wave = new WaveClient({
  apiKey: 'wave_pub_xxxxx' // Public key, safe for browser
});

// Request webcam access
const mediaStream = await navigator.mediaDevices.getUserMedia({
  video: { width: 1920, height: 1080, frameRate: 30 },
  audio: { echoCancellation: true, noiseSuppression: true }
});

// Create and start stream
const stream = await wave.streams.createFromMediaStream(mediaStream, {
  title: 'My Webcam Stream',
  protocol: 'webrtc',
  visibility: 'public' // or 'private', 'unlisted'
});

console.log('Streaming at:', stream.url);
console.log('Share this link with viewers!');

// Display preview locally
const video = document.getElementById('preview');
video.srcObject = mediaStream;
video.play();

Screen Sharing

Share your entire screen, a window, or a browser tab

// Share entire screen with system audio (Chrome only)
const mediaStream = await navigator.mediaDevices.getDisplayMedia({
  video: {
    displaySurface: 'monitor',  // Entire screen
    cursor: 'always',            // Show cursor
    frameRate: { ideal: 60 }     // High FPS for smooth motion
  },
  audio: {
    systemAudio: 'include'       // Capture system audio (Chrome)
  },
  selfBrowserSurface: 'exclude', // Don't show this browser
  surfaceSwitching: 'include'    // Allow switching during share
});

// Create stream
const stream = await wave.streams.createFromMediaStream(mediaStream, {
  title: 'Screen Share',
  protocol: 'webrtc'
});

// Handle user stopping share via browser UI
mediaStream.getVideoTracks()[0].onended = () => {
  console.log('User stopped sharing');
  wave.streams.stop(stream.id);
};

Picture-in-Picture Mode

Overlay your webcam on screen share for professional presentations

import { WaveClient, CompositeStream } from '@wave/browser-sdk';

const wave = new WaveClient({ apiKey: 'wave_pub_xxxxx' });

// Get both sources
const screenStream = await navigator.mediaDevices.getDisplayMedia({
  video: { displaySurface: 'monitor' },
  audio: { systemAudio: 'include' }
});

const webcamStream = await navigator.mediaDevices.getUserMedia({
  video: { width: 320, height: 240 },  // Smaller for overlay
  audio: true
});

// Composite them together
const composite = new CompositeStream({
  width: 1920,
  height: 1080,
  frameRate: 30
});

// Add screen as background
composite.addSource({
  stream: screenStream,
  layer: 0,
  position: { x: 0, y: 0 },
  size: { width: 1920, height: 1080 }
});

// Add webcam as overlay (bottom-right corner)
composite.addSource({
  stream: webcamStream,
  layer: 1,
  position: { x: 1580, y: 820 },  // Bottom-right
  size: { width: 320, height: 240 },
  borderRadius: 8,
  border: { width: 3, color: 'oklch(0.55 0.2 260)' } // Primary blue
});

// Mix audio from both
composite.setAudioMix({
  screen: 0.7,   // System audio at 70%
  webcam: 1.0    // Mic at 100%
});

// Create stream from composite
const stream = await wave.streams.createFromMediaStream(
  composite.getOutputStream(),
  { title: 'Presenter Mode' }
);

// Allow dragging the webcam overlay
composite.enableOverlayDrag(1);  // Enable drag for layer 1

Overlay Positions

  • • Bottom-right (default)
  • • Bottom-left
  • • Top-right
  • • Top-left
  • • Custom coordinates
  • • Draggable by user

Overlay Styles

  • • Rounded corners
  • • Colored border
  • • Drop shadow
  • • Opacity control
  • • Hide/show toggle
  • • Resize handles

Canvas Streaming (Games & Graphics)

Stream HTML5 games, WebGL content, or custom animations

// Stream a canvas element (games, animations, WebGL)
const canvas = document.getElementById('gameCanvas') as HTMLCanvasElement;

// Capture canvas at 60 FPS
const canvasStream = canvas.captureStream(60);

// Add audio if needed
const audioContext = new AudioContext();
const destination = audioContext.createMediaStreamDestination();
// ... connect your audio nodes to destination
canvasStream.addTrack(destination.stream.getAudioTracks()[0]);

// Create WAVE stream
const stream = await wave.streams.createFromMediaStream(canvasStream, {
  title: 'Game Stream',
  protocol: 'webrtc',
  metadata: {
    type: 'gaming',
    engine: 'three.js'
  }
});

// For WebGL with preserveDrawingBuffer
const gl = canvas.getContext('webgl', {
  preserveDrawingBuffer: true  // Required for canvas capture
});

// Performance optimization for high FPS
// Use requestVideoFrameCallback when available
if ('requestVideoFrameCallback' in HTMLVideoElement.prototype) {
  // More efficient frame timing
}

Virtual Backgrounds

Replace or blur your background using ML-powered segmentation

import { WaveClient, BackgroundProcessor } from '@wave/browser-sdk';

const wave = new WaveClient({ apiKey: 'wave_pub_xxxxx' });

// Get webcam
const webcamStream = await navigator.mediaDevices.getUserMedia({
  video: { width: 1920, height: 1080 }
});

// Initialize background processor (uses TensorFlow.js BodyPix model)
const bgProcessor = new BackgroundProcessor({
  modelUrl: 'https://cdn.wave.inc/models/bodypix',
  mode: 'replace'  // 'blur' | 'replace' | 'none'
});

await bgProcessor.initialize();

// Option 1: Blur background
bgProcessor.setMode('blur', { strength: 15 });

// Option 2: Replace with image
bgProcessor.setMode('replace', {
  imageUrl: 'https://example.com/office-background.jpg'
});

// Option 3: Replace with video
bgProcessor.setMode('replace', {
  videoUrl: 'https://example.com/animated-background.mp4'
});

// Process the stream
const processedStream = bgProcessor.process(webcamStream);

// Create WAVE stream with processed video
const stream = await wave.streams.createFromMediaStream(processedStream, {
  title: 'Stream with Virtual Background'
});

// Performance stats
bgProcessor.on('performance', (stats) => {
  console.log('Processing FPS:', stats.fps);
  console.log('Latency:', stats.latency + 'ms');
});

// Toggle background on/off
function toggleBackground() {
  const currentMode = bgProcessor.getMode();
  bgProcessor.setMode(currentMode === 'none' ? 'blur' : 'none');
}
Blur

Gaussian blur, adjustable strength 1-20

Image

Static image, auto-scaled to fit

Video

Looping video, synchronized playback

Browser Compatibility

Feature support across browsers and platforms

BrowserWebcamScreenSystem AudioPiPCanvasNotes
Chrome 90+Full support, recommended
Edge 90+Same as Chrome (Chromium)
Firefox 88+No system audio capture
Safari 15+Limited screen share options
Safari iOS 15+No screen share on iOS
Chrome AndroidScreen share requires Android 10+

Media Constraints Reference

Configure video and audio capture quality

Video Resolution

4K (3840x2160){ width: 3840, height: 2160, frameRate: 30 }
1080p (1920x1080){ width: 1920, height: 1080, frameRate: 30 }
720p (1280x720){ width: 1280, height: 720, frameRate: 30 }
480p (854x480){ width: 854, height: 480, frameRate: 30 }

Frame Rate

60 FPS (Gaming){ frameRate: { ideal: 60, max: 60 } }
30 FPS (Standard){ frameRate: { ideal: 30, max: 30 } }
24 FPS (Cinematic){ frameRate: { ideal: 24, max: 24 } }
15 FPS (Low bandwidth){ frameRate: { ideal: 15, max: 15 } }

Audio

Echo Cancellation{ echoCancellation: true }
Noise Suppression{ noiseSuppression: true }
Auto Gain Control{ autoGainControl: true }
High Quality{ sampleRate: 48000, channelCount: 2 }

Connection Quality Monitoring

Real-time stream health metrics

// Monitor connection quality in real-time
wave.on('connectionQuality', (quality) => {
  // Quality level
  console.log('Level:', quality.level);  // 'excellent' | 'good' | 'fair' | 'poor'

  // Metrics
  console.log('Bitrate:', quality.bitrate, 'kbps');
  console.log('Packet loss:', quality.packetLoss, '%');
  console.log('Round-trip time:', quality.rtt, 'ms');
  console.log('Jitter:', quality.jitter, 'ms');
  console.log('Frames dropped:', quality.framesDropped);

  // Auto-adjust quality based on connection
  if (quality.level === 'poor') {
    // Reduce resolution/bitrate
    wave.streams.setQuality('low');
  } else if (quality.level === 'excellent') {
    // Increase to max quality
    wave.streams.setQuality('high');
  }
});

// Get current stats
const stats = await wave.streams.getStats();
console.log('Current stats:', stats);
Excellent
>4000 kbps
Good
>2000 kbps
Fair
>1000 kbps
Poor
<1000 kbps

Troubleshooting Guide

Click any issue to see diagnostic commands

Permission Handling

Best practices for camera/microphone permissions

// Check permissions before requesting
async function checkPermissions() {
  const cameraPermission = await navigator.permissions.query({ name: 'camera' });
  const micPermission = await navigator.permissions.query({ name: 'microphone' });

  console.log('Camera:', cameraPermission.state);  // 'granted' | 'denied' | 'prompt'
  console.log('Mic:', micPermission.state);

  // Listen for permission changes
  cameraPermission.onchange = () => {
    console.log('Camera permission changed:', cameraPermission.state);
  };
}

// Handle permission errors gracefully
async function getMediaWithFallback() {
  try {
    // Try video + audio
    return await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
  } catch (error) {
    if (error.name === 'NotAllowedError') {
      // Permission denied - show UI to explain why needed
      showPermissionExplanation();
    } else if (error.name === 'NotFoundError') {
      // No camera/mic found - try audio only
      try {
        return await navigator.mediaDevices.getUserMedia({ video: false, audio: true });
      } catch (audioError) {
        throw new Error('No media devices available');
      }
    } else if (error.name === 'NotReadableError') {
      // Hardware error or in use
      throw new Error('Camera/microphone is in use by another application');
    }
    throw error;
  }
}

// List available devices
async function getDevices() {
  const devices = await navigator.mediaDevices.enumerateDevices();

  const cameras = devices.filter(d => d.kind === 'videoinput');
  const mics = devices.filter(d => d.kind === 'audioinput');
  const speakers = devices.filter(d => d.kind === 'audiooutput');

  console.log('Cameras:', cameras.map(c => c.label));
  console.log('Microphones:', mics.map(m => m.label));
  console.log('Speakers:', speakers.map(s => s.label));

  return { cameras, mics, speakers };
}

Best Practices

Click to expand implementation details

Enterprise Success Stories

How leading companies use browser streaming

Zoom

300M daily meeting participants

47% improvement in browser join rates
"Integrating WAVE's browser streaming SDK reduced our development time by 6 months. The WebRTC abstraction handles all the edge cases we used to struggle with - ICE negotiation, TURN fallbacks, adaptive bitrate. Our browser-based participants now have the same quality as native apps."

Eric Yuan

Founder & CEO, Zoom Video Communications

WebRTC
Screen Share
Virtual Backgrounds

Loom

25M users creating video content

92% first-try recording success rate
"WAVE powers our entire browser recording infrastructure. The SDK's MediaStream handling and automatic quality adaptation means our users can record professional videos without any plugins. Screen + webcam composite streaming just works, even on older hardware."

Joe Thomas

CEO & Co-founder, Loom

Screen Recording
PiP Mode
Canvas Streaming

Figma

4M+ real-time collaboration sessions/month

99.7% stream stability across all browsers
"FigJam's live video collaboration is built on WAVE's browser streaming. The low-latency WebRTC implementation lets our users collaborate in real-time with video overlays directly in the canvas. Connection quality monitoring automatically adjusts quality so collaboration never stutters."

Dylan Field

CEO & Co-founder, Figma

Multi-Source
Quality Monitoring
Cross-Browser

API Reference

Browser streaming endpoints

MethodPathDescriptionAuth
POST
/v1/browser/sessionsCreate browser streaming session
API Key
POST
/v1/browser/sessions/:id/startStart publishing to session
Session Token
POST
/v1/browser/sessions/:id/stopStop browser stream
Session Token
GET
/v1/browser/sessions/:id/statsGet real-time connection stats
Session Token
POST
/v1/browser/sessions/:id/qualitySet quality preset
Session Token
GET
/v1/browser/capabilitiesCheck browser feature support
Public
POST
/v1/browser/ice-serversGet ICE server configuration
API Key
POST
/v1/browser/compositeCreate multi-source composite
Session Token
PUT
/v1/browser/composite/:id/layoutUpdate composite layout
Session Token
GET
/v1/browser/devicesList user media devices
Public

Base URL: https://api.wave.online

See the full Browser API documentation for detailed request/response schemas.

WAVE - Enterprise Live Streaming Platform