Request only the browser permission your demo needs, then test refusal. A camera demo should explain its next step before opening a permission prompt.
For a fictional QR-scanning prototype, the core action needs video input. It does not automatically need microphone access, location or notifications. Put a clearly labeled Start camera control before the request, and explain whether images stay on the device or are sent elsewhere according to your actual implementation.
Ask for the required media type
Call the request from the user's deliberate action. The following is a minimal camera-acquisition helper, not a complete scanner:
async function acquireDemoCamera() {
if (!navigator.mediaDevices?.getUserMedia) {
return { kind: "unavailable" };
}
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: false
});
return { kind: "ready", stream };
} catch (error) {
return { kind: "failed", name: error.name };
}
}
MDN documents getUserMedia as a secure-context API. Rehearse the actual HTTPS demo URL. Check the hosting environment and embedded-frame policy rather than treating every failure as the visitor pressing Deny.
The returned promise can remain pending if the user ignores the prompt. Give the interface an explanation and a route to an alternative; do not leave the entire page looking frozen. Avoid starting a second request while the first one is still pending.
Give each blocked state a useful next step
NotAllowedError can reflect denial or another access restriction, including a permissions policy. Tell the visitor that camera access is unavailable and offer manual input if the product supports it. NotFoundError means no matching media source was found. It calls for a different explanation than an access restriction.
Keep the message specific without printing unrelated device information. A failure name is useful during a test, but the visible product message should describe what the visitor can do next. Do not promise that changing one setting will fix every cause.
Stop the camera when the task ends
Once the UI finishes with the stream, stop its tracks:
stream.getTracks().forEach(track => track.stop());
MDN's track.stop documentation describes releasing a track's use of its source. Keep that cleanup connected to leaving the scanner view or pressing Stop. The helper above does not attach video to an element, process frames or implement component cleanup for you.
Rehearse allowed access, refused access and a device without a usable camera in a test environment. Check that the visitor can continue or leave each state. Record which cases you actually tested rather than labeling the whole feature verified after one successful prompt.
When browsing the Stavleak hackathon catalogue, check how the chosen event expects judges to open demos. If your project requires hardware or a browser permission, put that requirement and its fallback beside the submitted link.
Top comments (0)