WebHID API
repository·main·Indexed 41 days ago
https://github.com/wicg/webhidThe WebHID API allows web applications to communicate directly with Human Interface Devices (HID), such as gamepads, custom controllers, or medical devices. It provides methods for requesting device permissions via navigator.hid.requestDevice(), managing connections, and exchanging data through input, output, and feature reports. Available in Chromium 89 and later, the API requires secure contexts (HTTPS) and explicit user consent to access hardware.
What's inside WebHID
- The WebHID API provides a way for web applications to interact with Human Interface Devices (HID) directly. It brings the capabilities of the native HID API to the web platform, allowing developers to communicate with specialized hardware like gamepads, custom controllers, or medical devices that use the HID protocol.
Security and privacy mitigations in WebHID
mainWebHID implements several security and privacy protections to prevent unauthorized data access and fingerprinting:
- Secure Contexts Only: Access to the WebHID API is restricted to secure contexts (HTTPS).
- Explicit User Consent: No device information is exposed to a script by default. A user must explicitly grant access to a specific device by selecting it from a device chooser list. Information about devices not selected by the user is not exposed.
- High-Value Data Protection: To prevent credential theft, FIDO devices are excluded from the device chooser. While keyboards and pointer devices (mice, touchscreens) may appear in the chooser, reports containing keyboard or pointer information are blocked and not delivered to the script.
- Incognito Mode: Device permissions granted during an incognito session must not persist once the session is closed.
Privacy implications of WebHID device access
mainDevelopers should be aware of the following privacy considerations when using WebHID:
- Fingerprinting: Information about connected peripherals can potentially be used to fingerprint a user. This is mitigated by the requirement for explicit user selection via a chooser.
- Sensor Access: Many sensors are implemented as HID peripherals; WebHID allows access to these sensors if the user grants permission.
- Local Environment Exposure: WebHID allows an origin to see a list of devices for which it has already been granted access and to send/receive data from them, which may reveal aspects of the user's local computing environment.
- Cross-Origin Communication: Device access is not exclusive. If multiple origins are granted access to the same device, they can potentially use that device to communicate across origins.
Access WebHID in Extension Service Workers
mainIn browser extensions, the
navigator.hidinterface is exposed within the Service Worker context. This allows extension developers to manage HID devices from a service worker rather than relying solely on a background page. Note thatnavigator.hidis only exposed to Service Workers when running within a browser extension context.[Exposed=(Window,ServiceWorker), SecureContext] interface HID : EventTarget { attribute EventHandler onconnect; attribute EventHandler ondisconnect; Promise<sequence<HIDDevice>> getDevices(); Promise<sequence<HIDDevice>> requestDevice( HIDDeviceRequestOptions options); };Understand HID terminology
mainTo work with WebHID, it is helpful to understand these core concepts:
- HID (Human Interface Device): A standard protocol for bi-directional communication between a host and a device (e.g., USB or Bluetooth).
- HID Report: A binary data packet. Input reports go from device to host; Output reports go from host to device; Feature reports can go in either direction.
- HID Report Descriptor: A hierarchical structure requested during enumeration that describes the binary format of the reports supported by the device.
- HID Usage: A numeric value (organized into Usage Pages) that describes the purpose of a device or a specific field within a report (e.g., a button or a joystick axis).
Request HID device permissions from a page
mainThe
requestDevice()method cannot be called directly from a Service Worker because it requires displaying a permission dialog to the user, and service workers cannot show UI elements.To request device permissions, you must call
requestDevice()from aWindowobject (a web page). If you attempt to callrequestDevice()from a Service Worker context, the method will throw aNotSupportedError.How to request and connect to HID devices
mainTo interact with a HID device, you must first request permission from the user via
navigator.hid.requestDevice(). This method displays a chooser dialog. Once the user selects a device, the returnedHIDDevicemust be explicitly opened using.open()before any data can be exchanged.You can also listen for global connection and disconnection events on
navigator.hidto manage devices being plugged in or removed from the system.let deviceFilter = { vendorId: 0x1234, productId: 0xabcd }; let requestParams = { filters: [deviceFilter] }; // 1. Listen for connection events navigator.hid.addEventListener("connect", (e) => { console.log("Device connected: " + e.device.productName); }); // 2. Request a device (requires user gesture) navigator.hid.requestDevice(requestParams).then((devices) => { if (devices.length == 0) return; const device = devices[0]; // 3. Open the device device.open().then(() => { console.log("Opened device: " + device.productName); // 4. Listen for input reports device.addEventListener("inputreport", (e) => { console.log(e.device.productName + ": got input report " + e.reportId); console.log(new Uint8Array(e.data.buffer)); }); // 5. Send an output report const outputReportId = 0x01; const outputReport = new Uint8Array([42]); device.sendReport(outputReportId, outputReport).then(() => { console.log("Sent output report " + outputReportId); }); }); });Inspect HID device collections and report structures
mainThe
HIDDevice.collectionsattribute provides a hierarchical description of the device's report formats viaHIDCollectionInfo. This allows applications to understand the device's capabilities (like which buttons or axes are available) without manual trial-and-error.Each collection contains:
usagePageandusage: Identifying the type of control.inputReports,outputReports, andfeatureReports: Arrays ofHIDReportInfodescribing the available report formats.children: NestedHIDCollectionInfoobjects.
Use the HID interface in Service Workers
mainOnce permission has been granted via a page, you can interact with HID devices in the Service Worker using the
navigator.hidinterface. The interface provides the following methods and events:getDevices(): Returns aPromisethat resolves to a list ofHIDDeviceobjects that the user has already granted permission for.onconnect: An event handler triggered when a device is connected.ondisconnect: An event handler triggered when a device is disconnected.
Use the HID interface via navigator.hid
mainThe
navigator.hidobject is the entry point for the WebHID API. It is used to manage device permissions and listen for connection changes.Key methods:
getDevices(): Returns aPromiseresolving to an array ofHIDDeviceobjects that the user has previously granted permission for.requestDevice(options): Displays a browser UI to let the user select a device. Returns aPromiseresolving to asequence<HIDDevice>.
Events:
connect: Fired when a device the page has permission for is connected.disconnect: Fired when a device the page has permission for is disconnected.
Communicate with an open HIDDevice
mainOnce an
HIDDeviceis opened via.open(), you can perform bi-directional communication using reports:- Input Reports: Listen for data sent from the device using the
inputreportevent. The event provides thereportIdand aDataViewcontaining thedata. - Output Reports: Send data to the device using
.sendReport(reportId, data). Thedatamust be aBufferSource. - Feature Reports: Use
.sendFeatureReport(reportId, data)to send data or.receiveFeatureReport(reportId)to request data from the device. Both returnPromises.
// Example of sending an output report await device.sendReport(0x01, new Uint8Array([0x42])); // Example of listening for input reports device.addEventListener("inputreport", (event) => { const { reportId, data } = event; // data is a DataView }); // Example of feature reports await device.sendFeatureReport(0x02, new Uint8Array([0x01])); const featureData = await device.receiveFeatureReport(0x02);- Input Reports: Listen for data sent from the device using the
Configure HID device filters
mainWhen calling
requestDevice(), you can provideHIDDeviceRequestOptionsto narrow down the devices shown to the user. This is done usingfilters(required) andexclusionFilters(optional).A
HIDDeviceFiltercan match devices based on:vendorId: The USB vendor ID.productId: The USB product ID.usagePage: The HID usage page.usage: The specific HID usage.
// Example of a filter object { "filters": [ { "vendorId": 0x1234, "productId": 0xabcd } ] }