Mediadevices Api
navigator.mediaDevices.getUserMedia() returns a live MediaStream from the camera or microphone. Feed it to a video element, pull frames to canvas, or pipe it anywhere. Green tier, HTTPS-only, permission-required.
The browser has been able to access a webcam since 2013. navigator.mediaDevices.getUserMedia() is the call that connects JavaScript to the camera -- and the MediaStream it returns is more versatile than most developers realize.
This is green tier. Chrome, Firefox, Safari, and Edge all support it on desktop and mobile.
Getting a Stream
const stream = await navigator.mediaDevices.getUserMedia({
video: true, // request camera
audio: false // skip microphone
})The constraints object controls what you get:
video: true-- any available camera, browser decides whichvideo: { facingMode: 'environment' }-- rear camera (phone back)video: { facingMode: 'user' }-- front camera (selfie side)video: { width: 1280, height: 720 }-- request resolution (not guaranteed)
The call is async and triggers the permission model. On denial it throws DOMException: NotAllowedError.
Displaying the Stream
const videoEl = document.getElementById('preview')
videoEl.srcObject = stream // assign stream directly
videoEl.play() // start renderingsrcObject accepts a MediaStream directly -- no blob URL needed. The video element renders live camera output continuously.
Extracting Frames for Processing
The stream does not have to go to a video element. Pull individual frames to a canvas:
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
function captureFrame() {
canvas.width = videoEl.videoWidth
canvas.height = videoEl.videoHeight
ctx.drawImage(videoEl, 0, 0)
return canvas // now pass to BarcodeDetector, run filters, etc.
}This is the bridge to the Shape Detection API: capture a frame, pass it to BarcodeDetector.detect(), and read the QR code. No need to upload anything -- the image processing stays on-device.
ExpandMediaDevices API: getUserMedia flow, stream → video element or frame extraction
Stopping the Stream
An open camera stream keeps the OS recording indicator active and drains battery.
function stopStream(stream) {
stream.getTracks().forEach(track => track.stop())
}A MediaStream has one or more tracks (video, audio). Calling track.stop() releases the camera or microphone. The video element goes blank.
Advanced Camera Control (PTZ)
Chromium supports Pan, Tilt, and Zoom on cameras that expose those controls:
const [track] = stream.getVideoTracks()
const capabilities = track.getCapabilities()
if (capabilities.zoom) {
await track.applyConstraints({
advanced: [{ zoom: 3 }] // 3x zoom if the camera supports it
})
}getCapabilities() returns what the current hardware supports. PTZ is Chromium only -- Safari and Firefox do not expose these controls.
Security Rules
HTTPS only. navigator.mediaDevices is undefined on HTTP origins. The API does not exist, let alone prompt for permission.
Permission is sticky. The permission model applies here the same way it does for geolocation. Denial is permanent until the user manually resets it in browser settings.
The browser also stops or mutes streams automatically when the page is hidden -- you cannot silently record in the background.
Augmented reality takes the camera stream further: instead of displaying it in a video element, WebXR and AR overlay virtual objects on top of it.
The Essentials
await navigator.mediaDevices.getUserMedia({ video: true })returns aMediaStream. Assign tovideoEl.srcObjectto display live.- Constraints control
facingMode(front/rear) and resolution -- hardware is the hard limit, constraints are a request. - Always stop tracks when done:
stream.getTracks().forEach(t => t.stop())releases the camera. - Frames extracted via
ctx.drawImage(videoEl, ...)can be passed directly toBarcodeDetector.detect()or any image pipeline. - HTTPS-only. PTZ camera control is Chromium only. Core stream API is green tier everywhere.
Further Reading
- Capture audio and video in HTML5 -- web.dev -- hands-on intro to stream constraints, device enumeration with
enumerateDevices, and common pitfalls - MediaDevices.getUserMedia() -- MDN -- full API reference including constraint system, error types, and browser support notes
Keep reading