How WebHID Connects Browsers to Custom HID Devices
The WebHID API allows web applications to communicate directly with Human Interface Devices (HIDs) that are too new, too rare, or too specific to be supported by standard browser APIs. By exposing low-level HID input and output reports to JavaScript, this API enables web software to interact with specialized hardware—such as custom game controllers, flight simulators, hardware status displays, medical tools, and specialized keyboards—directly within a secure browser context.
The Problem with Standard Input APIs
Browsers traditionally rely on high-level APIs like
KeyboardEvent, MouseEvent, or the
Gamepad API to receive user input. These interfaces rely on
the host operating system’s generic drivers, which standardize input
into basic actions like key presses, pointer movements, or standard
joystick axis shifts.
When a hardware device includes non-standard features—such as custom programmable buttons, auxiliary LCD displays, RGB lighting configurations, or proprietary sensor data—the generic operating system drivers often ignore these inputs. WebHID solves this by providing access to the raw HID data layer without requiring native companion apps or vendor-specific OS drivers.
Requesting Device Access and Permissions
Because direct hardware communication introduces security risks, WebHID requires explicit user consent and works only in secure contexts (HTTPS).
Communication begins by requesting access through
navigator.hid.requestDevice(). Developers can pass filters
containing vendor IDs, product IDs, or usage page identifiers to narrow
down the hardware choices presented to the user:
const filters = [{ vendorId: 0x1234, productId: 0xabcd }];
const [device] = await navigator.hid.requestDevice({ filters });
if (device) {
await device.open();
console.log(`Connected to: ${device.productName}`);
}Once granted, the browser stores the permission, allowing subsequent
visits to query previously authorized devices using
navigator.hid.getDevices().
Handling Input Reports
HIDs communicate changes in state via “Input Reports,” which are
binary buffers structured according to the device’s HID report
descriptor. When connected, JavaScript listens for these reports using
the inputreport event.
device.addEventListener("inputreport", (event) => {
const { data, device, reportId } = event;
// data is a DataView containing the raw bytes sent by the hardware
const buttonState = data.getUint8(0);
console.log(`Report ${reportId}: Raw State = ${buttonState}`);
});Using JavaScript’s DataView or Uint8Array,
developers can unpack the raw binary data to interpret custom sensor
streams, proprietary switch combinations, or measurement values.
Sending Output and Feature Reports
WebHID communication is bidirectional. JavaScript can send control signals back to the hardware via Output Reports (used for real-time states like force feedback or LED statuses) and Feature Reports (used for configuration settings).
- Output Reports: Transmitted using
device.sendReport(reportId, data)to trigger immediate device actions like rumble motors or updating an integrated display. - Feature Reports: Retrieved using
device.receiveFeatureReport(reportId)and applied usingdevice.sendFeatureReport(reportId, data)to read or modify onboard settings, such as polling rates or key-mapping profiles.
Security and Protected Devices
To prevent malicious websites from capturing sensitive credentials or hijacking critical OS controls, WebHID enforces strict safety boundaries: * Top-Level Security: WebHID cannot be invoked inside insecure contexts or third-party iframes without explicit permission policies. * Blocklist Enforcement: The underlying platform maintains a blocklist that blocks access to standard system input devices (like the primary OS keyboard and mouse) to prevent keylogging and input sniffing.
Through structured permission prompts, binary data streaming, and bidirectional report handling, WebHID bridges the gap between web applications and specialized hardware peripherals.