Person in anime style yelling getUserMedia()

Getting Started with getUserMedia In 2025

One of the features enabling today's modern web is getUserMedia(), a powerful JavaScript method that allows developers to access the user's camera and microphone directly from the browser.

The method has been implemented in browsers since 2012, and over the last 13 years, it has evolved significantly. The method is now core to WebRTC video conferencing, live streaming, taking photos, grabbing video frames, augmented reality, and audio and video recording via powerful services like the Pipe Recording Platform.

This article will cover what you need to know, as a developer, before and after calling getUserMedia().

Table of Contents

  1. Before The Call: Secure Contexts and Permissions
  2. Old variant: navigator.getUserMedia()
  3. Getting a Media Stream
  4. Getting a List of Available Devices
  5. Listening for Device Changes
  6. Working with Media Streams
  7. Video and Audio Codecs
  8. Understanding the Constraints Object
  9. Handling getUserMedia Errors
  10. Browser Compatibility

Before The Call: Secure Contexts and Permissions

Several gatekeepers safeguard the ability to access a user's devices to protect the user's privacy.

Secure Context Requirement

The first thing you need to know is that the getUserMedia method is only available in secure contexts. What this means exactly is that your code must be served in one of the following ways:

  • Using HTTPS: the page is served via https://
  • Local resources, such as the following origins: http://localhost, http://127.0.0.1, or file URLS ( file://)

Failing to run/host your code in one of the above secure contexts will prevent getUserMedia from accessing the user's camera or microphone on modern browsers.

Permissions Policy (former Feature Policy)

Chromium browsers (Chrome, Edge, Opera, etc.) implement the Permissions Policy (formerly known as Feature Policy). Such a policy can be used to control which features are enabled in different parts of a website. For example, the policy can be configured to block access to the camera and/or microphone, as a result, interfering with your getUserMedia calls.

Some environments, like cross origin iframes, will have restrictive policies by default and will block capturing the camera or microphone. In other environments, you might hit a manually imposed permission policy.

To further familiarize yourself with how it works, check out the following materials we've written on the topic:

  1. Camera and Microphone Access In Cross Origin Iframes With getUserMedia
  2. Recommended Permissions-Policy Settings

Browser and OS Permissions

To access the user's media devices, the user must grant explicit permission at both the browser and OS levels. These permission prompts will change over time as browsers evolve and mature, so it is essential to keep track of them to ensure this important step is handled carefully and covers both grant and deny cases.

Browser Level Permissions

Every browser has a different permission dialog which behaves a bit differently. Chrome and Firefox permissions are persistent by default at the browser tab/session level. Firefox will ask permission for every individual device and always allowed you to change the shared device directly in the permission prompt. Safari's permissions are the least persistent.

OS Level Permissions

OS level permissions are prominent on macOS, where every non-Safari browser needs to be given individual permission by the user to capture the microphone, camera, and the screen & system sounds and then it needs to be restarted. But Windows 10 and 11 also have controls for preventing apps from accessing the camera and microphone.

Future <permission> tag

Calling getUserMedia() is what currently triggers the permission prompt but this might change in the near future with the introduction of the <permission> HTML tag.

Permissions API

You can use the Permissions API to track the status of permissions in the current context. If you're interested in learning how to detect how often users allow or deny camera and microphone access, you can read this post, and you can further delve into finding out more about getUserMedia camera and microphone initialization times.

Old Variant: navigator.getUserMedia()

You might encounter very old tutorials, code or documentation that mention the callback based navigator.getUserMedia(). The functionality has been moved to the promise based navigator.mediaDevices.getUserMedia() - with Chrome this happened in Chrome 53 - and it's the version you should be using (even tough the older syntax might still be supported).

Getting a Media Stream

Now that you are in a secure context and have navigated through all the permission hoops, you can finally gain access to the user's devices and obtain the prize: the media stream.

To do so, you must call navigator.mediaDevices.getUserMedia(). This method takes a MediaStreamConstraints object as a parameter, which allows you to specify the type of media you want to access: audio, video, or both. Optionally, you can add specific granular requirements for both video and audio like the frame rate, resolution or preferred camera (front or back) on mobile devices.

We will cover constraints in a bit more detail later. For now, here is a basic example of how to get the video and audio stream from a webcam:

const constraints = {
  video: true,
  audio: true
};

navigator.mediaDevices.getUserMedia(constraints)
  .then(stream => {
    // You have a media stream, attribute it to the HTML video element
    const videoElement = document.querySelector('video');
    videoElement.srcObject = stream;
  })
  .catch(error => {
    // Handle errors
    console.error('Error accessing media devices.', error);
  });

Note that getUserMedia returns a Promise. This means you need to use .then() and .catch() to handle both success and failure cases.

Handling getUserMedia Errors

In the code above, there's a catch statement, which, in a production environment, needs to be extended to gracefully handle a few common situations:

  1. When no camera or microphone device exists you'll be met with a NotFoundError.
  2. The camera device is already in use by another app results in a NotReadableError.
  3. When the user has not granted permissions at the browser or OS level will result in a NotAllowedError.
  4. Specific constraints cannot be met (exact resolution, aspect ratio or fps, etc.), an OverconstrainedError will be thrown.

We go over the getUserMedia errors in more detail in a separate post.

Even after a successful getUserMedia call, you might encounter error situations that need to be handled:

  1. User mutes, disables or pulls out the camera or microphone device
  2. User's device disconnects from Bluetooth or is out of battery (the iPhone can be used as a camera)
  3. Computer/laptop is left unattended and it goes to sleep while device is accessed

Our own Pipe recording client handles many of these errors.

Getting a List of Available Devices

It is crucial to give your users the option to choose which camera and microphone they want to grant access to and use. Once permission is given, you can list the available media devices by calling navigator.mediaDevices.enumerateDevices(). This method will return an array of MediaDeviceInfo objects, and each of them will contain information about one particular device.

Here is a quick example:

navigator.mediaDevices.enumerateDevices()
  .then(devices => {
    devices.forEach(device => {
      console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
    });
  })
  .catch(error => {
    console.error('Error enumerating devices.', error);
  });

This apparently simple functionality is important for any app. Allowing users to choose their preferred camera and microphone devices is crucial for ensuring privacy and that the correct device is used.

We've worked hard to build one of the best camera and microphone selectors for our Pipe recording client.

Listening for Device Changes

But what happens if a user plugs in a new microphone or connects a new Bluetooth headset while your application is running or after you've called enumerateDevices()? This is where the ondevicechange event handler comes in, which can be attached to the navigator.mediaDevices object:

navigator.mediaDevices.ondevicechange = event => {
  // Handle device change
  console.log('A media device has been connected or disconnected.');
  // You can then call enumerateDevices() again to get the updated list
};

With it, you can gracefully handle changes in the list of devices.

Working with Media Streams

After getUserMedia is called successfully, you receive a MediaStream object that allows you to perform various actions. Here are a few examples:

  • Show the stream in an HTML video element: This is the most basic use case, but it is a great way to provide immediate feedback of the user's camera and microphone.
  • Send the stream over WebRTC: This implementation will enable real-time peer-to-peer communication with other users, allowing for video and audio calls. Integrations with services like OpenAI's Realtime API are another good example of streaming over WebRTC.
  • Record the stream using the MediaStream Recording API to easily create and store video or audio files.
  • Process the stream in real time with the Canvas API for advanced visual effects (e.g., background blurring), image recognition, or analytical data gathering.
  • Capture a frame using ImageCapture.grabFrame() or a photo using ImageCapture.takePhoto()

At Pipe, we've developed a robust raudio and video recording client that does much of the heavy lifting for you, allowing for seamless recording of video, audio, and screen directly from the browser. This way, our clients can focus on implementing their solutions instead of navigating the complexity of accessing the devices, recording, streaming, storage, etc..

Video and Audio Codecs

After capturing the audio and video streams via getUserMedia method, using those streams in WebRTC or recording them will result in the data being encoded using varying audio and video codecs (and containers).

For example, when recording the stream using the MediaStream Recording API, there's a bunch of codecs and containers that are available for audio and video encoding.

Here's a summary with the maximal audio and video capabilities of current major browsers:

BrowserContainerVideo CodecsAudio Codecs
Google Chromemp4 or webmVP8, VP9, H.264, HEVC (H.265), AV1Opus, PCM
Mozilla FirefoxwebmVP8Opus
Apple Safariwebm, mp4H264, VP8, VP9, HEVC (H.265), AV1AAC, Opus

Keep in mind, the available codecs differ based on the browser, OS and hardware capabilities. On a simple getUserMedia() implementation you might get mp4 with H.264 and AAC audio from Safari and a webm with H.265 and Opus from Chrome. You will definitely get VP8 video from Firefox.

Our MediaStream Recording API demo has been updated so that you can play with these codecs and test what your current browser/OS/hardware support.

Given the variety of possible codec combinations, in order to ensure maximum compatibility across devices, dedicated video recording platforms like Pipe will transcode the captured stream, server side, to a cross platform compatible .mp4 file.

Understanding the Constraints Object

Remember when we talked earlier about the constraints object (MediaStreamConstraints actually) that is being passed to getUserMedia ? This object is key to getting the media stream that best fits the needs of your applications.

The most important thing to know about the constraints object is that it allows you to request certain media characteristics, but these are requests, not commands. The browser will do its best to meet your constraints, but the results may vary depending on the device's hardware capabilities.

The simplest constraints that you can specify are, as seen in the example we gave earlier, { video: true, audio: true } .

You can also specify detailed requirements for:

  • Video constraints: You can request a specific resolution (width, height), framerate, aspectRatio or facingMode (useful for selecting specific cameras on mobile devices)
  • Audio constraints: You can control features like echoCancellation, noiseSuppression , and autoGainControla
  • Screen constraints: When it comes to screen capture, the counterpart for getUserMedia , is getDisplayMedia . Similarly, you can specify constraints for it. We will cover the specifics in an upcoming post.

For a deep dive into each type of constraint, you can check out our detailed articles on video constraints, audio constraints, and our examples page to see some of them in action.

Browser-Level Support: getSupportedConstraints()

There is a helpful function to learn which constraints the browser itself supports, before even attempting to request a certain constraint.

navigator.mediaDevices.getSupportedConstraints() will return an object containing keys with the name of the constraint and their values, either true or false :

const supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
console.log(supportedConstraints);
// { "width": true, "height": true, "aspectRatio": true, ... }

Device-Level Capabilities: getCapabilities()

You can query the capabilities of the active camera or microphone directly. This can only be done once you get hold of the media stream, by calling the function getCapabilities() on the MediaStreamTrack .

This method will return a range of values that the device can support for each constraint (e.g, the minimum and maximum video resolution).

// We assume you already have a stream object from getUserMedia()
const videoTrack = stream.getVideoTracks()[0];
const capabilities = videoTrack.getCapabilities();

console.log(capabilities);
// {
//   "width": { "min": 1, "max": 1920 },
//   "height": { "min": 1, "max": 1080 },
//   "frameRate": { "min": 0, "max": 30 },
//   ...
// }

Together, these two functions can help you build more robust applications. For example, you can display only the options that the user's hardware actually supports.

Browser Compatibility

The core getUserMedia functionality has the advantage of being well-established with wide browser support including Chrome, Firefox, Safari, Edge, Brave, Opera, etc. .

Other parts of the getUserMedia tech might not have as wide a support, so it is always wise to check with services like caniuse.com when making your implementation.

Getting Started with getUserMedia In 2025
Share this
IT TAKES 1 MINUTE
Sign up for a 14 Day Trial

With our 14 days (336 hours) trial you can add audio, video and screen + camera recording to your website today and explore Pipe for 2 weeks