All hooks / Browser APIs

useMediaRecorder

698 B minified and brotliedSourceMarkdown✓ Works in all modern browsers

Records a MediaStream (microphone, camera, or screen) into a file. Pair it with useUserMedia for the stream.

Picks a format the browser can actually record: Chrome and Firefox record WebM, Safari records MP4, so a hardcoded audio/webm fails in Safari. stop() resolves with the finished Blob once the recorder has delivered its last chunk. Recording stops on unmount and when stream changes; the stream itself is left running, so stop its tracks yourself (useUserMedia does that on unmount).

Import

import { useMediaRecorder } from '@vincent.ri/react-tils'
// or only this hook
import { useMediaRecorder } from '@vincent.ri/react-tils/useMediaRecorder'

Usage

const [on, setOn] = useState(false)
const { stream } = useUserMedia({ audio: true }, { enabled: on })
const recorder = useMediaRecorder(stream)
const finish = async () => {
  const blob = await recorder.stop()
  if (blob) await transcribe(new File([blob], 'note', { type: blob.type }))
  setOn(false)
}
return recorder.recording
  ? <button onClick={finish}>Stop</button>
  : <button onClick={() => (stream ? recorder.start() : setOn(true))}>{stream ? 'Record' : 'Allow microphone'}</button>

Live demo

Record a few seconds from your microphone, then play it back.

nothing recorded

When to use it

Voice notes, voice input for an AI chat (record, then send to a transcription API), recording a video message, or a screen recording.

When not to

You want live speech-to-text in the browser; that is the Web Speech API. To only show a camera or microphone preview, use useUserMedia alone.

API

function useMediaRecorder(stream: MediaStream | null, options?: MediaRecorderOptions): MediaRecorderState
ParameterDescription
streamThe stream to record, or null until it's ready.
optionsmimeTypes: formats to try, in order. Optional.

Returns { supported, recording, mimeType, blob, error, start, stop }.

Types

export type MediaRecorderOptions = {
  /** Formats to try, in order; the first one the browser can record is used. Default: Opus in WebM, then MP4 (Safari), then Ogg, for audio; VP9/VP8 WebM, then MP4, for video. */
  mimeTypes?: string[];
};
export type MediaRecorderState = {
  /** `false` on the server, during hydration, and in browsers without `MediaRecorder`. */
  supported: boolean;
  recording: boolean;
  /** The format actually recorded, e.g. `audio/webm;codecs=opus` or `audio/mp4`. Use it for the file extension and upload. */
  mimeType: string | null;
  /** The last finished recording. */
  blob: Blob | null;
  error: Error | null;
  /** Start recording `stream`. Does nothing while recording or without a stream. */
  start: () => void;
  /** Stop and resolve with the finished recording, including its last chunk. */
  stop: () => Promise<Blob | null>;
};

Browser support

UsesChromeEdgeFirefoxSafariChrome AndroidSafari iOS
MediaRecorderWidely available47+79+25+14.1+47+14+
  • Browsers record different formats (Safari records MP4, others WebM); the hook picks one the browser supports and reports it as mimeType.

First version with support, from MDN's compatibility data (web-features 3.42.0, @mdn/browser-compat-data 8.1.5).

Coming from another library?

Other libraries call this useRecorder, useAudioRecorder, react-media-recorder.