How to Create a Video and Audio Recorder with JavaScript MediaRecorder API?

In this tutorial, you will learn how to create an audio and video recorder using JavaScript's MediaRecorder API with WebRTC technology. This allows you to capture and record media directly in the browser.

What is WebRTC?

WebRTC (Web Real-Time Communication) enables real-time communication capabilities in web browsers. It allows access to user devices like webcams and microphones through JavaScript APIs.

The core method for accessing media devices is:

navigator.mediaDevices.getUserMedia(constraints)

The getUserMedia() function requests user permission to access the webcam and microphone. It returns a Promise that resolves with a MediaStream if permission is granted, or rejects if denied.

HTML Structure

Our interface includes:

  • Video Section: A video element to display the live stream, plus start/stop buttons

  • Audio Section: Start/stop buttons for audio recording

  • Font Awesome icons: For attractive play/stop button styling

Example: Complete HTML Structure

<!DOCTYPE html>
<html>
<head>
   <title>Video & Audio Recorder</title>
   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
   <style>
      body {
         text-align: center;
         font-family: Arial, sans-serif;
         margin: 20px;
      }
      
      h1 {
         color: #2196F3;
         margin-bottom: 30px;
      }
      
      .recorder-section {
         margin: 30px 0;
         padding: 20px;
         border: 2px solid #ddd;
         border-radius: 10px;
         background: #f9f9f9;
      }
      
      video {
         background-color: #333;
         border-radius: 8px;
         margin: 10px 0;
         width: 480px;
         height: 320px;
      }
      
      audio {
         margin: 10px 0;
         width: 300px;
      }
      
      button {
         margin: 10px;
         padding: 12px 20px;
         border: none;
         border-radius: 25px;
         cursor: pointer;
         font-size: 16px;
         transition: all 0.3s;
      }
      
      .start-btn {
         background: #4CAF50;
         color: white;
      }
      
      .stop-btn {
         background: #f44336;
         color: white;
      }
      
      button:disabled {
         background: #ccc;
         cursor: not-allowed;
      }
      
      .recorded-media {
         margin: 15px 0;
         padding: 10px;
         background: white;
         border-radius: 5px;
      }
   </style>
</head>
<body>
   <h1>Video & Audio Recorder</h1>
   
   <div class="recorder-section" id="vid-recorder">
      <h3>Record Video</h3>
      <video autoplay muted id="vidBox"></video><br>
      
      <button type="button" class="start-btn" id="video_st" onclick="startVideoRecording()">
         <i class="fa fa-play"></i> Start Video
      </button>
      
      <button type="button" class="stop-btn" id="video_en" disabled onclick="stopRecording('video')">
         <i class="fa fa-stop"></i> Stop Video
      </button>
      
      <div id="video-recordings"></div>
   </div>
   
   <div class="recorder-section" id="audio_rec">
      <h3>Record Audio</h3>
      
      <button type="button" class="start-btn" id="aud_st" onclick="startAudioRecording()">
         <i class="fa fa-play"></i> Start Audio
      </button>
      
      <button type="button" class="stop-btn" id="aud_en" disabled onclick="stopRecording('audio')">
         <i class="fa fa-stop"></i> Stop Audio
      </button>
      
      <div id="audio-recordings"></div>
   </div>

   <script>
      let mediaRecorder;
      let recordedChunks = [];
      let currentStream;

      async function startVideoRecording() {
         try {
            const stream = await navigator.mediaDevices.getUserMedia({
               video: true,
               audio: true
            });
            
            currentStream = stream;
            document.getElementById('vidBox').srcObject = stream;
            
            recordedChunks = [];
            mediaRecorder = new MediaRecorder(stream);
            
            mediaRecorder.ondataavailable = (event) => {
               if (event.data.size > 0) {
                  recordedChunks.push(event.data);
               }
            };
            
            mediaRecorder.onstop = () => {
               const blob = new Blob(recordedChunks, { type: 'video/webm' });
               createVideoElement(blob);
               stopAllTracks();
            };
            
            mediaRecorder.start(100);
            
            document.getElementById('video_st').disabled = true;
            document.getElementById('video_en').disabled = false;
            
         } catch (error) {
            console.error('Error accessing video:', error);
            alert('Could not access camera. Please check permissions.');
         }
      }

      async function startAudioRecording() {
         try {
            const stream = await navigator.mediaDevices.getUserMedia({
               audio: true,
               video: false
            });
            
            currentStream = stream;
            recordedChunks = [];
            mediaRecorder = new MediaRecorder(stream);
            
            mediaRecorder.ondataavailable = (event) => {
               if (event.data.size > 0) {
                  recordedChunks.push(event.data);
               }
            };
            
            mediaRecorder.onstop = () => {
               const blob = new Blob(recordedChunks, { type: 'audio/webm' });
               createAudioElement(blob);
               stopAllTracks();
            };
            
            mediaRecorder.start(100);
            
            document.getElementById('aud_st').disabled = true;
            document.getElementById('aud_en').disabled = false;
            
         } catch (error) {
            console.error('Error accessing audio:', error);
            alert('Could not access microphone. Please check permissions.');
         }
      }

      function stopRecording(type) {
         if (mediaRecorder && mediaRecorder.state !== 'inactive') {
            mediaRecorder.stop();
         }
         
         if (type === 'video') {
            document.getElementById('video_st').disabled = false;
            document.getElementById('video_en').disabled = true;
            document.getElementById('vidBox').srcObject = null;
         } else {
            document.getElementById('aud_st').disabled = false;
            document.getElementById('aud_en').disabled = true;
         }
      }

      function stopAllTracks() {
         if (currentStream) {
            currentStream.getTracks().forEach(track => track.stop());
            currentStream = null;
         }
      }

      function createVideoElement(blob) {
         const videoElement = document.createElement('video');
         videoElement.controls = true;
         videoElement.className = 'recorded-media';
         videoElement.style.width = '400px';
         videoElement.style.height = '240px';
         
         const url = URL.createObjectURL(blob);
         videoElement.src = url;
         
         const downloadLink = createDownloadLink(blob, 'video.webm');
         const container = document.createElement('div');
         container.appendChild(videoElement);
         container.appendChild(downloadLink);
         
         document.getElementById('video-recordings').appendChild(container);
      }

      function createAudioElement(blob) {
         const audioElement = document.createElement('audio');
         audioElement.controls = true;
         audioElement.className = 'recorded-media';
         
         const url = URL.createObjectURL(blob);
         audioElement.src = url;
         
         const downloadLink = createDownloadLink(blob, 'audio.webm');
         const container = document.createElement('div');
         container.appendChild(audioElement);
         container.appendChild(downloadLink);
         
         document.getElementById('audio-recordings').appendChild(container);
      }

      function createDownloadLink(blob, filename) {
         const downloadLink = document.createElement('a');
         downloadLink.href = URL.createObjectURL(blob);
         downloadLink.download = filename;
         downloadLink.textContent = 'Download';
         downloadLink.style.margin = '0 10px';
         downloadLink.style.color = '#2196F3';
         return downloadLink;
      }
   </script>
</body>
</html>

Key MediaRecorder API Methods

The MediaRecorder API provides these essential methods:

  • start() - Begins recording the media stream

  • stop() - Stops recording and triggers the onstop event

  • ondataavailable - Event fired when recorded data is available

  • onstop - Event fired when recording stops

How It Works

The recording process follows these steps:

  1. Request Permission: getUserMedia() asks for camera/microphone access

  2. Create MediaRecorder: Initialize with the media stream

  3. Start Recording: mediaRecorder.start() begins capture

  4. Collect Data: ondataavailable stores chunks of recorded data

  5. Stop & Save: onstop creates a Blob and generates playable media

Error Handling

Always include error handling for common issues:

try {
   const stream = await navigator.mediaDevices.getUserMedia(constraints);
   // Handle successful stream
} catch (error) {
   if (error.name === 'NotAllowedError') {
      console.log('User denied permission');
   } else if (error.name === 'NotFoundError') {
      console.log('No media devices found');
   }
}

Browser Compatibility

MediaRecorder API is supported in:

  • Chrome 47+

  • Firefox 25+

  • Safari 14+

  • Edge 79+

Conclusion

The MediaRecorder API with WebRTC provides a powerful way to create audio and video recording applications directly in the browser. With proper error handling and user permission management, you can build robust media capture functionality for web applications.

Updated on: 2026-03-15T23:19:00+05:30

5K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements