How to record audio from the user's microphone
Accessing the user's camera and microphone is possible on the web platform with the Media Capture and Streams API. The getUserMedia()
method prompts the user to access a camera and/or microphone to capture as a media stream. This stream can then be recorded with the MediaRecorder API or shared with others over the network. The recording can be saved to a local file via the showOpenFilePicker()
method.
The example below shows how you can record audio from the user's microphone in the WebM format and save the recording to the user's file system.
let stream;
let recorder;
startMicrophoneButton.addEventListener("click", async () => {
// Prompt the user to use their microphone.
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
recorder = new MediaRecorder(stream);
});
stopMicrophoneButton.addEventListener("click", () => {
// Stop the stream.
stream.getTracks().forEach(track => track.stop());
});
startRecordButton.addEventListener("click", async () => {
// For the sake of more legible code, this sample only uses the
// `showSaveFilePicker()` method. In production, you need to
// cater for browsers that don't support this method, as
// outlined in https://web.dev/patterns/files/save-a-file/.
// Prompt the user to choose where to save the recording file.
const suggestedName = "microphone-recording.webm";
const handle = await window.showSaveFilePicker({ suggestedName });
const writable = await handle.createWritable();
// Start recording.
recorder.start();
recorder.addEventListener("dataavailable", async (event) => {
// Write chunks to the file.
await writable.write(event.data);
if (recorder.state === "inactive") {
// Close the file when the recording stops.
await writable.close();
}
});
});
stopRecordButton.addEventListener("click", () => {
// Stop the recording.
recorder.stop();
});
Browser support #
MediaDevices.getUserMedia() #
Browser support
- Chrome 53, Supported 53
- Firefox 36, Supported 36
- Edge 12, Supported 12
- Safari 11, Supported 11
MediaRecorder API #
Browser support
- Chrome 47, Supported 47
- Firefox 25, Supported 25
- Edge 79, Supported 79
- Safari 14, Supported 14
File System Access API's showSaveFilePicker() #
Browser support
- Chrome 86, Supported 86
- Firefox, Not supported
- Edge 86, Supported 86
- Safari, Not supported
Further reading #
- W3C Media Capture and Streams Specification
- W3C MediaStream Recording Specification
- WICG File System Access Specification
Demo #
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="icon"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🎙️</text></svg>"
/>
<title>How to record audio from the user's microphone</title>
</head>
<body>
<h1>How to record audio from the user's microphone</h1>
<button id="startMicrophoneButton">Start using microphone</button>
<button id="stopMicrophoneButton" disabled>Stop using microphone</button>
<button id="startRecordButton" disabled>Start recording</button>
<button id="stopRecordButton" disabled>Stop recording</button>
<pre id="logs"></pre>
</body>
</html>
const startMicrophoneButton = document.querySelector('#startMicrophoneButton');
const stopMicrophoneButton = document.querySelector('#stopMicrophoneButton');
const startRecordButton = document.querySelector('#startRecordButton');
const stopRecordButton = document.querySelector('#stopRecordButton');
let stream;
let recorder;
startMicrophoneButton.addEventListener("click", async () => {
// Prompt the user to use their microphone.
stream = await navigator.mediaDevices.getUserMedia({ audio: true });
recorder = new MediaRecorder(stream);
stopMicrophoneButton.disabled = false;
startRecordButton.disabled = false;
log("Your microphone audio is being used.");
});
stopMicrophoneButton.addEventListener("click", () => {
// Stop the stream.
stream.getTracks().forEach(track => track.stop());
startRecordButton.disabled = true;
stopRecordButton.disabled = true;
log("Your microphone audio is not used anymore.");
});
startRecordButton.addEventListener("click", async () => {
// For the sake of more legible code, this sample only uses the
// `showSaveFilePicker()` method. In production, you need to
// cater for browsers that don't support this method, as
// outlined in https://web.dev/patterns/files/save-a-file/.
// Prompt the user to choose where to save the recording file.
const suggestedName = "microphone-recording.webm";
const handle = await window.showSaveFilePicker({ suggestedName });
const writable = await handle.createWritable();
// Start recording.
recorder.start();
recorder.addEventListener("dataavailable", async (event) => {
// Write chunks to the file.
await writable.write(event.data);
if (recorder.state === "inactive") {
// Close the file when the recording stops.
await writable.close();
}
});
stopRecordButton.disabled = false;
log("Your microphone audio is being recorded locally.");
});
stopRecordButton.addEventListener("click", () => {
// Stop the recording.
recorder.stop();
stopRecordButton.disabled = true;
log("Your microphone audio has been successfully recorded locally.");
});
:root {
color-scheme: dark light;
}
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 1rem;
font-family: system-ui, sans-serif;
}
button {
display: block;
margin-bottom: 4px;
}
pre {
color: red;
white-space: pre-line;
}