JavaScript Navigator getUserMedia() Method

Beginner
⏱️ 12 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Deprecated

What You’ll Learn

navigator.getUserMedia() was the original way to open the webcam or mic from JavaScript. Learn its callback syntax, constraints, why it is deprecated, and how to migrate to mediaDevices.getUserMedia() with five examples and try-it labs.

01

Kind

Method

02

Returns

undefined (callbacks)

03

Status

Deprecated

04

Context

Secure (HTTPS)

05

Modern API

mediaDevices.getUserMedia

06

Delivers

MediaStream

Introduction

Video calls, selfie filters, and voice notes all need permission to use the camera or microphone. Early browsers exposed that as navigator.getUserMedia(constraints, success, error).

Today every modern browser prefers navigator.mediaDevices.getUserMedia(). The old method still appears in tutorials and legacy code, so beginners should recognize it — and know what to write instead.

💡
One-line migration

Replace callback navigator.getUserMedia(...) with await navigator.mediaDevices.getUserMedia(constraints), then video.srcObject = stream.

Understanding the getUserMedia() Method

  • Three argumentsconstraints, successCallback, errorCallback.
  • No return value — results arrive only through callbacks.
  • Success gets a MediaStream — assign it to video.srcObject (or an audio element).
  • Error gets a DOMException-like object — check err.name (for example NotAllowedError, NotFoundError).
  • User may not choose — if the prompt is ignored, neither callback may run.
  • Secure context — HTTPS / localhost in supporting browsers.

📝 Syntax

Legacy (deprecated) form:

JavaScript
navigator.getUserMedia(constraints, successCallback, errorCallback)

Parameters

  • constraints — object describing media types (for example { audio: true, video: true }).
  • successCallback — function receiving the MediaStream when permission is granted.
  • errorCallback — function receiving an error object when the request fails.

Return value

  • undefined — use the callbacks (or migrate to the Promise API).

Modern replacement

JavaScript
const stream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: { width: 1280, height: 720 }
});
const video = document.querySelector("video");
video.srcObject = stream;
await video.play();

⚡ Quick Reference

GoalCode
Detect legacy APItypeof navigator.getUserMedia === "function"
Detect modern API!!navigator.mediaDevices?.getUserMedia
Legacy call (avoid)navigator.getUserMedia(c, ok, err)
Modern call (prefer)await navigator.mediaDevices.getUserMedia(c)
Show in <video>video.srcObject = stream
Stop camera / micstream.getTracks().forEach((t) => t.stop())
Secure context?window.isSecureContext

🔍 At a Glance

Four facts to remember about navigator.getUserMedia().

Style
callbacks

Not a Promise

Status
Deprecated

Use mediaDevices

Context
HTTPS

Secure required

Result
MediaStream

Camera / mic tracks

📋 Legacy vs Modern getUserMedia

navigator.getUserMediamediaDevices.getUserMedia
StatusDeprecatedCurrent standard
Result styleCallbacksPromise (async/await)
Vendor prefixesOften needed in old codeNot required
New projectsAvoidPrefer

Examples Gallery

Examples show detection, legacy callbacks (for reading old code), and the modern Promise API you should ship. Try It Yourself may prompt for camera / mic permission on HTTPS or localhost.

📚 Getting Started

Detect which APIs exist before requesting media.

Example 1 — Feature Detection

Compare the deprecated Navigator method with the modern MediaDevices method.

JavaScript
const lines = [
  "navigator.getUserMedia: " +
    (typeof navigator.getUserMedia === "function" ? "available" : "missing"),
  "mediaDevices.getUserMedia: " +
    (navigator.mediaDevices &&
    typeof navigator.mediaDevices.getUserMedia === "function"
      ? "available"
      : "missing"),
  "isSecureContext: " + window.isSecureContext
];
console.log(lines.join("\n"));
Try It Yourself

How It Works

If only the modern method exists, never invent a legacy shim for new features.

Example 2 — Legacy Callbacks (MDN Style)

Understand old tutorials that used prefixes and success / error callbacks. Prefer Example 3 for new code.

JavaScript
// DEPRECATED — shown for reading legacy code only
navigator.getUserMedia =
  navigator.getUserMedia ||
  navigator.webkitGetUserMedia ||
  navigator.mozGetUserMedia;

if (navigator.getUserMedia) {
  navigator.getUserMedia(
    { audio: true, video: { width: 1280, height: 720 } },
    (stream) => {
      const video = document.querySelector("video");
      video.srcObject = stream;
      video.onloadedmetadata = () => video.play();
      console.log("legacy success: tracks=" + stream.getTracks().length);
    },
    (err) => {
      console.error("legacy error: " + err.name);
    }
  );
} else {
  console.log("legacy getUserMedia not supported");
}
Try It Yourself

How It Works

Prefixes were a historical workaround. Modern browsers expose MediaDevices instead.

📈 Practical Patterns

Use the Promise API, set constraints, and migrate safely.

Example 3 — Modern mediaDevices.getUserMedia()

Recommended path for new projects: await a stream and attach it to a video element.

JavaScript
async function startCamera() {
  if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
    return "mediaDevices.getUserMedia not supported";
  }
  try {
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: false,
      video: true
    });
    const video = document.querySelector("video");
    video.srcObject = stream;
    await video.play();
    return "modern success: tracks=" + stream.getTracks().length;
  } catch (err) {
    return "Error: " + err.name;
  }
}

startCamera().then(console.log);
Try It Yourself

How It Works

try/catch replaces the separate error callback and works cleanly with async/await.

Example 4 — Ideal Video Size Constraints

Ask for a preferred resolution; the browser picks the closest supported settings.

JavaScript
async function startHdPreview() {
  if (!navigator.mediaDevices?.getUserMedia) {
    return "API missing";
  }
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: { width: 1280, height: 720 }
  });
  const settings = stream.getVideoTracks()[0]?.getSettings() || {};
  return JSON.stringify({
    width: settings.width || null,
    height: settings.height || null,
    tracks: stream.getTracks().length
  });
}

startHdPreview().then(console.log).catch((err) => {
  console.log("Error: " + err.name);
});
Try It Yourself

How It Works

Constraints are shared between the legacy and modern APIs; only the call style differs.

Example 5 — Safe Helper (Prefer Modern, Stop Tracks)

One helper that uses MediaDevices when available and always cleans up tracks.

JavaScript
async function getUserMediaSafe(constraints) {
  if (!window.isSecureContext) {
    return { ok: false, stream: null, reason: "insecure-context" };
  }
  if (navigator.mediaDevices?.getUserMedia) {
    try {
      const stream = await navigator.mediaDevices.getUserMedia(constraints);
      return { ok: true, stream: stream, reason: "mediaDevices" };
    } catch (err) {
      return { ok: false, stream: null, reason: err.name };
    }
  }
  // Legacy fallback only for very old environments — prefer migrating callers
  if (typeof navigator.getUserMedia !== "function") {
    return { ok: false, stream: null, reason: "unsupported" };
  }
  return new Promise((resolve) => {
    navigator.getUserMedia(
      constraints,
      (stream) => resolve({ ok: true, stream: stream, reason: "legacy" }),
      (err) => resolve({ ok: false, stream: null, reason: err.name })
    );
  });
}

function stopStream(stream) {
  if (!stream) return;
  stream.getTracks().forEach((track) => track.stop());
}

getUserMediaSafe({ video: true, audio: false }).then((result) => {
  console.log(JSON.stringify({
    ok: result.ok,
    reason: result.reason,
    tracks: result.stream ? result.stream.getTracks().length : 0
  }));
  stopStream(result.stream);
});
Try It Yourself

How It Works

Stopping tracks turns the camera light off when your preview is done — always clean up.

🚀 Common Use Cases

  • Webcam preview — show a live <video> before recording or uploading.
  • Voice capture — request audio: true for notes or speech input.
  • Video chat / WebRTC — local stream before peer connection.
  • Photo booths — grab a frame from the stream onto a canvas.
  • Legacy maintenance — recognize old callback code and rewrite to MediaDevices.

🧠 How getUserMedia() Works

1

Choose constraints

Decide audio / video needs and optional size preferences.

Constraints
2

Ask for permission

The browser prompts the user (on a secure page).

Permission
3

Receive a MediaStream

Legacy: success callback. Modern: await the Promise.

Stream
4

Attach and clean up

Set srcObject, then track.stop() when finished.

📝 Notes

  • Deprecated — MDN banner is Deprecated only (not Experimental / Non-standard).
  • Prefer navigator.mediaDevices.getUserMedia() for all new code.
  • Requires a secure context (HTTPS / localhost).
  • If the user never answers the prompt, legacy callbacks may never fire.
  • Related: getVRDisplays(), mediaDevices, canShare(), Window.

Legacy / Deprecated Support

navigator.getUserMedia() is deprecated. Modern browsers expose navigator.mediaDevices.getUserMedia() instead. Some engines still keep a legacy alias for compatibility, but new apps should feature-detect MediaDevices and use the Promise API on HTTPS.

Deprecated · Use mediaDevices

Navigator.getUserMedia()

Legacy callback camera/mic API — migrate to mediaDevices.getUserMedia().

Legacy Deprecated
Google Chrome Prefer mediaDevices; legacy may remain as alias
Legacy
Microsoft Edge Prefer mediaDevices (Chromium)
Legacy
Opera Prefer mediaDevices
Legacy
Mozilla Firefox Prefer mediaDevices; old moz prefix era ended
Legacy
Apple Safari Prefer mediaDevices on HTTPS
Legacy
Internet Explorer No modern MediaDevices path
Unavailable
getUserMedia() (Navigator) Deprecated

Bottom line: Detect mediaDevices.getUserMedia first, request media on a secure page, attach MediaStream to video.srcObject, and stop tracks when done.

Conclusion

navigator.getUserMedia() taught the web how to open cameras and microphones, but its callback style is deprecated. Learn it to read old samples, then ship navigator.mediaDevices.getUserMedia() with clear permission UX and track cleanup.

Continue with getVRDisplays(), mediaDevices, or the JavaScript hub.

💡 Best Practices

✅ Do

  • Use mediaDevices.getUserMedia() for new code
  • Call only on HTTPS / localhost
  • Explain why you need camera / mic before prompting
  • Handle NotAllowedError and NotFoundError
  • Stop tracks when the preview closes

❌ Don’t

  • Start new features on navigator.getUserMedia
  • Rely on webkit / moz prefixes forever
  • Leave the camera running after the UI closes
  • Assume devices exist without checking errors
  • Request both mic and camera if you only need one

Key Takeaways

Knowledge Unlocked

Five things to remember about getUserMedia()

Deprecated callback API — migrate to mediaDevices for camera and mic.

5
Core concepts
02

Status

Deprecated

Avoid
03

Modern

mediaDevices

Promise
🔒 04

Context

HTTPS required

Secure
🛑 05

Cleanup

track.stop()

Always

❓ Frequently Asked Questions

It is the old callback API that asks for permission to use the camera and/or microphone and delivers a MediaStream to a success callback, or an error object to an error callback.
No. MDN marks it Deprecated. Use navigator.mediaDevices.getUserMedia(), which returns a Promise and is the supported modern API.
navigator.mediaDevices.getUserMedia(constraints). Await the Promise, assign stream to video.srcObject, and stop tracks when finished.
Yes in supporting browsers: getUserMedia is available only in secure contexts (HTTPS or localhost).
An object describing which media you want, such as { audio: true, video: true } or more detailed video size settings like { video: { width: 1280, height: 720 } }.
On the legacy API, neither callback may run until the user chooses Allow or Block. Always design UI that waits for a decision and offers a clear retry.
Did you know?

Early demos used webkitGetUserMedia and mozGetUserMedia. Those prefixes are historical — today’s standard path is navigator.mediaDevices.getUserMedia() with no vendor prefix.

Explore getVRDisplays() Next

Learn the deprecated WebVR API and migrate to WebXR.

getVRDisplays() →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful