JavaScript MediaRecorder API: Capture Audio and Video
The MediaRecorder API provides a native JavaScript interface for
capturing real-time audio and video streams directly within web browsers
without relying on external plugins. This article explains what the
MediaRecorder interface is and details the step-by-step
mechanism JavaScript uses to record MediaStream tracks,
collect binary data chunks during recording, and assemble them into a
final Blob for playback, download, or server upload.
What is the MediaRecorder API?
The MediaRecorder interface is a core component of the
MediaStream Recording API. It allows developers to capture media
generated by webcams, microphones, canvas elements, or screen sharing
via navigator.mediaDevices.getUserMedia() or
navigator.mediaDevices.getDisplayMedia().
Unlike older approaches that required sending raw canvas frames or
WebAudio buffers to external encoders, MediaRecorder
handles the encoding process natively in the browser, producing
compressed formats such as WebM or MP4.
How Media Streams Become Blobs: The Step-by-Step Process
Capturing a stream and outputting it as a Blob follows a
clear four-step lifecycle:
[Media Stream] ──> [MediaRecorder] ──> [dataavailable: chunks[]] ──> [stop: new Blob(chunks)]
1. Obtaining the MediaStream
First, the application requests access to audio and video inputs from
the user. This returns a MediaStream object containing
individual audio and video tracks.
const stream = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true
});2. Initializing the MediaRecorder
An instance of MediaRecorder is created by passing the
active MediaStream and optional configuration options, such
as the target MIME type and bitrate.
const options = { mimeType: 'video/webm; codecs=vp9' };
const mediaRecorder = new MediaRecorder(stream, options);3. Collecting Data
Chunks (ondataavailable)
When recording starts via mediaRecorder.start(), the
recorder begins encoding data in the background. As encoded data becomes
available, the dataavailable event fires, providing a
Blob slice containing a portion of the recording. These
chunks are stored in an array.
const recordedChunks = [];
mediaRecorder.ondataavailable = (event) => {
if (event.data && event.data.size > 0) {
recordedChunks.push(event.data);
}
};You can pass a time interval (in milliseconds) to
mediaRecorder.start(1000) to trigger the
dataavailable event periodically, or omit it to fire the
event only when recording stops.
4. Assembling the Final Blob
(onstop)
When mediaRecorder.stop() is called, the recorder
finishes processing the remaining stream buffer. The stop
event listener then combines the array of binary chunks into a single
unified Blob.
mediaRecorder.onstop = () => {
const completeBlob = new Blob(recordedChunks, { type: 'video/webm' });
// Create a local URL for playback or download
const videoURL = URL.createObjectURL(completeBlob);
const videoElement = document.querySelector('video');
videoElement.src = videoURL;
};Practical Complete Example
async function recordStream(durationMs = 5000) {
// 1. Get user media
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
// 2. Instantiate recorder
const recorder = new MediaRecorder(stream);
const chunks = [];
// 3. Collect chunks
recorder.ondataavailable = (e) => chunks.push(e.data);
// 4. Handle completion
recorder.onstop = () => {
const finalBlob = new Blob(chunks, { type: recorder.mimeType });
console.log('Recording complete. Blob size:', finalBlob.size);
// Stop all tracks to release camera/mic hardware
stream.getTracks().forEach(track => track.stop());
};
// Start recording, record for specified duration, then stop
recorder.start();
setTimeout(() => recorder.stop(), durationMs);
}Working with the Resulting Blob
Once the binary data is compiled into a Blob, it can be
utilized in several ways:
- Playback: Generate an object URL using
URL.createObjectURL(blob)and assign it to thesrcattribute of an<audio>or<video>tag. - Download: Attach the object URL to a hidden
<a>element with adownloadattribute and programmatically trigger a click event. - Upload: Append the
Blobdirectly to aFormDatainstance and transmit it to a backend server usingfetch()orXMLHttpRequest.