How To Access Front and Rear Cameras with JavaScript's getUserMedia()
Practical guide to using getUserMedia camera facingMode: support checks, constraints (width/height/facingMode), enumerateDevices, selecting deviceId, switching front/rear cameras, and error handling.
Drake Nguyen
Founder · System Architect
Introduction
The MediaDevices API (navigator.mediaDevices) gives web apps controlled access to microphones and cameras. The getUserMedia camera facingMode combination lets developers request the front or rear camera on mobile devices, control resolution and select a specific video input. This guide explains how to use MediaDevices.getUserMedia in JavaScript, how constraints work, and how to list and pick devices with enumerateDevices.
Prerequisites
- Basic familiarity with JavaScript and HTML.
- A modern browser that supports WebRTC getUserMedia (secure origin: HTTPS or localhost).
Check browser support for getUserMedia
Before calling getUserMedia, verify that the browser exposes navigator.mediaDevices and the getUserMedia method to avoid runtime errors.
// Simple support check
if ('mediaDevices' in navigator && typeof navigator.mediaDevices.getUserMedia === 'function') {
console.log('MediaDevices and getUserMedia available');
} else {
console.warn('getUserMedia not supported in this browser');
}
Requesting camera permission and capturing video
Call navigator.mediaDevices.getUserMedia with a MediaStream constraints object. The returned Promise resolves to a MediaStream you can attach to a video element using srcObject.
const constraints = { video: true };
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
// display stream in a <video> element
const videoEl = document.querySelector('video');
videoEl.srcObject = stream;
videoEl.play();
})
.catch(err => console.error('Permission or device error:', err));
Understanding MediaStream constraints (width, height, facingMode)
The constraints object controls which devices and what quality you request. You can specify exact, ideal, min and max values for width and height. The facingMode constraint is used to request the front-facing camera ("user") or the rear-facing camera ("environment").
// Example: prefer rear camera and specific resolution
const videoConstraints = {
video: {
width: { ideal: 1280, min: 640, max: 1920 },
height: { ideal: 720, min: 480, max: 1080 },
facingMode: { ideal: 'environment' } // or 'user'
}
};
navigator.mediaDevices.getUserMedia(videoConstraints)
.then(stream => /* handle stream */)
.catch(err => console.error(err));
Use facingMode: 'user' for a front-facing camera and facingMode: 'environment' for the rear camera. On some devices you can require an exact facing mode:
{ video: { facingMode: { exact: 'environment' } } }
Note: exact can result in an OverconstrainedError if no device matches the requirement.
List available cameras with enumerateDevices
enumerateDevices returns a Promise resolving to an array of MediaDeviceInfo objects. Use this to present camera selection UI or to pick by deviceId when facingMode is insufficient.
async function listVideoInputs() {
const devices = await navigator.mediaDevices.enumerateDevices();
return devices.filter(d => d.kind === 'videoinput');
}
listVideoInputs().then(inputs => {
inputs.forEach(device => console.log(device.deviceId, device.label));
});
Device labels are empty until the user grants permission to a media device, so call getUserMedia first or handle empty labels gracefully.
Selecting a specific camera by deviceId
If you need to switch cameras programmatically (e.g., switch between front and rear on mobile), capture the deviceId from enumerateDevices and pass it as an exact constraint.
const updatedConstraints = {
video: { deviceId: { exact: selectedDeviceId } }
};
navigator.mediaDevices.getUserMedia(updatedConstraints)
.then(stream => /* attach stream to video */)
.catch(err => console.error('Error selecting device:', err));
Handling common errors
- NotFoundError: No matching device for requested constraints.
- OverconstrainedError: Constraints are too strict (e.g., exact resolution not available).
- NotAllowedError / PermissionDeniedError: User denied camera access.
Tip: When you get OverconstrainedError, relax the constraints (use ideal instead of exact or widen min/max).
Switching cameras (front vs rear) in JavaScript
A common pattern is to enumerate devices, find the appropriate deviceId for front or rear, and restart the stream with the deviceId exact constraint to switch cameras.
async function switchCamera(preferEnvironment) {
const inputs = await navigator.mediaDevices.enumerateDevices();
const videoInputs = inputs.filter(d => d.kind === 'videoinput');
// Try to pick a device whose label or facing matches preference
let chosen = videoInputs.find(d => /back|rear|environment/i.test(d.label));
if (!chosen) chosen = videoInputs[0];
const constraints = { video: { deviceId: { exact: chosen.deviceId } } };
const stream = await navigator.mediaDevices.getUserMedia(constraints);
document.querySelector('video').srcObject = stream;
}
Displaying and capturing frames (srcObject vs createObjectURL)
Use video.srcObject = stream to attach a MediaStream to an HTMLVideoElement. createObjectURL for MediaStream is deprecated in modern browsers and should be avoided.
// Recommended: set srcObject
videoElem.srcObject = stream;
// Deprecated: URL.createObjectURL(stream) — avoid this approach
Security and best practices
- getUserMedia requires a secure origin: HTTPS or localhost. This prevents misuse of camera access.
- Ask for the minimal permission and constraints needed to reduce privacy impact and data usage.
- Stop tracks when you no longer need the camera: stream.getTracks().forEach(t => t.stop());
Conclusion
Using getUserMedia camera facingMode and related MediaStream constraints gives web apps flexible control over camera selection and quality. Combine enumerateDevices, deviceId exact constraints and facingMode to support switching between front and rear cameras, handle OverconstrainedError gracefully, and always serve your pages over HTTPS for a secure experience.