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

react-record-webcam

v2.0.1

Published

React hook for webcam and audio recording with multi-device support, quality presets, and full TypeScript types

Downloads

32,662

Readme

npm npm bundle size license

React hook for webcam and audio recording with multi-device support, quality presets, screenshot capture, recording timer, and full TypeScript types. Zero dependencies beyond React.

Demo  |  Try on StackBlitz

Features

  • Multi-device — record from multiple webcams and microphones simultaneously
  • Quality presetslow, medium, high, hd with sensible defaults
  • Recording timeruseRecordingTimer hook with pause-aware elapsed time
  • Screenshot capture — grab a PNG frame from any live camera
  • Audio-only mode — record audio without video
  • Pause / resume / mute — full recording lifecycle control
  • Max duration — auto-stop recording after a time limit
  • Device hot-plug — device list updates when hardware is connected or removed
  • Permissions APIcameraPermission state without triggering the browser prompt
  • Progressive uploadonDataAvailable callback streams chunks in real-time
  • Status callbacksonStatusChange fires on every state transition
  • Structured errors — typed error object with code, message, and recordingId
  • Next.js ready — ships with "use client" directive
  • ESM + CJS — dual-format build with full TypeScript declarations
  • Tiny — zero runtime dependencies

Install

npm install react-record-webcam

Quick start

import { useRecordWebcam } from 'react-record-webcam';

function App() {
  const {
    activeRecordings,
    createRecording,
    openCamera,
    startRecording,
    stopRecording,
    download,
  } = useRecordWebcam();

  const record = async () => {
    const recording = await createRecording();
    if (!recording) return;
    await openCamera(recording.id);
    await startRecording(recording.id);
  };

  return (
    <div>
      <button onClick={record}>Record</button>
      {activeRecordings.map((recording) => (
        <div key={recording.id}>
          <video ref={recording.webcamRef} autoPlay muted playsInline />
          <video ref={recording.previewRef} autoPlay loop playsInline />
          <button onClick={() => stopRecording(recording.id)}>Stop</button>
          <button onClick={() => download(recording.id)}>Download</button>
        </div>
      ))}
    </div>
  );
}

Quality presets

Skip manual configuration with built-in presets:

const recorder = useRecordWebcam({ quality: 'high' });

| Preset | Resolution | Video bitrate | Audio bitrate | | -------- | ---------- | ------------- | ------------- | | low | 640x480 | 500 kbps | 64 kbps | | medium | 1280x720 | 1.5 Mbps | 128 kbps | | high | 1920x1080 | 3 Mbps | 192 kbps | | hd | 3840x2160 | 8 Mbps | 256 kbps |

Recording timer

import { useRecordWebcam, useRecordingTimer } from 'react-record-webcam';

function RecordingView({ recording }) {
  const elapsed = useRecordingTimer(recording);

  return (
    <div>
      <p>{Math.floor(elapsed / 60)}:{String(elapsed % 60).padStart(2, '0')}</p>
      <video ref={recording.webcamRef} autoPlay muted playsInline />
    </div>
  );
}

The timer correctly pauses when the recording is paused and resumes from the correct offset.

Audio-only recording

const recording = await createRecording(undefined, undefined, { audioOnly: true });
await openCamera(recording.id);
await startRecording(recording.id);

Screenshot capture

const blob = await captureScreenshot(recording.id);
// blob is a PNG image you can upload or display

Progressive upload

Stream recording chunks to a server in real-time:

const recorder = useRecordWebcam({
  options: { timeSlice: 1000 },
  onDataAvailable: (recordingId, chunk) => {
    fetch('/api/upload', { method: 'POST', body: chunk });
  },
});

Auto-stop with max duration

const recorder = useRecordWebcam({
  options: { maxDuration: 30000 }, // 30 seconds
});

Status change callback

const recorder = useRecordWebcam({
  onStatusChange: (recordingId, oldStatus, newStatus) => {
    console.log(`${recordingId}: ${oldStatus} -> ${newStatus}`);
  },
});

API

useRecordWebcam(args?)

Main hook. All arguments are optional.

| Argument | Type | Description | | ------------------------ | --------------------------- | -------------------------------------------------------- | | mediaTrackConstraints | MediaTrackConstraints | Video track constraints (e.g. width, height, frameRate). These are MediaTrackConstraintsnot MediaStreamConstraints. Do not pass video: true or audio: true here; video and audio are always enabled by default. Use createRecording(videoId, audioId, { audioOnly: true }) to record audio-only. | | mediaRecorderOptions | MediaRecorderOptions | Options for the MediaRecorder constructor | | options.fileName | string | Output file name (default: timestamp) | | options.fileType | string | Output file extension (default: webm) | | options.timeSlice | number | Chunk interval in ms for MediaRecorder.start() | | options.maxDuration | number | Auto-stop after this many ms | | quality | QualityPreset | 'low' | 'medium' | 'high' | 'hd' | | onStatusChange | (id, old, new) => void | Called on every status transition | | onDataAvailable | (id, chunk) => void | Called when a data chunk is available |

Return value

| Property | Type | Description | | --------------------- | ------------------------------------------ | --------------------------------------------- | | activeRecordings | Recording[] | All current recordings | | cameraPermission | CameraPermission | 'prompt' | 'granted' | 'denied' | 'unknown' | | devicesByType | { video, audio } | Available devices grouped by type | | devicesById | Record<string, { label, type }> | Devices keyed by ID | | error | RecordingError \| null | Structured error with code and message | | errorMessage | string \| null | Error message string (backward compat) | | createRecording | (videoId?, audioId?, opts?) => Promise | Create a new recording session | | openCamera | (id) => Promise | Open the camera stream | | closeCamera | (id) => Promise | Close the camera stream | | startRecording | (id) => Promise | Start recording | | stopRecording | (id) => Promise | Stop recording | | pauseRecording | (id) => Promise | Pause recording | | resumeRecording | (id) => Promise | Resume recording | | muteRecording | (id) => Promise | Toggle audio mute | | cancelRecording | (id) => Promise | Cancel and remove a recording | | captureScreenshot | (id) => Promise<Blob \| void> | Capture a PNG screenshot from the webcam | | download | (id) => Promise | Download the recording | | getBlob | (id) => Blob \| undefined | Get the recording's Blob directly | | clearPreview | (id) => Promise | Clear the preview and reset | | clearAllRecordings | () => Promise | Clear all recordings | | clearError | () => void | Dismiss the current error | | applyConstraints | (id, constraints) => Promise | Apply new constraints to a live camera | | applyRecordingOptions | (id) => Promise | Apply current options to a recording |

useRecordingTimer(recording?)

Returns the elapsed recording time in seconds. Handles pause/resume correctly.

const elapsed = useRecordingTimer(recording); // number (seconds)

Recording

| Field | Type | Description | | -------------- | -------------------------- | ---------------------------------------- | | id | string | Unique recording identifier | | status | Status | Current status | | audioOnly | boolean | Whether this is audio-only | | webcamRef | RefObject | Attach to a <video> for live preview | | previewRef | RefObject | Attach to a <video> for playback | | blob | Blob \| undefined | The recorded blob (after stop) | | objectURL | string \| null | Object URL for the blob | | startedAt | number \| null | Timestamp when recording started | | pausedAt | number \| null | Timestamp when recording was paused | | totalPausedMs| number | Total milliseconds spent paused | | isMuted | boolean | Whether audio is muted | | recorder | MediaRecorder \| null | The underlying MediaRecorder |

Status

'INITIAL' | 'OPEN' | 'RECORDING' | 'PAUSED' | 'STOPPED' | 'CLOSED' | 'ERROR'

Migrating from v1

v2 is backward compatible for most users. Breaking changes:

  • Minimum React version is now 18.0 (was 16.3). The store was rewritten to use useSyncExternalStore.
  • createRecording accepts an optional third argument { audioOnly: boolean }.
  • New fields on Recording (audioOnly, startedAt, pausedAt, totalPausedMs) have safe defaults.
  • New return values (error, cameraPermission, captureScreenshot, getBlob) are additive.

Browser support

Requires browsers with MediaRecorder and getUserMedia support. All modern browsers (Chrome, Firefox, Edge, Safari 14.1+).

License

MIT