How to Build a Browser Screen Recorder with the MediaRecorder API
This guide explains how to use the native MediaRecorder API to capture screen, audio, or canvas streams in the browser, walk through a three‑step implementation—getting the stream, recording it, and handling the output—and shares best practices for compatibility, MIME types, user permissions, resource cleanup, and performance.
In the past, implementing screen‑recording on a web page required complex browser plugins, desktop applications, or paid third‑party services, increasing both user friction and developer effort. Today, the powerful native MediaRecorder API provides a streamlined solution.
What is the MediaRecorder API?
MediaRecorder, part of the WebRTC stack, receives a MediaStream and encodes it into formats such as WebM or MP4, outputting the data as Blob chunks.
Media streams can originate from many sources, including:
User camera and microphone ( navigator.mediaDevices.getUserMedia)
User screen, window, or tab ( navigator.mediaDevices.getDisplayMedia)
HTML <video> or <audio> elements
Dynamically generated Canvas elements
The screen‑recording feature specifically leverages the second source— getDisplayMedia API.
Build a basic screen‑recording feature in three steps
The core workflow is: Get stream → Record stream → Process result .
Step 1: Obtain a screen‑sharing MediaStream
Prompt the user for permission and request the screen, window, or tab stream using getDisplayMedia. This call must be triggered by a user interaction.
async function getScreenStream() {
try {
// Prompt user to select screen or window
const stream = await navigator.mediaDevices.getDisplayMedia({
video: true, // capture video
audio: true // optionally capture audio
});
return stream;
} catch (error) {
console.error("Failed to get screen sharing:", error);
alert("You cancelled screen sharing or an error occurred.");
return null;
}
}Note: getDisplayMedia must be called from a user‑initiated action (e.g., button click), otherwise browsers will block it for security reasons.
Step 2: Create a MediaRecorder instance and start recording
After acquiring the MediaStream, instantiate a MediaRecorder to begin capturing.
Step 3: Stop recording and handle the result
When the user stops sharing or clicks a stop button, call mediaRecorder.stop(). Recorded chunks accumulate in the recordedChunks array; combine them into a single Blob to produce the final video file.
// Stop recording function
function stopRecording() {
if (mediaRecorder && mediaRecorder.state !== 'inactive') {
mediaRecorder.stop();
}
}
// Process recorded data
function handleRecordingStop() {
// Merge all chunks into a Blob
const recordedBlob = new Blob(recordedChunks, { type: 'video/webm' });
const videoUrl = URL.createObjectURL(recordedBlob);
// Create a download link
const downloadLink = document.createElement('a');
downloadLink.href = videoUrl;
downloadLink.download = `recording-${new Date().toISOString()}.webm`;
downloadLink.textContent = 'Download recording';
document.body.appendChild(downloadLink);
// Or create a video element for preview
const previewVideo = document.createElement('video');
previewVideo.src = videoUrl;
previewVideo.controls = true;
document.body.appendChild(previewVideo);
// Clean up for next recording
recordedChunks = [];
}Integrating these steps with UI buttons (Start, Stop) yields a complete web‑based screen‑recording application.
The MediaRecorder API can also be used for user feedback and bug reproduction, online education, live demos, and more.
Considerations and best practices
Browser compatibility: MediaRecorder is widely supported in modern browsers (Chrome, Firefox, Edge, Safari), but always verify support and provide graceful fallbacks for unsupported environments.
MIME types: Different browsers support different mimeType s. Use MediaRecorder.isTypeSupported() to check availability; video/webm offers the broadest compatibility.
User authorization: Invoke getDisplayMedia only after explicit user interaction and clearly explain why the permission is needed.
Resource management: After recording, call URL.revokeObjectURL() to free the created URL and stop all tracks with stream.getTracks().forEach(track => track.stop()) to turn off camera or screen‑sharing indicators.
Performance considerations: Long or high‑resolution recordings consume significant memory and CPU. For upload scenarios, consider chunked uploading instead of waiting for the entire file.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JavaScript
Provides JavaScript enthusiasts with tutorials and experience sharing on web front‑end technologies, including JavaScript, Node.js, Deno, Vue.js, React, Angular, HTML5, CSS3, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
