MediaRecorder for Real Recording Pipelines: Chunked Capture, WebM, and the Safari Problem

MediaRecorder is the bridge between 'camera demo' and 'recorded file' — chunked data handling, codec selection, duration limits, and the Safari fallback strategy.

MediaRecorder turns a MediaStream into a file — but “turns into a file” hides the real work: chunks arrive asynchronously, the container format is WebM (or MP4 on newer Safari), and a 10-minute recording in memory will crash the tab if you don’t stream it out.

The Basic Pipeline

const recorder = new MediaRecorder(stream, {
  mimeType: 'video/webm;codecs=vp9,opus',
  videoBitsPerSecond: 2500000,
  audioBitsPerSecond: 128000
});

const chunks = [];
recorder.ondataavailable = (e) => { if (e.data.size) chunks.push(e.data); };
recorder.onstop = () => {
  const blob = new Blob(chunks, { type: 'video/webm' });
  upload(blob); // or download, or store
};

recorder.start(1000); // emit a data chunk every second — critical for long recordings

The timeslice argument to start(1000) is the difference between a demo and a pipeline: without it, dataavailable only fires on stop() — a 5-minute recording buffers entirely in RAM.

Codec and Container Selection

mimeTypeBrowser SupportNotes
video/webm;codecs=vp9,opusChrome, Edge, FirefoxBest quality/bitrate
video/webm;codecs=vp8,opusChrome, FirefoxBroader VP8 compatibility
video/mp4Safari 14.1+ (partial), ChromeH.264 inside — easier to edit

Safari is the outlier — it supports MediaRecorder since 14.1 but defaults to video/mp4 and can produce files that some tools refuse to edit. If your pipeline feeds into a standard NLE or transcoder, force a WebM-compatible fallback or transcode on upload.

The Duration Trap

A 10-minute 1080p30 VP9 recording at 2.5 Mbps produces ~190 MB of chunks. In-memory buffering is fine on a desktop; on a phone it OOMs. For production:

  • Upload in chunks as dataavailable fires — send each Blob to your server, don’t accumulate.
  • Or use a Service Worker to write chunks to IndexedDB, then upload in background when the user is done.

“The start(1000) timeslice is the single line that separates a recording demo from a recording feature. Everything else is error handling.”

Chunked upload protocol, resume logic, and the Safari MP4 transcode path are in the MediaRecorder production pipeline.