Skip to content

WebUSB API

Published

WebUSB API — The WebUSB API lets a web app request access to non-standard USB devices via navigator.usb.requestDevice() and communicate with them directly.

  • Legend
  • Yes
  • Partial
  • Flag
  • No
  • Unknown
Browser / PlatformSupportVersionsConfidenceSourceNotes
Chrome (Desktop)Yes61highsource—
Chrome (Android)Yes61highsource1
Edge (Desktop)Yes79highsource2
Firefox (Desktop)No—highsource3
Firefox (Android)No—highsource45
Safari (macOS)No—highsource6
Safari (iOS)No—highsource78
Samsung InternetYes8.0highsource9
WebView (Android)No—highsource10
OperaYes48highsource—
  1. Derived by browser-compat-data mirroring from Chrome.
  2. Derived by browser-compat-data mirroring from Chrome.
  3. No Firefox support is recorded in browser-compat-data.
  4. No Firefox for Android support is recorded in browser-compat-data.
  5. Derived by browser-compat-data mirroring from Firefox.
  6. No Safari support is recorded in browser-compat-data.
  7. No Safari on iOS support is recorded in browser-compat-data.
  8. Derived by browser-compat-data mirroring from Safari.
  9. Derived by browser-compat-data mirroring from Chrome Android.
  10. No WebView Android support is recorded in browser-compat-data.

Source data: /compatibility/web-usb.json · Global usage: 74 % (StatCounter 2026-05)

Source: spec · MDN · Last verified 2026-10-03 · Confidence: high (computed from sources)

Requesting a device must happen inside a user gesture, and filters narrows the picker to devices matching a vendor/product ID pair. Once the user selects a device, open it before transferring data:

async function connectUsbDevice() {
const device = await navigator.usb.requestDevice({
filters: [{ vendorId: 0x1209, productId: 0xa800 }],
});
await device.open();
return device;
}

The configuration and interface numbers to select and claim next are specific to each device’s own descriptors — read them from device.configurations rather than assuming fixed numbers, then call device.selectConfiguration() and device.claimInterface() with the values found there.

Check for navigator.usb before offering the feature, and give the reader a fallback path when it is absent:

if ('usb' in navigator) {
connectButton.hidden = false;
} else {
connectButton.hidden = true;
fallbackNotice.textContent = 'This browser cannot access USB devices from the page.';
}
  • Requires a secure context (HTTPS) — it is unavailable on plain HTTP origins.
  • requestDevice() needs transient user activation (a click or keypress handler); without it, the returned promise rejects with a SecurityError DOMException.
  • claimInterface() claims a specific interface for exclusive use: only one execution context can hold a given interface at a time, and it must be released with releaseInterface() (or the device closed) before another context can claim it.
  • The picker only lists devices matching the filters you pass, so a request with no matching device leaves the user with nothing to select, which rejects the returned promise.
  • Firefox and Safari do not implement the API, so 'usb' in navigator is false there and any USB-dependent flow needs the fallback path above.

For the full reference (device pairing, permission model, landing pages), see WebUSB API.

See also Web Bluetooth API for the equivalent flow over Bluetooth.

← Back to the Compatibility explorer.