← Capability Elements: <usermedia> MVP
v151 · html · method + dictionary reference
setConstraints() / HTMLMediaStreamConstraints
The configuration channel for the getUserMedia() call a <usermedia> element makes: call setConstraints() with an HTMLMediaStreamConstraints dictionary (video and audio MediaTrackConstraintSet members) before the user interacts.
Syntax
// Specification IDL (Media Capture and Streams Extensions):
undefined setConstraints(optional HTMLMediaStreamConstraints constraints = {});
dictionary HTMLMediaStreamConstraints {
MediaTrackConstraintSet video;
MediaTrackConstraintSet audio;
};
// Usage:
const el = document.querySelector("usermedia");
el.setConstraints({
video: { width: 1280, facingMode: "user" },
audio: { echoCancellation: true, noiseSuppression: true }
});
Chromium ships the method and dictionary in user_media_element_constraints.idl (as a partial mixin on HTMLMediaCaptureElementBase). The MediaTrackConstraintSet members accept the same constraint properties as getUserMedia() — width, height, frameRate, facingMode, echoCancellation, sampleRate, and so on — defined by Media Capture and Streams.
Inputs
One optional parameter, an HTMLMediaStreamConstraints dictionary, defaulting to {}:
| Member | Type | Meaning |
|---|---|---|
video | MediaTrackConstraintSet | Constraints for the camera track. Omitting it does not disable video — see the backfill rule below. |
audio | MediaTrackConstraintSet | Constraints for the microphone track. Omitting it does not disable audio — see the backfill rule below. |
Two input rules matter, and both are defined by the shipping Chromium implementation, not the raw dictionary shape:
- Both kinds are always requested. Chromium backfills any missing member with an empty constraint set, so
{ video: {} }does not make a camera-only element — it still requests microphone access too. The upstream WPT combinations test states the contract directly: “In standard mode, the element always requests both camera and microphone. Missing constraints default to enabled.” Per-kind selection is not part of the shipping MVP. - Only bare scalar values survive sanitization. Chromium's
SanitizeTrackConstraintskeeps a constraint only when its value is a plain scalar (width: 1280,facingMode: "user",echoCancellation: true) or a string sequence. Parameterized forms —{ ideal: … },{ exact: … },{ min: … },{ max: … }objects — are dropped entirely, so{ width: { ideal: 1280 } }silently loseswidthaltogether. This is stricter than the spec's constraint filter (which only removes requiredexact-style constraints); write plain scalars.
setConstraints() — outputs
Returns undefined. The observable effect is stored state — but only on the first call: Chromium's implementation is first-call-wins (if (did_set_constraints_) return;), so every later setConstraints() call is a permanent no-op that silently keeps the constraints from the first call. There is no way to reset or replace them afterwards, and no getter to read the stored constraints back — keep your own copy if you need it.
HTMLMediaStreamConstraints — outputs
The dictionary is a pure input shape — it has no methods and produces no value itself. Its observable effect is the shape of the eventual MediaStream: on a successful acquisition, el.stream contains a video track when video was present and an audio track when audio was present, configured as close to the constraints as the device allows (after the user agent's filtering). Constraint keys the device can't honor as preferences are simply approximated, per the standard Constrainable pattern.
Errors
setConstraints() itself does not surface exceptions for ordinary dictionary input — it sanitizes and stores what you pass. Because missing members are always backfilled (and the never-configured path substitutes the { video: {}, audio: {} } default), there is no page-reachable “no constraints set” failure: a call like el.setConstraints({}) simply stores the audio+video default. Per WebIDL conversion, passing null or undefined is treated as an empty dictionary (same default outcome), while a throwing getter on the input object propagates its exception out of the call before any constraints are stored.
Context
Receiver: any HTMLUserMediaElement instance (the method lives on the shared HTMLMediaCaptureElementBase mixin, so the same call exists on the experimental <camera>/<microphone> elements). Exposure: window only; the element operates only in secure contexts. Timing contract: call it before the user first interacts with the element — the method exists precisely because there is no declarative constraint syntax on the shipping MVP, so configuration is imperative-but-early. Feature-detect with "HTMLUserMediaElement" in window.
Lifecycle
The constraints slot starts unset. If no setConstraints() call has happened when the first acquisition runs, the browser substitutes the secure default { video: {}, audio: {} }. The first setConstraints() call stores the sanitized dictionary; every later call is ignored — there is no merge, no replace, and no reset for the life of the element. Configure exactly once, before the user can click. If you need different constraints later, replace the element node in the DOM and configure the fresh instance before its first activation.
Examples
const el = document.querySelector("usermedia");
// 1. Configure exactly once, early — before any click. Later calls are ignored.
el.setConstraints({
video: { width: 1280, height: 720 },
audio: { echoCancellation: true }
});
// 2. Omitting a member does NOT disable that kind — both camera and
// microphone are always requested; missing members default to enabled:
document.querySelector("#defaults").setConstraints({ video: {} }); // still asks for mic too
// 3. Use bare scalars — parameterized forms are dropped entirely by
// Chromium's sanitizer:
el.setConstraints({ video: { width: 1920 } }); // width kept
// el.setConstraints({ video: { width: { ideal: 1920 } } }); // width silently dropped
// 4. There is no reset: a second call is a no-op. To reconfigure, replace
// the element node and configure the fresh instance before first use.
Source: WPT set-constraints-combinations.tentative.https.html; Chromium user_media_element_constraints.cc.
Compatibility
| Engine / runtime | Support | Notes |
|---|---|---|
| Chrome / Edge (desktop) | 151 | Enabled by default (milestone listing; UserMediaElement status stable) |
| Chrome (Android) | 151 | Per the ChromeStatus feature detail (desktop + Android 151); not supported on Android WebView |
| Firefox | Not supported | “Under consideration” (mozilla/standards-positions #1392) |
| Safari | Not supported | No signal (WebKit/standards-positions #651; WICG/PEPC #62) |
| BCD | No entry | No api/HTMLUserMediaElement.json in browser-compat-data as of 2026-07-26 |
| WPT | Upstream WPT coverage exists | html/semantics/permission-element/usermedia (incl. the setConstraints combinations test); also unit-tested in Chromium (core, modules) |
Security and privacy
Declarative-style constraints carry the same device-fingerprinting weight as an imperative getUserMedia() constraints object — highly specific values probe camera capabilities. The explainer holds this API to the same mitigations as getUserMedia() (fuzzing exact values, withholding deviceId until a grant), and the required-constraint stripping doubles as an abuse guard: a site cannot force an OverconstrainedError oracle to learn device capabilities. Constraints never widen what the user consents to — the browser's prompt text reflects the actual camera/microphone request regardless of what the dictionary asked for.