Accessing a device's camera and microphone with JavaScript

- 👤 Andrés Cruz

🇪🇸 En español

Accessing a device's camera and microphone with JavaScript

When I first discovered that HTML5 allowed opening the camera without plugins, I thought exactly what you're probably thinking now: "this is fascinating." Being able to access the user's video and audio directly from JavaScript changed the way we build web applications, from QR code readers to video calls or image capture systems, and all this brings us closer to what the use of native apps is from web apps.

In this guide, I'm going to teach you, step-by-step, how to access the camera and microphone with JavaScript using the modern API, how to show the stream in a <video>, how to capture a photo with <canvas>, and how to solve the typical errors we've all suffered from at some point.

This is a fascinating feature that the HTML5 API with Canvas brings with it, and it consists of the possibility of accessing the camera and microphone (with prior user approval) of the computer or mobile device without the need to use any plugin; in this article we will learn how to access a device's camera and direct this data stream into a <video> tag; basically we are going to take a capture or image through the user's camera.

Requirements, permissions, and limitations (HTTPS, compatibility, common errors)

Before getting into the code, there are three key rules:

  • You Need HTTPS
    • Browsers do not allow opening the camera from pages served as file://. Believe me, the first time I tried it from a loose file I went crazy: the code was perfect, but the camera simply didn't appear.
  • The user must always approve the permission
    • When you call getUserMedia(), the browser will display a popup asking for access to the camera and/or microphone.
  • Modern Compatibility
    • Today everything is done with navigator.mediaDevices.getUserMedia().
      The version with prefixes (navigator.webkitGetUserMedia, etc.) is obsolete.

How to access the camera with JavaScript

The basis of everything is navigator.mediaDevices.getUserMedia(). This method receives an object called constraints that specifies what you want to activate: video, audio, or both.

The navigator.getUserMedia object from HTML5

Some typical configurations before starting, which depend on what you want to activate; this is typical for a webcam:

{ video: true, audio: false } // Only video 
{ video: false, audio: true } // Only microphone 
{ video: true, audio: true// Video + audio

The first thing we must do is configure the JavaScript; the code that accesses the camera of the computer or device using the corresponding prefixes to maintain compatibility between the most used web browsers (Google Chrome, Mozilla Firefox and Internet Explorer):

  navigator.getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);

Once the getUserMedia object has been created in the previous step, the next thing is to initialize it with the following parameters:

  • constraints: this object takes two boolean parameters: video and audio; as you can imagine, we must specify at least one of them to obtain the data stream we want to access; possible cases:
    • { video: true, audio: true }: We enable both options; therefore, the data stream will provide us with video and audio.
    • { video: true, audio: false }: We enable only the video; therefore, the data stream will provide us with only video.
    • { video: false, audio: true }: We enable only the audio; therefore, the data stream will provide us with only audio.
    • { video: false, audio: false}: This option is NOT valid.
      • successCallback: This function is called if the user allows access to their camera and/or microphone and when the data stream has been loaded; therefore, this function will provide us with a LocalMediaStream object that contains the data stream to be manipulated and assigned to the appropriate or corresponding object, for this tutorial, it will be the <video> tag.
      • errorCallback (opcional): This function is the negation of the previous one; that is, if the user denied access or the data stream could not be loaded for some reason, this function will be executed, which provides one of the following error codes:
ErrorDescription
PERMISSION_DENIEDThe user denied permission to use the media device required for this operation.
NOT_SUPPORTED_ERRORA specified constraint is not supported by the browser.
MANDATORY_UNSATISFIED_ERRORNo media sources of the type specified in the constraints were found.
NO_DEVICES_FOUNDNo webcam found.

Available on Firefox Developer.

Accessing the camera and microphone of a device with JavaScript: Example

The complete JavaScript code for the example:

navigator.getUserMedia = ( navigator.getUserMedia ||
                       navigator.webkitGetUserMedia ||
                       navigator.mozGetUserMedia ||
                       navigator.msGetUserMedia);

navigator.getUserMedia (

   // constraints
   {
      video: true,
      audio: false
   },

   // successCallback
   function(localMediaStream) {
      var video = document.querySelector(video);
      video.src = window.URL.createObjectURL(localMediaStream);
   },
   
   // errorCallback
   function(err) {
    console.log("Ocurrió el siguiente error: " + err);
   }

);

To summarize, first we assign the constraints, indicating that we are only interested in video and not audio:

   // constraints { video: true, audio: false },

If no error occurred, we will assign the data stream returned in the LocalMediaStream object to a video tag:

   // successCallback
   function(localMediaStream) {
      var video = document.querySelector(video);
      video.src = window.URL.createObjectURL(localMediaStream);
   },

Finally, we handle errors (if any):

   // errorCallback function(err) { console.log("The following error occurred: " + err); }
  • We cannot use getUserMedia on pages that use file:// in their URLs.
  • This API requests permission from the user to access the camera and microphone.

A summarized and more modern way of the previous exercise:

navigator.mediaDevices.getUserMedia({ video: true })
  .then(stream => {
    const video = document.querySelector("video");
    video.srcObject = stream;
  })
  .catch(error => {
    console.error("Error:", error);
  });

▶️ Show the video in a <video> element

Your HTML can be as simple as this:

<video autoplay playsinline></video>

And yes: as soon as the user approves the permission, ENJOY, the video will appear as if by magic... like in a native app.

️ How to also access the microphone

Using the microphone is just as easy as using the camera:

navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { console.log("Microphone ready"); });

️ Audio + video in the same stream

If you want both, just mix constraints:

navigator.mediaDevices.getUserMedia({
 video: true,
 audio: true
})
.then(stream => {
 const video = document.querySelector("video");
 video.srcObject = stream;
});

Take photos from the webcam (canvas + capture)

This is one of my favorite uses.
To capture an image from the <video>, you only need a <canvas>.

️ Link the <canvas> with the stream

We can also use Canvas to render the video:

<video autoplay playsinline></video>
<canvas id="canvas" width="640" height="480"></canvas>
<button id="capture">Tomar foto</button>

Code:

const video = document.querySelector("video");
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
document.getElementById("capture").addEventListener("click", () => {
 ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
});

When I implemented this in a project, seeing the frozen image on the canvas was like having Photoshop integrated into the web.

Save or download the image

const dataURL = canvas.toDataURL("image/png"); // You can open it or download it console.log(dataURL);

❌ Error handling and denied permissions

Here's where the most common errors occur:

  • PERMISSION_DENIED
    • Occurs when the user denies access.
      It often happens when the browser had previously blocked permissions.
  • NOT_SUPPORTED_ERROR
    • Means that the requested constraint does not exist on that device.
    • For example: asking for video on a device without a camera.
  • MANDATORY_UNSATISFIED_ERROR / NO_DEVICES_FOUND
    • No available camera or microphone found.

Practical advice after implementing it in real projects

  • Never test from file://, it won't work. Use a local server.
  • Avoid using APIs with prefixes (webkitGetUserMedia): they are obsolete.
  • Always capture errors, especially on mobile.
  • Check previous permissions: some browsers remember prior decisions.
  • If you need to record video, add MediaRecorder to your flow (optional).

❓ Frequently Asked Questions

  1. Why doesn't my camera work if I open the file directly?
    1. Because file:// does not have permissions. Use a local server or HTTPS.
  2. Can I capture photos without plugins?
    1. Yes. You only need <video> + <canvas>.
  3. How do I also capture the microphone?
    1. Include { audio: true } in your constraints.
  4. Is it necessary to use srcObject?
    1. Yes, it is the recommended modern method.
  5. What happens if the user denies permissions?
    1. You must catch the error and display a friendly message.

Conclusion

Accessing the camera and microphone with JavaScript is easier than it looks. With the modern mediaDevices.getUserMedia API, you can create everything from simple photo captures to complete recording, streaming, and video calling applications.

The key is mastering constraints, correctly displaying the stream, handling real errors, and understanding how permissions work. From here, you can build any browser-based multimedia tool.

The next recommended experiment for you is: How to create rings of circles in JavaScript and Canvas

I agree to receive announcements of interest about this Blog.

Learn step-by-step how to access your camera and microphone with JavaScript using the getUserMedia API. We'll show you how to display video, capture photos with canvas, and troubleshoot common errors. Create interactive web applications today!

| 👤 Andrés Cruz

🇪🇸 En español