Rooks
HooksBrowser APIs

useMediaRecorder

Records audio/video streams using the MediaRecorder API.

About

React hook for audio/video recording using the MediaRecorder API. Provides methods to record, pause, resume, and stop media capture from any MediaStream source.

Installation

npm install rooks

Usage

import { useMediaRecorder } from "rooks";
import { useEffect, useState } from "react";

function AudioRecorder() {
  const [stream, setStream] = useState<MediaStream | null>(null);

  useEffect(() => {
    let activeStream: MediaStream | null = null;
    void navigator.mediaDevices.getUserMedia({ audio: true }).then((next) => {
      activeStream = next;
      setStream(next);
    });

    return () => {
      activeStream?.getTracks().forEach((track) => track.stop());
    };
  }, []);

  const {
    startRecording,
    stopRecording,
    pauseRecording,
    resumeRecording,
    recordingState,
    dataUrl,
    error,
    isSupported,
  } = useMediaRecorder(stream, { mimeType: "audio/webm" });

  if (!isSupported) {
    return <div>MediaRecorder API not supported in this browser</div>;
  }

  return (
    <div>
      <h2>Audio Recorder</h2>
      <p>
        Status: <strong>{recordingState}</strong>
      </p>

      <div>
        <button
          onClick={startRecording}
          disabled={recordingState === "recording" || !stream}
        >
          Start Recording
        </button>
        <button
          onClick={pauseRecording}
          disabled={recordingState !== "recording"}
        >
          Pause
        </button>
        <button
          onClick={resumeRecording}
          disabled={recordingState !== "paused"}
        >
          Resume
        </button>
        <button
          onClick={stopRecording}
          disabled={recordingState === "idle" || recordingState === "stopped"}
        >
          Stop
        </button>
      </div>

      {dataUrl && (
        <div>
          <h3>Recording</h3>
          <audio src={dataUrl} controls />
          <a href={dataUrl} download="recording.webm">
            Download Recording
          </a>
        </div>
      )}

      {error && <p style={{ color: "red" }}>Error: {error.message}</p>}
    </div>
  );
}

Return value

Returns an object with the following properties:

PropertyTypeDescription
startRecording() => voidStart recording
stopRecording() => voidStop recording
pauseRecording() => voidPause recording
resumeRecording() => voidResume recording
recordingState"idle" | "recording" | "paused" | "stopped"Current recording state
dataBlob | nullRecorded data as a Blob
dataUrlstring | nullURL to the recorded data
errorError | nullAny error that occurred
isSupportedbooleanWhether MediaRecorder API is supported

Recording States

  • "idle" - Not recording
  • "recording" - Currently recording
  • "paused" - Recording paused
  • "stopped" - Recording stopped (data available)

MediaRecorder Options

The hook accepts an optional options parameter:

OptionTypeDescription
mimeTypestringMIME type for the recording
audioBitsPerSecondnumberAudio bits per second
videoBitsPerSecondnumberVideo bits per second
bitsPerSecondnumberOverall bits per second

Examples

import { useState } from "react";
import { useMediaRecorder } from "rooks";

export default function AudioRecorder() {
  const [stream, setStream] = useState<MediaStream | null>(null);
  const recorder = useMediaRecorder(stream, { mimeType: "audio/webm" });

  async function requestMicrophone() {
    setStream(await navigator.mediaDevices.getUserMedia({ audio: true }));
  }

  return (
    <section>
      <p>Recorder state: {recorder.recordingState}</p>
      <button type="button" onClick={requestMicrophone}>
        Enable microphone
      </button>
      <button
        type="button"
        onClick={recorder.startRecording}
        disabled={!stream}
      >
        Record
      </button>
      <button type="button" onClick={recorder.stopRecording}>
        Stop
      </button>
    </section>
  );
}

Video Recording

function VideoRecorder() {
  const [stream, setStream] = useState(null);

  const startCamera = async () => {
    const mediaStream = await navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true,
    });
    setStream(mediaStream);
  };

  const { startRecording, stopRecording, recordingState, dataUrl } =
    useMediaRecorder(stream, { mimeType: "video/webm" });

  return (
    <div>
      {!stream && <button onClick={startCamera}>Start Camera</button>}
      {stream && (
        <>
          <video
            ref={(video) => {
              if (video && stream) video.srcObject = stream;
            }}
            autoPlay
            muted
          />
          <button onClick={startRecording}>Record</button>
          <button onClick={stopRecording}>Stop</button>
        </>
      )}
      {dataUrl && <video src={dataUrl} controls />}
    </div>
  );
}

Screen Recording

function ScreenRecorder() {
  const [stream, setStream] = useState(null);

  const startScreenCapture = async () => {
    const mediaStream = await navigator.mediaDevices.getDisplayMedia({
      video: { mediaSource: "screen" },
      audio: true,
    });
    setStream(mediaStream);
  };

  const { startRecording, stopRecording, dataUrl } = useMediaRecorder(stream);

  return (
    <div>
      <button onClick={startScreenCapture}>Share Screen</button>
      {stream && (
        <>
          <button onClick={startRecording}>Start Recording</button>
          <button onClick={stopRecording}>Stop Recording</button>
        </>
      )}
      {dataUrl && (
        <div>
          <video src={dataUrl} controls style={{ maxWidth: "100%" }} />
          <a href={dataUrl} download="screen-recording.webm">
            Download
          </a>
        </div>
      )}
    </div>
  );
}

Features

  • Audio/video recording - Record from any MediaStream source
  • Pause/resume - Control recording with pause and resume
  • Multiple sources - Works with microphone, camera, screen capture
  • Automatic cleanup - Properly manages resources and memory
  • Error handling - Comprehensive error handling
  • TypeScript support - Full type definitions with generics

Browser Support

The MediaRecorder API is supported in:

  • Chrome 47+
  • Firefox 25+
  • Safari 14.1+
  • Edge 79+
  • Opera 36+

Notes

  • You must obtain a MediaStream before using the hook (via getUserMedia, getDisplayMedia, etc.)
  • The recorded Blob is available after calling stopRecording()
  • dataUrl is automatically created and can be used for playback or download
  • Data URL is automatically revoked on unmount to prevent memory leaks
  • Supported MIME types vary by browser - check MediaRecorder.isTypeSupported()
  • The MediaRecorder is automatically stopped on component unmount

Parameters

ArgumentTypeDefaultDescription
streamMediaStream | nullrequiredStream from getUserMedia, getDisplayMedia, or another source.
optionsobject{}mimeType, audioBitsPerSecond, videoBitsPerSecond, and bitsPerSecond, passed to MediaRecorder.

Behavior and lifecycle

When a supported, non-null stream is supplied, the effect constructs a MediaRecorder. Changing the stream/options or unmounting stops an active recorder. Each start clears prior chunks, blob, URL, and error. The stop event joins chunks into a Blob, creates an object URL, and sets state to "stopped"; replaced URLs are revoked. The hook stops the recorder, but it does not stop source media tracks—call track.stop() when capture is no longer needed.

Compatibility and accessibility

SSR reports isSupported: false. Creating the recorder and every control operation can set error; controls that do not match the current state are otherwise no-ops. Media capture requires HTTPS, permission, and a user gesture, and supported MIME types differ by browser—check MediaRecorder.isTypeSupported() before selecting one. Keep visible recording indicators and accessible start/stop controls, and honor revoked permission or ended tracks.

On this page