MediaRecorder and microphone permissions

Recording audio in the browser has been a native feature since 2016, but the docs are scattered. The key pieces are getUserMedia for microphone access and MediaRecorder for capture. Once you own these two APIs, everything else is plumbing.

Browser recording lifecycle

From permission prompt to a Blob ready for upload.

frontend/src/App.tsx
typescript
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });

mediaRecorderRef.current = new MediaRecorder(stream);
chunksRef.current = [];

getUserMedia triggers the browser permission prompt. If the user grants access, you get a MediaStream you can hand to MediaRecorder. The stream stays live until you stop its tracks.

Microphone access is a powerful permission. Browsers restrict getUserMedia to secure contexts so attackers cannot silently record users from a man-in-the-middle position. Localhost is treated as secure for development, but production must be served over HTTPS.

frontend/src/App.tsx
typescript
try {
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  // ... set up recorder
} catch (err) {
  const errorMessage = err instanceof Error ? err.message : 'Unknown error';
  setError('Microphone access denied: ' + errorMessage);
}

Always wrap getUserMedia in a try/catch. Users deny permission, browsers block insecure contexts, and laptops sometimes have no microphone at all. Surface the failure instead of hanging.

Quiz: Quiz

Loading practice…