What you’ll take away
- Identify the document that requests the camera; a top-level site label does not describe every embedded origin.
- A policy-enabled frame has not thereby received user consent, and the parent must itself be eligible to delegate.
- Denied can reflect policy or context, while granted does not guarantee that capture will succeed.
- Required constraints filter complete configurations; a preferred width is not proof of the delivered format.
- Record actual outcomes and times: a pending request or local timeout is not evidence of a refusal.
First name the page that is actually asking for the camera
A video page says camera access is allowed, yet its embedded meeting panel cannot start the camera. The useful first question is which page is making the request. A browser origin is identified by its scheme, host and port; a path is not a separate origin. [6] Our fictional site at https://studio.example/room can therefore share an origin with https://studio.example/settings while embedding a panel from the different origin https://lens.example. A setting observed for the surrounding page does not, by itself, describe every condition affecting that panel.
We will follow this invented arrangement through permission, embedding policy and camera selection. The examples use ordinary origins, with no sandbox or origin-relaxation changes. They are deductions from the cited documents, not browser tests. The Permissions and Permissions Policy documents are working drafts dated 26 October 2026; the media-capture document is a candidate recommendation draft dated 9 October 2025. [1][2][3] Their distinctions help explain a failure, while exact browser support and interface wording still need to be checked for the version involved. Even a different port, such as https://studio.example:8443, changes our requesting origin. [6]
Identify the requesting Document before interpreting an allow setting. For ordinary tuple origins, WHATWG HTML compares scheme, host and port. [6] Let A=https://studio.example and B=https://lens.example. The paths /room and /settings at A have the same origin; B and https://studio.example:8443 do not. A visible top-level URL is therefore insufficient to identify the origin of the document executing a request inside a cross-origin iframe. The relevant observation is the document that invokes the camera API, not merely the site name beside the browser's address field.
Our original fixture uses A as a top-level document and B as a direct child. Assume supported camera features, ordinary unsandboxed origins and fully active documents; the security-context and policy variations will be stated separately. No camera or browser implementation is exercised. The normative references are the 26 October 2026 Permissions and Permissions Policy working drafts and the 9 October 2025 Media Capture and Streams candidate recommendation draft. [1][2][3] We analyze their documented relationships, without claiming uniform implementation across browser versions. In particular, neither the example nor an A-specific UI observation establishes B's applicable stored user decision.
A permission query is different from a request for a stream
The Permissions API can report a state named granted, denied or prompt. Asking for that state is different from asking the camera API to provide video. [1][3] Think of the query as an observation about access at that point, rather than a photograph or a working video connection. A page can receive an answer to the permission question without having received any camera frames. Keeping those observations separate prevents an application from announcing that its camera is working before it has a stream.
The labels also need context. A denied result can include a policy restriction, so it does not necessarily record someone pressing a refusal button. A granted result is not a guarantee that a later camera request will succeed. [1][3] Prompt describes a permission state that can require a decision; the query itself does not supply that decision. If a browser does not support the requested permission descriptor, the documented query can reject instead of returning one of these states. [1] An application should preserve that distinction rather than relabeling an unsupported query as a user's refusal.
Separate navigator.permissions.query from getUserMedia. The first resolves a PermissionStatus whose state is granted, denied or prompt; the second requests a MediaStream subject to its own algorithm. [1][3] A successful state query is therefore not evidence that device selection, constraint application or stream creation completed. This separation also affects logging: a permission-state value and a capture Promise outcome are different fields, even when they are observed close together in one user interaction.
The Permissions draft's state algorithm includes security-context and policy checks before consulting the applicable permission information. [1] Consequently, denied is not a unique encoding of user rejection. Conversely, the media-capture draft explicitly permits capture failure despite granted permission. [3] Query errors are a third category: an unsupported descriptor name yields TypeError in the cited draft, and an inactive document has a separate InvalidStateError path. [1] The fixture assumes a supported camera descriptor and an active document, but a real diagnostic record should distinguish an unavailable query operation from a valid query returning denied.
An HTTPS child can still have an insecure embedding context
An HTTPS address is useful information, but the surrounding frame arrangement matters too. The Secure Contexts document explains that an HTTPS page inside an insecure HTTP ancestor is not a secure context merely because its own connection uses HTTPS. [4] Camera access is exposed through a secure-context interface in the cited media-capture document. [3] That means the page's address and the context in which it runs answer related, but different, questions. A secure connection for one document does not rewrite its ancestors.
Consider three fictional arrangements using ordinary remote hosts. HTTPS A containing HTTPS B has no insecure ancestor in this example. HTTP A containing the same HTTPS B gives B an insecure ancestor. Opening HTTPS B as its own top-level page removes that particular ancestor issue. This comparison concerns secure-context eligibility only; it does not grant consent or promise a working camera. The specification also has special treatment for some potentially trustworthy local origins. [4] We are not using those exceptions, so the example should not be stretched into a claim that every HTTP address behaves identically.
Secure-context status is not a predicate over the child URL alone. The Secure Contexts specification describes an ancestral check, and its examples explicitly distinguish a secure document under a secure ancestor from the same HTTPS document under an insecure HTTP ancestor. [4] The media-capture Navigator.mediaDevices interface is marked SecureContext. [3] These are exposure and eligibility boundaries, not merely a later interpretation of the camera permission UI. Missing access to an interface should not be logged as if an ordinary permission Promise had returned denied.
For the declared remote-origin fixture, compare HTTPS A → HTTPS B with HTTP A → HTTPS B. The second B context fails the secure-ancestor condition despite identical transport to B. A separate top-level HTTPS B has no such ancestor in this construction. We stipulate the other relevant context conditions rather than deriving complete browser behavior from URL text. Potentially trustworthy local-origin exceptions exist in the cited specification. [4] They are outside this fixture, as are browser configuration overrides. Restoring a secure context resolves only that condition; policy, applicable permission and the actual capture request still require their own interpretation.
The response header and the frame attribute describe different boundaries
Return to the secure A-and-B arrangement. The response header Permissions-Policy describes which origins may use a controlled feature under the document's policy. An iframe's allow attribute supplies a policy for that embedded frame. [2] For camera, the media-capture document specifies a default based on the same origin. [3] A different-origin panel therefore needs careful attention to delegation; simply seeing camera listed in one place does not explain the whole arrangement.
Use this explicit fictional configuration: A sends Permissions-Policy: camera=(self "https://lens.example"), and its B frame has allow="camera https://lens.example". In our ordinary direct-child fixture, A and B are both included by the parent header, and B is included by the frame rule. The documented policy checks let B remain eligible. [2][5] This result means that policy does not block camera use there. It does not mean that the visitor has agreed to video, that the camera exists, or that a requested recording format is available. The browser still has separate work to do.
Permissions Policy combines the document's declared response policy with an inherited policy derived for the child navigable; an iframe allow attribute contributes a container policy. [2] Camera's default allowlist is self in the cited media-capture specification. [3] Our explicit case avoids relying on omitted-header or omitted-attribute shorthand: A declares camera=(self "https://lens.example"), and the B container explicitly declares camera https://lens.example. Chrome's documentation shows the corresponding header/attribute syntax and delegation relationship. [5]
Let H={A,B} be the parent's explicit camera allowlist and F={B} the explicit container allowlist. Assume the parent is inherited-enabled and the child adds no response restriction. Under the pinned policy algorithms, the parent checks allow A and B, the container matches B, and B's own default camera check accepts its own origin. [2][3] Thus the child is policy-enabled in this fixture. This conclusion is deliberately narrower than permission granted or getUserMedia fulfilled. Policy establishes eligibility; it cannot manufacture the user's consent. [1]
Listing the child alone can still leave the child blocked
A surprising variation removes self from A's header while leaving B listed. The header now names only https://lens.example, and the frame still allows B. It may look as though this grants exactly the panel that needs the camera. However, the documented inheritance check first asks whether the feature is enabled for the parent itself. If it is disabled there, the child inherits that restriction. [2] Chrome's explanation also calls out this need for the embedding origin to be allowed. [5]
Our four cases make the difference visible. Header {A,B} with frame {B} passes the policy checks. Header {A} with frame {B} blocks B at the parent declaration. Header {A,B} with an explicitly empty frame allowlist blocks B at the frame. Header {B} with frame {B} blocks inheritance because A is excluded. These are four constructed configurations, not four measured browser results. The last case shows why merely intersecting two lists for B misses an important condition: the parent must be able to delegate the feature in the first place.
The pinned inherited-policy algorithm checks the parent document's feature value for its own origin before checking the child's origin and container allowlist. [2] In the fixture with explicit H and F, inherited-enabled A and no child response restriction, child eligibility reduces to (A∈H) ∧ (B∈H) ∧ (B∈F). This is a specialization of the cited algorithms, not a universal formula for every feature, nesting arrangement or policy syntax. Chrome's embedder-origin warning independently supports the parent-self condition. [5]
Evaluate four supplied configurations: ({A,B},{B}) enables B; ({A},{B}) disables it; ({A,B},∅) disables it; and ({B},{B}) also disables it. Here ∅ means an explicit empty camera allowlist, rather than an omitted attribute with default behavior. The final row is the counterexample to using only B∈H∩F: B belongs to both sets, but A does not belong to H. A child cannot undo that inherited disabled state with a more permissive declaration of its own. [2] This finite calculation concerns policy only; no user-permission values are inputs to it.
A denied state and an error name do not identify one unique cause
Suppose the B frame queries camera permission and receives denied. The pinned Permissions algorithm can reach that state because the context is insecure, because policy disallows the feature, or because of the applicable permission information. [1] A single word therefore cannot establish which event happened. In particular, it is unfair and unhelpful for an application to tell someone that they refused access when the application has only observed a policy restriction that the person did not control.
The capture request has its own failure reporting. In the cited getUserMedia algorithm, a policy failure can lead to NotAllowedError, so that name alone is not proof of a fresh refusal either. [3] Compare the query result, the requesting origin, its context and the actual request outcome. Keep them as separate observations, with their times, instead of overwriting one with a guessed explanation. If the evidence points to a site's embedding configuration, changing the visitor's broader device permissions is not a demonstrated solution to that configuration problem.
The pinned permission-state algorithm returns denied for a non-secure context and for a document disallowed from the corresponding policy-controlled feature, before its applicable permission-store lookup. [1] Consequently, the inverse inference denied → user selected deny is invalid. Multiple causes map to the same state. The result is still useful: it describes the effective state under that algorithm. What it does not provide is a complete causal history or a record of the most recent visible interaction.
Similarly, the getUserMedia Permission Failure branch rejects with NotAllowedError, and the policy checks can route the request to that branch. [3] A diagnostic classifier should not treat this exception name as an exclusive user-refusal code. Error exposure and algorithm ordering can also limit which more specific failure becomes observable. [3] Our model does not prescribe a universal priority among all possible errors. It supports a narrower conclusion: retain state-query results, exceptions and independently established context conditions as distinct evidence, then report only the cause those observations actually establish.
An allowed request may ask for a configuration that cannot be supplied
Permission answers an access question; a camera request can also ask for a particular image size or frame rate. The cited media-capture document distinguishes required basic constraints from preferences. For supported properties, basic min, max and exact values impose requirements, while ideal expresses a preference. [3] This difference is easy to miss when two requests display the same number, such as a width of 1,920 pixels, but attach different meanings to that number.
We will invent a tiny camera configuration catalogue: 640×480 at 30 frames per second, 1,280×720 at 30, and 1,280×720 at 15. These three combinations are the whole catalogue for the next calculation, not specifications of a real camera. Assume the browser recognizes the named properties and other conditions remain satisfied. Requiring width exactly 1,920 leaves no candidate. Preferring width 1,920 does not itself discard all three available combinations. The same requested number therefore leads to different eligibility calculations before we even ask which acceptable configuration the browser will select.
For supported constrainable properties, the cited media-capture model treats basic min, max and exact constraints as required; basic ideal values are optional preferences. [3] A recognized property's requested value and its required/optional status are separate inputs. getSupportedConstraints indicates recognized property names, not that a particular device can satisfy every value associated with those names. [3] This distinction matters when interpreting a format failure under an otherwise granted permission state.
Define the original finite configuration set K={(640,480,30),(1280,720,30),(1280,720,15)}, with tuple components width, height and frames per second. Treat it as the complete allowed catalogue for our arithmetic; it is not an implementation of browser device enumeration. Assume all three property names are supported. The required predicate width=1920 yields an empty subset of K. Changing only that condition to an ideal width of 1920 does not impose the same hard exclusion. The preference can influence selection among remaining candidates without turning an unavailable width into a requirement that every selected candidate must meet.
Check whole configurations rather than independent maxima
The invented catalogue also shows why a list of maximum values can be misleading. Require width 1,280 and a frame rate of at least 30: only the 1,280×720-at-30 entry remains. Instead require width 1,280 and a frame rate of at most 20: only the 15-frame entry remains. Both calculations apply their requirements together to each complete configuration. The media-capture document similarly treats required basic constraints as simultaneous conditions. [3] Selecting a width and a frame rate independently can hide whether that combination is available.
When only an ideal width of 1,920 is requested, our three catalogue entries remain possible under the hard requirements. That does not mean they are equally preferred, nor does it tell us which one a browser will choose. The cited selection algorithm leaves choices to the user agent and distinguishes optional constraints from guaranteed requirements. [3] A useful outcome record therefore includes the actual resulting settings when a stream is obtained, rather than treating the requested preference as proof of the delivered format. This is a format interpretation problem, separate from whether access was allowed.
Apply required predicates to complete tuples. For K, width=1280 ∧ frameRate≥30 selects only (1280,720,30). The alternative width=1280 ∧ frameRate≤20 selects only (1280,720,15). These are exact finite-set intersections, with no averaging or independent recombination of tuple components. The required-constraint semantics support this joint treatment. [3] The catalogue does not imply that every intermediate resolution or rate is available; such an interpolation would add unstated candidates to the model.
With no hard width restriction and ideal width=1920, K remains the hard-feasible set. We intentionally do not implement the full fitness calculation or predict a browser's selected tuple. The source distinguishes required filtering, optional preferences and user-agent selection. [3] Nor do we assign a universal exception precedence to every empty-set case: the full request algorithm contains permission and information-exposure checks as well. The defensible result is the candidate set under each declared constraint predicate. If capture succeeds, observed track settings provide the actual configuration; the original preference alone is not a substitute for that observation. [3]
Granted permission does not make an unavailable device usable
Now suppose B is in a secure context, its policy permits camera access, the applicable permission is granted, and a requested configuration exists. A further failure is still possible when the device cannot actually be opened. The cited media-capture algorithm describes hardware or operating-system, program or webpage locks that can remove a candidate after permission has been granted. [3] This is why an allowed status should not be converted into a promise that the next request will produce video.
For an invented final step, assume there is one suitable candidate. In one run it is accessible; in another, a hardware-access failure removes it. If no candidate of the requested kind remains on that documented failure path, the algorithm rejects with NotReadableError. [3] The same earlier granted observation can therefore accompany different capture outcomes. This example does not identify which application owns a device or establish a universal rule about camera sharing. It shows why an access outcome must be observed, and why repeatedly changing a site's permission is not evidence that an underlying device problem has been solved.
Granted permission does not guarantee successful getUserMedia completion; the media-capture draft states this explicitly. [3] Its post-grant selection steps can discard candidates when hardware access fails, including a lock at the operating-system, program or webpage level. If that path leaves no candidate of the requested kind, it rejects with NotReadableError. [3] This is a particular documented branch, not a claim that every capture failure must use that exception or that all browsers share identical camera-concurrency behavior.
Take an original single-candidate continuation after the stipulated permission and format checks. With accessible hardware, that specific obstacle is absent. With an access failure removing the sole candidate, the set becomes empty and the cited branch fails. Earlier policy eligibility and granted permission are unchanged between these two continuations. Thus those earlier observations do not determine the device-access outcome. The comparison also separates permission from allocation: authorization to request a resource is not a reservation that makes it available. Our fixture leaves later successful stream construction conditional on the remaining algorithm steps, rather than declaring success merely because one obstruction is absent.
A pending request is not a refusal, and an old state is not permanent
Permission decisions can have lifetimes, and the cited Permissions document allows permission state to change. [1] An observation made yesterday should therefore retain its date and context instead of becoming a permanent label attached to a site. The same applies within a session: a page can observe a state, then make a request later under different circumstances. A permission-state change and a device-access failure are different events even when both eventually interrupt the experience of using a camera.
There is also a quieter outcome: no answer yet. The media-capture request algorithm can remain waiting when the person does not respond to a permission request. [3] If an application's own timer reaches five seconds, that proves only that its chosen waiting interval elapsed. It does not prove that the person refused, that the browser finished the request, or that the request was cancelled. An honest message can describe the request as still waiting. It should not invent a denial event merely to force every interaction into a success-or-failure report.
Permission state has a lifecycle. The Permissions draft describes expiry, revocation and asynchronous state-change notification, with lifetimes that can depend on the feature and user agent. [1] A recorded PermissionStatus value is not a timeless grant identifier. The article does not assume one universal duration, permission-store key or revocation propagation mechanism across browsers. The practical data requirement is narrower: associate each observed state with its requesting context and observation time, and distinguish it from the result of a later capture operation.
The media-capture algorithm can stall awaiting a response to the permission request. [3] Consider an application-side five-second deadline imposed by our example. Reaching it is an event in the application's waiting policy; it is not a new permission decision or a settlement of the underlying Promise. Without a separately observed result, the state remains unresolved in that record. This logical distinction avoids interpreting silence as consent or refusal. It also prevents a local UI timeout from being misrepresented as proof that the browser cancelled an outstanding request or released a device.
Keep a small record that can explain the actual failure
A useful report begins with the requesting frame's origin and its parent arrangement. Add whether that context is secure, what policy applies to the camera, what permission query actually returned, and what the capture request asked for and returned. Those entries describe different questions established by the cited specifications. [1][2][3][4] In our A-and-B example, this record can separate a missing child origin, an excluded parent, a navigation to C, an impossible required width and a later hardware-access failure without accusing the visitor of a choice they did not make.
Then match the next step to the evidence. A visitor can confirm which site or embedded service they intended to use and decide whether they want to grant access. A site maintainer can inspect the actual frame and supported browser version, compare the declared policies and preserve the specific request outcome. These are checks of the described arrangement, not instructions to weaken browser protections. The important improvement is the explanation: an allow setting, a policy-enabled frame, a granted query and a working stream are individually useful observations, but each establishes only its own part of the camera request.
Use a compact diagnostic record with requesting origin, ancestor context, effective policy evidence, permission-query result or query exception, requested constraints, capture outcome and timestamps. These fields follow the separate mechanisms in the cited documents. [1][2][3][4] A browser/version identifier preserves the implementation boundary around the pinned drafts. In the original fixture, they distinguish H excluding A from H excluding B, navigation to C from a child camera=() restriction, and required-format infeasibility from a later hardware-access failure.
The record should support a bounded causal claim rather than a guessed global explanation. If effective policy is the established blocker, identify that policy boundary. If the request is pending, preserve pending. If a stream is obtained, record its actual settings instead of treating ideal constraints as delivered values. None of these checks authorizes a maintainer to invent the visitor's consent. They make an existing choice and a browser operation easier to interpret. The resulting account explains which condition was observed, which operation completed and which remaining facts are still unknown, without promising that one visible allowed control makes every embedded camera request succeed.
Sources & further reading
Explore the references behind this guide. External pages may change after our review.
- PermissionsW3C · Accessed 7 Nov 2026
- Permissions PolicyW3C · Accessed 7 Nov 2026
- Media Capture and StreamsW3C · Accessed 7 Nov 2026
- Secure ContextsW3C · Accessed 7 Nov 2026
- Control browser features with Permissions Policy | Privacy & Security | Chrome for DevelopersChrome for Developers · Accessed 7 Nov 2026
- HTML StandardWHATWG · Accessed 7 Nov 2026
Article updated 7 Nov 2026.
Found something we should revisit?
Good explanations get better with thoughtful feedback.