Back to Knowledge Hub
Identity

WebUSB Device Access: Permissions, Interfaces, and Privacy

Separate a WebUSB chooser grant from device readiness, handle protected interfaces and disconnects, and keep USB metadata out of routine logs.

BotBrowser Team

Documentation

Want the structured docs for Identity?

This article lives in the editorial library. For step-by-step setup, reference material, and ongoing updates, jump into the docs section.

For a new WebUSB permission, make the user's action open the browser chooser; a previously granted device may also be returned to the same origin later. Neither path proves that the device is ready. BotBrowser can exercise a page-owned capability check and fallback in a provisioned browser context, but it does not provide a USB device, grant operating-system access, or prove hardware I/O. Treat opening the device, selecting a configuration, claiming an interface, and completing an operation as separate outcomes, and keep a non-USB path available.

A user starts a USB request, a chooser selection crosses an access boundary into a short-lived session, and rejection or disconnection returns to a page fallback

TL;DR

  • requestDevice() is a user-mediated permission step, not a nearby-device inventory.
  • A granted device can still fail to open or expose a claimable interface.
  • WebUSB does not make protected interface classes available to an ordinary web page.
  • Release claimed interfaces and close the session when the task ends; closing does not itself reset permission.
  • Store a task outcome, not serial numbers or a long-lived device history.

Contents

Choose access at the point of use

WebUSB is restricted to secure contexts, and requestDevice() requires transient user activation. Put the request behind a named control that says what the device will do. The chooser lets the person select a matching device and grants the origin access; a feature check alone does neither. A browser or Permissions Policy may also make the request unavailable in the current document.

navigator.usb.getDevices() can return devices previously granted to the origin without opening a new chooser. It does not list every connected device. Use it only for a clear returning-user task, and do not treat its result as proof that a device is still connected. For a new grant, do not call the chooser on page load or loop after a rejection. A cancelled chooser should return to the page without losing the task's draft; offer another request only after a new user action.

The permission relationship is not a connection. It does not establish that the device is still plugged in, that it exposes the configuration the application needs, or that a transfer will succeed. Report each stage separately so a user can tell whether to select again, reconnect the device, or continue without USB.

Separate permission from device readiness

After a selection, USBDevice.open() starts a session. The application may then need to select a configuration and claim an interface before it can communicate. Each operation can reject for reasons that are different from a chooser decision, including a disconnected device, a missing configuration, or an interface that the API cannot claim.

Keep the application action bounded. If the required interface cannot be claimed, stop that path and explain that the device is unsupported in this environment. Do not broaden the requested access or repeat selection automatically. A product that only needs one permitted operation should request no wider set of capabilities than that operation needs.

The public BotBrowser Playwright guide documents browser automation for owned workflows. In an explicitly provisioned context, a test can verify a page's capability branch, status message, and fallback. That does not make a physical device available, grant operating-system access, or prove hardware I/O. Keep hardware-specific assertions in an environment that actually supplies the approved device.

Keep protected interfaces protected

For ordinary web pages, the WebUSB specification blocks access to protected interface classes, including common audio, human-interface, mass-storage, hub, smart-card, video, and wireless-controller classes. WebUSB does not make those platform protections optional. Specialized isolated web app rules are outside this page's scope. A device can be selected while a required interface remains unavailable to an ordinary web page.

Treat an unavailable or protected interface as a clear support boundary. Do not ask users to disable operating-system safeguards or describe a successful chooser as approval for every function on a composite device. If the workflow needs an interface outside WebUSB's allowed scope, use a reviewed native or operating-system path with its own consent and support contract.

Close the lifecycle and minimize metadata

Listen for disconnect on navigator.usb; the event carries the affected device. On physical disconnect, stop dependent work and preserve the user's draft. The device may already be closed, so attempt interface release and session close as best-effort cleanup and do not report either as a guaranteed physical release. A reconnect should require an explicit user action when the page needs a new attempt. When a task finishes while the device is still available, release claimed interfaces and close the session rather than leaving it open.

Closing a session and forgetting a device are different actions. close() ends the active session and releases open interfaces. forget() removes the page's permission for that device. Do not tell users that closing a connection erased a saved permission; explain the separate forget control or browser site settings when revocation is needed.

USBDevice may expose a serial number, product name, manufacturer name, and vendor or product identifiers after access is granted. These values can distinguish a particular unit or model. Avoid writing them to analytics, URLs, account records, screenshots, or routine support logs. Prefer a short-lived outcome such as selected, unsupported, or disconnected. If the task needs a label, let the user choose one and make its storage and deletion behavior clear.

Classify failures with a decision table

Classify the first failed stage and preserve the same non-USB task path. Do not infer a cause from a timeout alone.

Observed stageWhat it establishesNext action
API absent, insecure context, or policy restrictionThe page cannot start this WebUSB request hereKeep the task usable and explain the environment limitation
Chooser rejected or closedNo usable selection was returned for this attemptPreserve the draft; wait for a new, explicit user action
open(), configuration, or interface claim rejectedSelection did not produce a usable session or required interfaceStop USB work, show the supported path, and avoid requesting broader access
Device disconnect eventThe active device connection endedStop dependent operations, clean up, preserve input, and offer a deliberate retry
Operation reports successThe page observed its expected USB operation resultReport only that result; do not infer upload, account association, or remote storage

Expected result: every row returns to an understandable page state, and no row automatically reopens the chooser or records device identifiers. BotBrowser can check those page-owned states in its declared test context; it cannot turn them into evidence of a real device operation.

Make each transition observable

A useful implementation records a small state machine rather than one boolean such as usbReady. A representative sequence is idle, requesting, selected, opening, configuring, claiming, operating, and then either complete, unsupported, cancelled, or disconnected. These labels describe application progress, not browser permission state. Keep that distinction explicit in the interface and in test assertions. For example, selected means the chooser returned a device; it does not mean open() succeeded.

Use one transition owner for each asynchronous step. Disable duplicate action controls while a chooser request is pending, but do not trap the user in a modal page state if the browser chooser is cancelled. After the chooser resolves, check that the operation still belongs to the current task. A user may have navigated away or started another task while the browser UI was open. In that case, do not attach a late device result to unrelated work; close any session that the page itself opened and restore the correct page state.

Every visible status should name the observed event. “Device selected” is more accurate than “Device connected” immediately after requestDevice(). “Session opened” is more accurate than “Ready” before configuration and interface checks complete. If the operation needs a user confirmation outside the page, do not infer that confirmation from a successful USB transfer. These distinctions reduce both misleading support reports and accidental data retention because the product does not need a durable device identity to explain what happened.

Bound filters and request options

The filters passed to requestDevice() should reflect the task's supported devices. A vendor identifier or supported class can reduce irrelevant choices, but a filter is not an authorization for every interface exposed by a composite device. Keep the list small and review it when product support changes. Avoid broad filters that invite the user to select an unrelated peripheral and then fail after permission has already been granted.

Treat optional interface requests as an explicit product decision. If the application requests optional interfaces, explain why before the chooser appears and handle a selection that does not provide them. Do not use chooser options to turn a user-facing device picker into a discovery mechanism. If the task can run with a narrower device set, prefer that set and test the unsupported case as an expected outcome, not as an exceptional crash.

The browser still applies protected-interface rules after a device has been selected. Filters cannot override the blocklist, and a matching vendor or product identifier does not imply that every interface is claimable. This is why interface support belongs in the post-selection state machine as well as in the initial chooser design. Document the exact supported operation, not a vague promise that a device model “works.” Firmware variants, operating-system policy, and interface layouts can differ even when product names appear identical.

Keep asynchronous cleanup race-safe

USB work can overlap with navigation, a second user action, a disconnect event, or an operation timeout. Use a task generation token or equivalent ownership check so an older promise cannot overwrite the status of a newer attempt. When disconnect arrives, mark the active task terminal before awaiting cleanup. Otherwise, a late transfer completion may repaint the page as successful after the connection has ended.

Cleanup should be idempotent. Track whether an interface was actually claimed and whether a session was opened before calling release or close. Catch cleanup failures independently so a failed release does not prevent the remaining cleanup path, and do not turn best-effort cleanup into a claim that the hardware was reset. Clear references to device objects when the task ends if they are no longer needed. This reduces accidental reuse and makes the next explicit attempt easier to reason about.

Do not automatically reconnect, reopen, or repeat a transfer after a disconnect unless the operation is known to be safe and the user explicitly starts a retry. For a write or firmware action, a retry may duplicate or partially apply work. The user-facing recovery path should identify what is known: whether the page saw the operation begin, whether it observed completion, and whether the device disconnected before confirmation. Leave uncertain outcomes uncertain instead of guessing from a timeout.

Design tests around evidence boundaries

Separate page-owned tests from hardware acceptance tests. A page-owned test can stub the availability branch, simulate a chooser rejection, assert that a cancelled chooser preserves a draft, or dispatch a disconnect event to verify status and cleanup behavior. Such a test is valuable because it checks deterministic application logic. It must not be described as a test of a real peripheral, operating-system permission, physical disconnect timing, electrical behavior, or successful device I/O.

Hardware acceptance needs a device supplied by the approved test environment, a documented operating system and browser version, and an operation whose expected result can be checked. Record only the environment facts needed to reproduce the result. Do not copy raw serial numbers into general test reports; use a test fixture label or a controlled inventory reference with separate access and retention rules. If no approved device is available, mark the hardware assertion as unverified and retain the page-level test result as narrower evidence.

A compact test matrix should include at least these dimensions:

DimensionPage-owned checkHardware check
API and secure contextForce absent or unavailable capability and verify the non-USB task remains usableConfirm the approved browser and origin expose the API
User activationVerify the request starts only from the intended controlConfirm the chooser is presented during a real user action
Permission outcomeSimulate cancellation and rejection without losing inputSelect only the approved test fixture and verify the expected grant
Session setupSimulate open, configuration, and claim failures separatelyConfirm the actual device's supported configuration and interface
DisconnectDispatch a controlled event and assert terminal state plus idempotent cleanupDisconnect at a documented point and verify the recovery instructions
Data handlingAssert logs contain outcome labels but not identifiersReview the test report and telemetry path for serial or account identifiers

This division prevents a test report from silently claiming more than its environment can establish. It also creates a useful diagnostic sequence: first prove that the page responds correctly to each branch, then run the hardware-specific acceptance only where the real device exists. BotBrowser can help exercise the former in a provisioned browser context; hardware claims remain with the environment that supplies and observes the device.

Review privacy at collection time

The simplest retention policy is to avoid collecting device identifiers in the first place. Before adding telemetry, ask what decision the event will support and whether a coarse outcome is sufficient. A count of completed, cancelled, unsupported, and disconnected tasks may be enough to measure reliability. If debugging requires a correlation key, use a short-lived random task identifier rather than a serial number or another stable device-derived value. A transformed identifier is not harmless when it can still link repeated visits or reveal a particular unit.

Keep diagnostic detail local by default. If a user chooses to submit a support report, show which fields will be sent and omit identifiers unless a specific investigation requires them. Do not include device properties in a URL query string, because URLs can propagate to browser history, referrer data, proxy logs, screenshots, and analytics systems. Do not attach them to an account merely because the page has already authenticated the user; device identity and account identity answer different product questions.

Also consider screenshots and copied error messages. A useful error should name the failed stage and next action without printing vendor IDs, product IDs, serial numbers, or full device descriptors. In a shared or managed environment, support staff may need the model but not a unique unit identifier. Make that distinction part of the support workflow and delete temporary diagnostic records on a defined schedule.

Decide what “forget” means for the product

Users often interpret “disconnect,” “close,” and “forget” as synonyms, so label the controls by their effect. A disconnect control should end the page's active work. close() releases the active WebUSB session; it does not remove the origin's remembered grant. A forget control calls the API operation that removes that grant, subject to browser support and the current device state. Browser site settings remain a separate way to review or revoke site access.

Do not automatically call forget() as cleanup after every task. A returning-user flow may intentionally rely on a previous grant, and erasing it can create repeated chooser friction without improving session cleanup. Conversely, do not keep a page session open merely to preserve permission. Let the user choose between ending current work and removing future access, and communicate the scope of each action before it runs.

Test the distinction directly: after a session closes, verify that the page no longer uses the active device object while the returning-device behavior remains governed by the browser grant; after forgetting, verify that the page no longer treats the device as previously granted. The exact observable behavior can vary with browser support, so avoid promising that every browser exposes identical controls or timing. A clear product label plus accurate help text is safer than a universal claim about browser UI.

Ship with explicit support boundaries

Publish a support statement that names the browser context, the classes of devices tested, the operation covered, and the known exclusions. “WebUSB supported” is too broad if only one device family and one interface layout have been exercised. Include a non-USB route for the core task so users are not blocked by an unsupported browser, protected interface, missing device, or policy restriction.

When support changes, update the chooser filters, interface checks, user-facing statuses, hardware test matrix, and privacy review together. A new device variant may add an interface or expose additional identifying properties; the change is not merely a new product ID. Keep the evidence attached to the precise combination of page version, browser environment, and approved hardware fixture so an old pass is not reused as proof for a different setup.

These boundaries are part of the feature contract. The page can state what it requested and what result it observed. The browser and operating system decide which device and interface operations are available. BotBrowser can exercise the page-owned checks and fallback in its provisioned context, but it cannot supply the hardware or certify the physical operation. Keeping those statements aligned makes the interface more honest and makes failures recoverable without collecting more data than the task needs.

Implementation and privacy checks

Keep state labels separate from permission, make asynchronous cleanup idempotent, and test cancellation, disconnect, and unsupported interfaces as expected branches. Review telemetry at collection time, distinguish close() from forget(), and publish the exact browser, device class, and operation supported. BotBrowser can verify these page-owned states and the fallback in an explicitly provisioned browser context; it cannot provide hardware or prove physical I/O.

Practical conclusion

Use one explicit chooser action, keep permission separate from session and interface state, and make disconnect cleanup predictable. Before shipping, verify one supported-device flow, one rejected or unavailable flow, and one disconnect flow in the environment each actually requires. Keep the normal task complete without USB, and store only the outcome needed to explain that task.

FAQ

Does a chooser grant mean the device is connected?

No. It authorizes the origin to work with the selected device within the API and platform limits. The device can be unplugged, fail to open, or lack an interface the page can claim.

Does close() revoke the site's device permission?

No. close() ends the current session. Use forget() or the browser's site controls when the permission itself should be removed.

Should an app save serialNumber to recognize a device later?

Only when the task has a specific need and the user understands the retention. The value can distinguish a physical unit, so it should not become a default analytics or account identifier.

What should the page show after a failed stage?

It should name the first observed failure and keep the task usable through its non-USB path.

Can BotBrowser prove a physical device operation?

BotBrowser can verify page-owned capability states and the fallback in a provisioned context, but it cannot provide the device or prove hardware I/O.

Sources

For related browser boundaries, see Permissions Policy and browser capabilities and browser permission privacy.

#WebUSB#Device Access#Permissions#Privacy#Browser APIs

Take BotBrowser from research to production

The guides cover the model first, then move into cross-platform validation, isolated contexts, and scale-ready browser deployment.