๐ฅ Stream and Store Screen Recordings in WebM Chunks Using MediaRecorder API + RecordRTC
Recording screen activity from the browser and streaming it in chunks can be trickyโโโespecially if your goal is to process each chunkโฆ
๐ฅ Stream and Store Screen Recordings in WebM Chunks Using MediaRecorder API + RecordRTC
Recording screen activity from the browser and streaming it in chunks can be tricky โ especially if your goal is to process each chunk independently (like extracting audio or processing metadata). While the MediaRecorder API makes recording possible, the chunks it generates (after the first one) often lack essential metadata headers. This causes issues when you try to process or extract audio from those chunks using tools like FFmpeg.
Recently, I faced this challenge and solved it by combining the MediaRecorder API with RecordRTC, ensuring every chunk remains self-contained and independently processable.
Hereโs a breakdown of how I tackled the problem:
๐น Step 1: Get the Screen Stream
First, use the MediaDevices API to prompt the user for screen access. We reuse the same stream for all chunks to avoid re-prompting the user every time.
let screenStream = null;
async function getScreenStream() {
if (!screenStream) {
screenStream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: true,
});
console.log("Screen stream initialized.");
}
return screenStream;
}
๐น Step 2: Record the Stream in Chunks
The core of the solution is using RecordRTCPromisesHandler from RecordRTC. By specifying a timeSlice, it creates consistent, self-contained chunks every few seconds.
let isRecording = false;
async function startScreenRecording() {
console.log("Starting screen recording...");
let recordedChunks = [];
try {
if (isRecording) return;
isRecording = true;
const stream = await getScreenStream();
const recorder = new RecordRTCPromisesHandler(stream, {
type: "video",
mimeType: "video/webm",
timeSlice: 20000, // Record in 20s chunks
});
await recorder.startRecording();
setTimeout(async () => {
await recorder.stopRecording();
isRecording = false;
const blob = await recorder.getBlob();
console.log("Recording stopped, sending file...");
if (!blob || !(blob instanceof Blob)) {
console.error("Error: Invalid Blob received.");
return;
}
await sendChunksToServer(blob);
startScreenRecording(); // Loop to keep recording continuously
}, 20000);
} catch (err) {
console.error("Error accessing media devices:", err);
}
}
๐น Step 3: Upload Each Chunk to Your Server
Each chunk is uploaded right after itโs recorded using a simple fetch request and FormData.
async function sendChunksToServer(blob) {
try {
const formData = new FormData();
formData.append("video_chunk", blob, "chunk.webm");
const response = await fetch("https://yourserver.com/upload", {
method: "POST",
body: formData,
});
if (!response.ok) throw new Error("Failed to upload chunk");
console.log("Chunk uploaded successfully.");
} catch (error) {
console.error("Error uploading chunk:", error);
}
}
๐ Why This Works
- โ The stream is initialized once and reused across chunks.
- โ RecordRTC ensures that each chunk includes necessary metadata.
- โ The recording loop runs continuously without user interruption.
- โ
Each chunk is independently processable โ no more
EBML header parsing failederrors in FFmpeg.
๐ง Bonus Tips
- Want to extract audio from each chunk using FFmpeg? You can now directly do:
ffmpeg -i chunk.webm -vn -acodec libmp3lame output.mp3
- To stop the recording loop gracefully, keep a
shouldRecordflag. - You can extend this flow to stream to cloud storage or convert chunks on the server.
If youโre building a screen recording app or browser-based streaming tool, this approach gives you smooth chunked recording with real-time upload and easy processing โ without dealing with metadata headaches.
If you found this helpful, please give it a ๐ and share it with others who might benefit!
Thank you for being a part of the community
Before you go:
- Be sure to clap and follow the writer ๏ธ๐๏ธ๏ธ
- Follow us: **X | [LinkedIn](https://www.linkedin.com/company/inplainenglish/) | [YouTube](https://www.youtube.com/@InPlainEnglish) | [Newsletter](https://newsletter.plainenglish.io/) | [Podcast](https://open.spotify.com/show/7qxylRWKhvZwMz2WuEoua0) | [Twitch](https://twitch.tv/inplainenglish)**
- **Start your own free AI-powered blog on Differ** ๐
- **Join our content creators community on Discord** ๐ง๐ปโ๐ป
- For more content, visit **plainenglish.io + [stackademic.com](https://stackademic.com/)**
๋ฉํ๋ฐ์ดํฐ
- post_id
- 4e2dc188f23b
- slug
- stream-and-store-screen-recordings-in-webm-chunks-using-mediarecorder-api-recordrtc-4e2dc188f23b
- url
- https://javascript.plainenglish.io/stream-and-store-screen-recordings-in-webm-chunks-using-mediarecorder-api-recordrtc-4e2dc188f23b
- canonical_url
- https://javascript.plainenglish.io/stream-and-store-screen-recordings-in-webm-chunks-using-mediarecorder-api-recordrtc-4e2dc188f23b
- author_url
- https://medium.com/@mudit.alwar31
- status
- ok
- fetched_at
- 2026-06-25 12:15:08