npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vidtreo/recorder

v1.3.3

Published

Vidtreo SDK for browser-based video recording and transcoding. Features include camera/screen recording, real-time MP4 transcoding, audio level analysis, mute/pause controls, source switching, device selection, and automatic backend uploads. Similar to Zi

Downloads

758

Readme

@vidtreo/recorder

Vidtreo SDK for browser-based video recording and transcoding. Similar to Ziggeo and Addpipe, Vidtreo provides enterprise-grade video processing capabilities for web applications. Features include camera and screen recording, real-time MP4 transcoding, audio level analysis, mute/pause controls, source switching, device selection, and automatic backend uploads.

Installation

npm install @vidtreo/recorder

Quick Start

import { VidtreoRecorder } from '@vidtreo/recorder';

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://core.vidtreo.com', // Optional, defaults to https://core.vidtreo.com
  enableSourceSwitching: true,
  maxRecordingTime: 300000,
  onUploadComplete: (result) => {
    console.log('Recording ID:', result.recordingId);
    console.log('Video URL:', result.uploadUrl);
  },
});

await recorder.startPreview('camera');
await recorder.startRecording({}, 'camera');
const result = await recorder.stopRecording();
recorder.cleanup();

API Reference

VidtreoRecorder

The main class for recording video from camera or screen sources.

Constructor

new VidtreoRecorder(config: VidtreoRecorderConfig)

Creates a new recorder instance with the specified configuration.

Parameters:

  • config.apiKey (required): Your API key for backend authentication
  • config.apiUrl (optional): Your backend API URL endpoint. Defaults to https://core.vidtreo.com if not provided
  • config.enableSourceSwitching (optional): Enable switching between camera and screen during recording. Default: false
  • config.enableMute (optional): Enable mute/unmute functionality. When disabled, muteAudio(), unmuteAudio(), and toggleMute() will throw errors. Default: true
  • config.enablePause (optional): Enable pause/resume functionality. When disabled, pauseRecording() and resumeRecording() will throw errors. Default: true
  • config.enableDeviceChange (optional): Enable device selection functionality. When disabled, getAvailableDevices() will throw an error. Default: true
  • config.maxRecordingTime (optional): Maximum recording duration in milliseconds. When the maximum time is reached, recording automatically stops. If not set, recording can continue indefinitely until manually stopped. Examples: 300000 (5 minutes), 600000 (10 minutes), 1800000 (30 minutes)
  • config.countdownDuration (optional): Countdown duration in milliseconds before recording starts. Default: 0 (no countdown)
  • config.userMetadata (optional): Custom metadata object to include with uploads
  • config.onUploadComplete (optional): Callback invoked when upload completes successfully
  • config.onUploadProgress (optional): Callback invoked during upload with progress value (0-1)
  • config.onUploadError (optional): Callback invoked when upload fails
  • config.onRecordingStart (optional): Callback invoked when recording starts
  • config.onRecordingStop (optional): Callback invoked when recording stops
  • config.onError (optional): Callback invoked when a stream error occurs

Throws: Error if apiKey is missing

Methods

initialize(): Promise<void>

Initializes the recorder with the provided configuration. Called automatically when needed, but can be called explicitly for early initialization.

Returns: Promise<void>

startPreview(sourceType?: SourceType): Promise<MediaStream>

Starts a preview stream from the specified source without recording.

Parameters:

  • sourceType (optional): Source type to preview. Either 'camera' or 'screen'. Default: 'camera'

Returns: Promise<MediaStream> - The preview media stream

Throws: Error if stream initialization fails

startRecording(options?: RecordingStartOptions, sourceType?: SourceType): Promise<void>

Starts recording from the specified source. If no preview is active, automatically starts one.

Parameters:

  • options (optional): Recording options object
    • options.video: Video constraints (boolean or CameraConstraints object)
    • options.audio: Audio constraints (boolean or MediaTrackConstraints object)
  • sourceType (optional): Source type to record from. Either 'camera' or 'screen'. Default: 'camera'

Returns: Promise<void>

Throws: Error if recording cannot be started

stopRecording(): Promise<RecordingStopResult>

Stops the current recording, transcodes the video, and uploads it to the backend.

Returns: Promise<RecordingStopResult> - Object containing:

  • recordingId: Unique identifier for the uploaded recording
  • uploadUrl: URL where the video can be accessed
  • blob: The recorded video as a Blob

Throws: Error if recording is not active or upload fails

switchSource(sourceType: SourceType): Promise<void>

Switches the recording source between camera and screen during an active recording.

Parameters:

  • sourceType: Target source type. Either 'camera' or 'screen'

Returns: Promise<void>

Throws: Error if source switching is not enabled or if not currently recording

getAvailableDevices(): Promise<AvailableDevices>

Retrieves the list of available camera and microphone devices.

Returns: Promise<AvailableDevices> - Object containing:

  • video: Array of available video input devices
  • audio: Array of available audio input devices

Throws: Error if device change functionality is disabled (enableDeviceChange === false)

muteAudio(): void

Mutes the audio track during recording.

Throws: Error if mute functionality is disabled (enableMute === false)

unmuteAudio(): void

Unmutes the audio track during recording.

Throws: Error if mute functionality is disabled (enableMute === false)

toggleMute(): void

Toggles the mute state of the audio track.

Throws: Error if mute functionality is disabled (enableMute === false)

isMuted(): boolean

Returns the current mute state.

Returns: true if audio is muted, false otherwise

pauseRecording(): void

Pauses the current recording. Video frames are not captured while paused.

Throws: Error if pause functionality is disabled (enablePause === false)

resumeRecording(): void

Resumes a paused recording.

Throws: Error if pause functionality is disabled (enablePause === false)

isPaused(): boolean

Returns the current pause state.

Returns: true if recording is paused, false otherwise

getRecordingState(): RecordingState

Returns the current recording state.

Returns: One of:

  • 'idle': Not recording
  • 'countdown': Countdown in progress before recording
  • 'recording': Actively recording
getStream(): MediaStream | null

Returns the current media stream, or null if no stream is active.

Returns: MediaStream | null

cleanup(): void

Cleans up all resources, stops active streams, and cancels any pending operations. Should be called when the recorder is no longer needed.

Type Definitions

VidtreoRecorderConfig

interface VidtreoRecorderConfig {
  apiKey: string;
  apiUrl?: string;
  enableSourceSwitching?: boolean;
  enableMute?: boolean;
  enablePause?: boolean;
  enableDeviceChange?: boolean;
  maxRecordingTime?: number;
  countdownDuration?: number;
  userMetadata?: Record<string, unknown>;
  enableTabVisibilityOverlay?: boolean;
  tabVisibilityOverlayText?: string;
  onUploadComplete?: (result: {
    recordingId: string;
    uploadUrl: string;
  }) => void;
  onUploadProgress?: (progress: number) => void;
  onUploadError?: (error: Error) => void;
  onRecordingStart?: () => void;
  onRecordingStop?: () => void;
  onError?: (error: Error) => void;
}

enableTabVisibilityOverlay applies to camera recordings. When enabled and tabVisibilityOverlayText is omitted or blank, the SDK uses "User in another tab" as a default fallback. Overlay rendering is skipped for screen capture recordings.

Note: For web component usage, see the @vidtreo/recorder-wc package. Use the max-recording-time attribute instead of maxRecordingTime. The attribute accepts a numeric value in milliseconds as a string (e.g., max-recording-time="300000" for 5 minutes).

RecordingStartOptions

interface RecordingStartOptions {
  video?: boolean | CameraConstraints;
  audio?: boolean | MediaTrackConstraints;
}

RecordingStopResult

interface RecordingStopResult {
  recordingId: string;
  uploadUrl: string;
  blob: Blob;
}

SourceType

type SourceType = 'camera' | 'screen';

RecordingState

type RecordingState = 'idle' | 'countdown' | 'recording';

AvailableDevices

interface AvailableDevices {
  video: MediaDeviceInfo[];
  audio: MediaDeviceInfo[];
}

CameraConstraints

interface CameraConstraints {
  width?: number | { ideal?: number; min?: number; max?: number };
  height?: number | { ideal?: number; min?: number; max?: number };
  frameRate?: number | { ideal?: number; min?: number; max?: number };
}

Usage Examples

Basic Recording Workflow

import { VidtreoRecorder } from '@vidtreo/recorder';

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com', // Optional, defaults to https://core.vidtreo.com
  onUploadComplete: (result) => {
    console.log('Uploaded:', result.uploadUrl);
  },
});

try {
  await recorder.startPreview('camera');
  await recorder.startRecording({}, 'camera');

  setTimeout(async () => {
    const result = await recorder.stopRecording();
    console.log('Recording ID:', result.recordingId);
    recorder.cleanup();
  }, 10000);
} catch (error) {
  console.error('Recording failed:', error);
  recorder.cleanup();
}

Recording with Maximum Time Limit

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
  maxRecordingTime: 300000,
  onRecordingStop: () => {
    console.log('Recording stopped automatically after 5 minutes');
  },
});

await recorder.startRecording({}, 'camera');

Recording with Source Switching

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
  enableSourceSwitching: true,
  maxRecordingTime: 600000,
});

await recorder.startRecording({}, 'camera');

setTimeout(async () => {
  await recorder.switchSource('screen');
}, 5000);

setTimeout(async () => {
  await recorder.switchSource('camera');
}, 10000);

setTimeout(async () => {
  const result = await recorder.stopRecording();
  recorder.cleanup();
}, 15000);

Note: When maxRecordingTime is set, the recording will automatically stop when the time limit is reached, even if the timeout callbacks are still pending. The onRecordingStop callback will be invoked when the maximum time is reached.

Recording with Mute Control

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
});

await recorder.startRecording({}, 'camera');

recorder.muteAudio();
setTimeout(() => recorder.unmuteAudio(), 5000);
setTimeout(() => recorder.toggleMute(), 10000);

setTimeout(async () => {
  await recorder.stopRecording();
  recorder.cleanup();
}, 15000);

Recording with Pause and Resume

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
});

await recorder.startRecording({}, 'camera');

setTimeout(() => recorder.pauseRecording(), 3000);
setTimeout(() => recorder.resumeRecording(), 6000);

setTimeout(async () => {
  await recorder.stopRecording();
  recorder.cleanup();
}, 10000);

Recording with Upload Progress

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
  onUploadProgress: (progress) => {
    const percentage = Math.round(progress * 100);
    console.log(`Upload: ${percentage}%`);
  },
  onUploadComplete: (result) => {
    console.log('Upload complete:', result.uploadUrl);
  },
  onUploadError: (error) => {
    console.error('Upload failed:', error.message);
  },
});

await recorder.startRecording({}, 'camera');
setTimeout(async () => {
  await recorder.stopRecording();
  recorder.cleanup();
}, 5000);

Recording with Custom Metadata

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
  userMetadata: {
    userId: 'user-123',
    sessionId: 'session-456',
    projectId: 'project-789',
  },
});

await recorder.startRecording({}, 'camera');
setTimeout(async () => {
  await recorder.stopRecording();
  recorder.cleanup();
}, 5000);

Recording with Countdown

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
  countdownDuration: 3000,
});

await recorder.startPreview('camera');
await recorder.startRecording({}, 'camera');
setTimeout(async () => {
  await recorder.stopRecording();
  recorder.cleanup();
}, 10000);

Device Selection

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
});

const devices = await recorder.getAvailableDevices();
console.log('Cameras:', devices.video.map(d => d.label));
console.log('Microphones:', devices.audio.map(d => d.label));

await recorder.startRecording({}, 'camera');
setTimeout(async () => {
  await recorder.stopRecording();
  recorder.cleanup();
}, 5000);

Recording State Monitoring

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
  onRecordingStart: () => {
    console.log('Recording started');
  },
  onRecordingStop: () => {
    console.log('Recording stopped');
  },
});

await recorder.startRecording({}, 'camera');

const checkState = setInterval(() => {
  const state = recorder.getRecordingState();
  const isPaused = recorder.isPaused();
  const isMuted = recorder.isMuted();
  console.log(`State: ${state}, Paused: ${isPaused}, Muted: ${isMuted}`);
}, 1000);

setTimeout(async () => {
  clearInterval(checkState);
  await recorder.stopRecording();
  recorder.cleanup();
}, 10000);

Screen Recording

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
  enableSourceSwitching: true,
});

await recorder.startPreview('screen');
await recorder.startRecording({}, 'screen');
setTimeout(async () => {
  await recorder.stopRecording();
  recorder.cleanup();
}, 30000);

Error Handling

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
  onError: (error) => {
    console.error('Stream error:', error.message);
  },
  onUploadError: (error) => {
    console.error('Upload error:', error.message);
  },
});

try {
  await recorder.startRecording({}, 'camera');
  const result = await recorder.stopRecording();
  console.log('Success:', result.uploadUrl);
} catch (error) {
  console.error('Recording error:', error);
} finally {
  recorder.cleanup();
}

Recording with Disabled Features

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com',
  enableMute: false,
  enablePause: false,
  enableSourceSwitching: false,
  enableDeviceChange: false,
});

await recorder.startRecording({}, 'camera');

try {
  recorder.muteAudio();
} catch (error) {
  console.error('Mute is disabled:', error.message);
}

try {
  recorder.pauseRecording();
} catch (error) {
  console.error('Pause is disabled:', error.message);
}

setTimeout(async () => {
  await recorder.stopRecording();
  recorder.cleanup();
}, 10000);

Web Component Usage

The web component is available in a separate package: @vidtreo/recorder-wc

For web component installation, usage, and examples, please refer to the @vidtreo/recorder-wc documentation.

Advanced Usage

Telemetry

The recorder automatically sends telemetry events to monitor SDK usage, detect issues, and improve the product. Telemetry is always active and cannot be disabled through configuration.

When Telemetry is Activated

Telemetry is initialized when you call initialize() on the recorder instance:

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://api.example.com', // This URL is also used for telemetry
});

await recorder.initialize(); // Telemetry client is initialized here

Telemetry Endpoint

Telemetry events are sent to:

  • Default: {apiUrl}/api/v1/telemetry
  • Same apiUrl used for config and upload operations

The apiUrl can be overridden when creating the recorder:

const recorder = new VidtreoRecorder({
  apiKey: 'your-api-key',
  apiUrl: 'https://custom-api.example.com', // Telemetry, config, and upload all use this URL
});

Delivery Behavior

Telemetry delivery is optimized for low overhead and no duplicate events:

  • Events are batched in memory and flushed after 10 events or 1 second
  • One-time events are deduped per session (sdk.init.started, sdk.init.succeeded, sdk.init.failed)
  • Noisy errors are throttled (currently stream.error emits at most once per 5 seconds)

Events Tracked

The SDK automatically tracks the following telemetry events:

| Event Name | Category | Description | |------------|----------|-------------| | Lifecycle Events | | | | sdk.init.started | lifecycle | Sent when recorder initialization begins | | sdk.init.succeeded | lifecycle | Sent when recorder initialization completes successfully | | sdk.init.failed | error | Sent when recorder initialization fails (includes error details) | | Preview Events | | | | preview.start.succeeded | interaction | Sent when preview stream starts successfully | | preview.start.failed | error | Sent when preview stream fails to start (includes error details) | | Recording Events | | | | recording.start.requested | interaction | Sent when user requests to start recording | | recording.start.succeeded | interaction | Sent when recording starts successfully | | recording.start.failed | error | Sent when recording fails to start (includes error details) | | recording.stop.requested | interaction | Sent when user requests to stop recording | | recording.stop.succeeded | interaction | Sent when recording stops successfully | | recording.stop.failed | error | Sent when recording fails to stop (includes error details) | | Upload Events | | | | upload.started | performance | Sent when video upload begins | | upload.succeeded | performance | Sent when video upload completes successfully | | upload.failed | error | Sent when video upload fails (includes error details) | | Source Switch Events | | | | source.switch.requested | interaction | Sent when source switch is requested | | source.switch.succeeded | interaction | Sent when source switch completes successfully | | source.switch.failed | error | Sent when source switch fails (includes error details) | | Stream Events | | | | stream.error | error | Sent when a stream error occurs (includes error details) |

Event Categories

Events are categorized for analysis:

  • lifecycle: SDK initialization events
  • interaction: User-initiated actions (start/stop/switch)
  • performance: Upload performance metrics
  • error: Any error that occurs during operations

Event Properties

Events include the following properties automatically:

  • browserName: Detected browser (chrome, firefox, safari, edge, unknown)
  • sourceType: Source being used (camera or screen)
  • filename: Name of uploaded file (upload events)
  • duration: Video duration in milliseconds (upload events)
  • recordingId: ID of uploaded recording (upload.succeeded)

Error Details

Error events include additional information:

  • error.message: Human-readable error message
  • error.name: Error type/name
  • error.stack: Stack trace (if available)

Telemetry Payload

Each telemetry request includes:

{
  events: [
    {
      event: string,               // Event name
      category: string,            // lifecycle | interaction | performance | error
      timestamp: number,           // Unix timestamp in milliseconds
      installationId: string,      // Persistent per-browser installation ID
      sdkVersion: string,          // SDK version from package.json
      fingerprint: {
        userAgent?: string,
        language?: string,
        platform?: string,
        hardwareConcurrency?: number,
        deviceMemory?: number,
      },
      context?: {
        sessionId?: string,
        userId?: string,
        environmentId?: string,
        appVersion?: string,
        release?: string,
        pageUrl?: string,
        referrerUrl?: string,
        sdkLocation?: string,
        clientLocation?: string,
      },
      properties?: Record<string, unknown>,
      error?: {
        message: string,
        name?: string,
        stack?: string,
      },
    },
  ];
}

Note: The API key is only sent in the Authorization header for other requests (like upload). It is not included in telemetry payloads.

Installation ID

A unique installationId is generated per browser and persisted in localStorage under key VIDTREO_INSTALLATION_ID. This ID persists across sessions and helps identify unique installations.

Privacy

  • API keys are sent in the Authorization header as Bearer ${apiKey} (not hashed)
  • Installation IDs are anonymous and randomly generated
  • User and session identifiers are optional and provided by your application
  • No personally identifiable information is collected unless explicitly provided through userMetadata

Low-Level APIs

For advanced use cases, the package exports lower-level APIs that provide more granular control:

Transcoding

import { transcodeVideo, DEFAULT_TRANSCODE_CONFIG } from '@vidtreo/recorder';

const videoBlob = new Blob([videoData], { type: 'video/mp4' });
const result = await transcodeVideo(videoBlob, {
  width: 1920,
  height: 1080,
  fps: 60,
  bitrate: 2000000,
});

console.log('Transcoded size:', result.buffer.byteLength);

RecorderController

For fine-grained control over the recording process:

import { RecorderController } from '@vidtreo/recorder';

const controller = new RecorderController({
  recording: {
    onStateChange: (state) => console.log('State:', state),
  },
});

await controller.initialize({
  apiKey: 'your-api-key',
});

Stream Management

import { CameraStreamManager } from '@vidtreo/recorder';

const streamManager = new CameraStreamManager();
await streamManager.startStream();
const stream = streamManager.getStream();

Configuration

Video transcoding configuration is managed through your backend API. The recorder fetches configuration using the provided apiKey and apiUrl.

Watermark Support

The recorder supports real-time watermark rendering. This is highly optimized for performance:

  • One-time preparation: The watermark is loaded and pre-rendered once before recording starts.
  • Dynamic Scaling: The watermark automatically scales to 7% of the video width while maintaining its aspect ratio.
  • Efficient Composition: The watermark is drawn directly onto a composition canvas, avoiding redundant opacity calculations per frame.

Watermark Configuration:

  • url: The URL of the image (PNG, JPG, or SVG). Data URLs (base64) are also supported and recommended for reliability.
  • opacity: Watermark opacity (0.0 to 1.0). Default: 1.0 (Recommended for best video compression).
  • position: One of "top-left", "top-right", "bottom-left", "bottom-right", or "center". Default: "bottom-right".

Default transcoding settings include:

  • Format: MP4
  • Frame rate: 30 fps
  • Resolution: 1280x720
  • Bitrate: 500 kbps
  • Audio codec: Opus
  • Preset: Medium quality

These defaults are used when backend configuration is unavailable or during initialization.

Browser Compatibility

This package requires modern browser APIs for full functionality. The most critical requirement is support for the WebCodecs API, which enables real-time MP4 transcoding.

Full Support (All Features)

The following browsers support all features including real-time MP4 transcoding:

  • Chrome 94+ - Full support for all features
  • Edge (Chromium) 94+ - Full support, same as Chrome
  • Opera 80+ - Full support, Chromium-based
  • Brave 1.30+ - Full support, Chromium-based
  • Vivaldi 5.0+ - Full support, Chromium-based
  • Firefox 130+ - Full WebCodecs support
  • Safari (macOS/iOS) 26.0+ - Full WebCodecs support

Partial Support (Core Features Only)

The following browsers support core recording features but may have limitations:

  • Firefox 76-129 - AudioWorklet supported, but WebCodecs not available. Real-time MP4 transcoding unavailable; falls back to MediaRecorder (WebM format)
  • Safari (macOS/iOS) 16.4-25.x - Partial WebCodecs support; some codecs may not be available

Required Browser APIs

  • WebCodecs API - Required for real-time MP4 transcoding (via mediabunny)
  • Web Workers - Required for video processing (no fallback available)
  • AudioWorklet - Required for audio processing and PCM capture
  • AudioContext - Required for AudioWorklet pipelines
  • MediaStreamTrackProcessor - Required for track processing in workers
  • VideoFrame - Required for video frame processing in workers
  • Screen Capture API (getDisplayMedia) - Required for screen recording
  • MediaDevices API (getUserMedia) - Required for camera/microphone access
  • IndexedDB - Required for persistent upload queue
  • Storage API - Required for storage quota management

Note: This package requires modern browsers with full Web Worker and AudioWorklet support. There is no fallback for browsers without Worker, AudioWorklet, MediaStreamTrackProcessor, VideoFrame, or OffscreenCanvas APIs.

Feature Support by Browser

| Feature | Chrome 94+ | Edge 94+ | Firefox 130+ | Safari 26.0+ | Firefox 76-129 | Safari 16.4-25.x | |---------|------------|---------|--------------|--------------|---------------|------------------| | Camera Recording | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Screen Recording | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Real-time MP4 Transcoding | ✅ | ✅ | ✅ | ✅ | ❌ (WebM) | ⚠️ (Partial) | | Audio Level Analysis | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Source Switching | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Device Switching | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Persistent Upload Queue | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |

Unsupported Browsers

  • Internet Explorer (all versions)
  • Firefox < 76 (missing AudioWorklet)
  • Safari < 14.1 (missing AudioWorklet)
  • Safari < 16.4 (missing OffscreenCanvas and WebCodecs)
  • Edge Legacy (pre-Chromium)
  • Chrome < 94 (missing WebCodecs)

Mobile Browser Support

  • Chrome Android 94+ - Full support
  • Samsung Internet 18.0+ - Full support
  • Firefox Android 130+ - Full support
  • Safari iOS 16.4+ - Partial support (WebCodecs partial)
  • Safari iOS 26.0+ - Full support

Important Notes

  1. HTTPS Required: Media capture APIs require HTTPS (or localhost) in most browsers
  2. User Permissions: Camera, microphone, and screen capture require explicit user permission
  3. Web Workers Required: This package requires Web Workers and AudioWorklet for video processing. Browsers without Worker support (or missing MediaStreamTrackProcessor, VideoFrame, or OffscreenCanvas) are not supported
  4. No Fallback: The package does not include a fallback for browsers without Web Worker support. Ensure your target browsers meet the minimum requirements

For detailed browser compatibility information, API requirements, and known limitations, see BROWSER_COMPATIBILITY.md.

License

MIT