Connecting to uncommon HID devices Stay organized with collections Save and categorize content based on your preferences.
The WebHID API allows websites to access alternative auxiliary keyboards and exotic gamepads.
Success: The WebHID API, part of thecapabilities project, launched inChrome 89.There is a long tail of human interface devices (HIDs), such as alternativekeyboards or exotic gamepads, that are too new, too old, or too uncommon to beaccessible by systems' device drivers. The WebHID API solves this by providing away to implement device-specific logic in JavaScript.
Suggested use cases
An HID device takes input from or provides output to humans. Examples of devicesinclude keyboards, pointing devices (mice, touchscreens, etc.), and gamepads.TheHID protocol makes it possible to access these devices on desktopcomputers using operating system drivers. The web platform supports HID devicesby relying on these drivers.
The inability to access uncommon HID devices is particularly painful when itcomes to alternative auxiliary keyboards (e.g.Elgato Stream Deck,Jabraheadsets,X-keys) and exotic gamepad support. Gamepads designed for desktopoften use HID for gamepad inputs (buttons, joysticks, triggers) and outputs(LEDs, rumble). Unfortunately, gamepad inputs and outputs are not wellstandardized and web browsers often require custom logic for specific devices.This is unsustainable and results in poor support for the long tail of older anduncommon devices. It also causes the browser to depend on quirks in the behaviorof specific devices.
Terminology
HID consists of two fundamental concepts: reports and report descriptors.Reports are the data that is exchanged between a device and a software client.The report descriptor describes the format and meaning of data that the devicesupports.
An HID (Human Interface Device) is a type of device that takes input from orprovides output to humans. It also refers to the HID protocol, a standard forbi-directional communication between a host and a device that is designed tosimplify the installation procedure. The HID protocol was originally developedfor USB devices, but has since been implemented over many other protocols,including Bluetooth.
Applications and HID devices exchange binary data through three report types:
Report type | Description |
---|---|
Input report | Data that is sent from the device to the application (e.g. a button is pressed.) |
Output report | Data that is sent from the application to the device (e.g. a request to turn on the keyboard backlight.) |
Feature report | Data that may be sent in either direction. The format is device-specific. |
A report descriptor describes the binary format of reports supported by thedevice. Its structure is hierarchical and can group reports together as distinctcollections within the top-level collection. Theformat of the descriptor isdefined by the HID specification.
An HID usage is a numeric value referring to a standardized input or output.Usage values allow a device to describe the intended use of the device and thepurpose of each field in its reports. For example, one is defined for the leftbutton of a mouse. Usages are also organized into usage pages, which provide anindication of the high-level category of the device or report.
Using the WebHID API
Feature detection
To check if the WebHID API is supported, use:
if("hid"innavigator){// The WebHID API is supported.}
Open an HID connection
The WebHID API is asynchronous by design to prevent the website UI fromblocking when awaiting input. This is important because HID data can be receivedat any time, requiring a way to listen to it.
To open an HID connection, first access aHIDDevice
object. For this, you caneither prompt the user to select a device by callingnavigator.hid.requestDevice()
, or pick one fromnavigator.hid.getDevices()
which returns a list of devices the website has been granted access topreviously.
Thenavigator.hid.requestDevice()
function takes a mandatory object thatdefines filters. Those are used to match any device connected with a USB vendoridentifier (vendorId
), a USB product identifier (productId
), a usage pagevalue (usagePage
), and a usage value (usage
). You can get those fromtheUSB ID Repository and theHID usage tables document.
The multipleHIDDevice
objects returned by this function represent multipleHID interfaces on the same physical device.
// Filter on devices with the Nintendo Switch Joy-Con USB Vendor/Product IDs.constfilters=[{vendorId:0x057e,// Nintendo Co., LtdproductId:0x2006// Joy-Con Left},{vendorId:0x057e,// Nintendo Co., LtdproductId:0x2007// Joy-Con Right}];// Prompt user to select a Joy-Con device.const[device]=awaitnavigator.hid.requestDevice({filters});
// Get all devices the user has previously granted the website access to.constdevices=awaitnavigator.hid.getDevices();

You can also use the optionalexclusionFilters
key innavigator.hid.requestDevice()
to exclude some devices from the browser pickerthat are known to be malfunctioning for instance.
// Request access to a device with vendor ID 0xABCD. The device must also have// a collection with usage page Consumer (0x000C) and usage ID Consumer// Control (0x0001). The device with product ID 0x1234 is malfunctioning.const[device]=awaitnavigator.hid.requestDevice({filters:[{vendorId:0xabcd,usagePage:0x000c,usage:0x0001}],exclusionFilters:[{vendorId:0xabcd,productId:0x1234}],});
AHIDDevice
object contains USB vendor and product identifiers for deviceidentification. Itscollections
attribute is initialized with a hierarchicaldescription of the device's report formats.
for(letcollectionofdevice.collections){// An HID collection includes usage, usage page, reports, and subcollections.console.log(`Usage:${collection.usage}`);console.log(`Usage page:${collection.usagePage}`);for(letinputReportofcollection.inputReports){console.log(`Input report:${inputReport.reportId}`);// Loop through inputReport.items}for(letoutputReportofcollection.outputReports){console.log(`Output report:${outputReport.reportId}`);// Loop through outputReport.items}for(letfeatureReportofcollection.featureReports){console.log(`Feature report:${featureReport.reportId}`);// Loop through featureReport.items}// Loop through subcollections with collection.children}
TheHIDDevice
devices are by default returned in a "closed" state and must beopened by callingopen()
before data can be sent or received.
// Wait for the HID connection to open before sending/receiving data.awaitdevice.open();
Receive input reports
Once the HID connection has been established, you can handle incoming inputreports by listening to the"inputreport"
events from the device. Those eventscontain the HID data as aDataView
object (data
), the HID device it belongsto (device
), and the 8-bit report ID associated with the input report(reportId
).

Continuing with the previous example, the code below shows you how to detectwhich button the user has pressed on a Joy-Con Right device so that you canhopefully try it at home.
device.addEventListener("inputreport",event=>{const{data,device,reportId}=event;// Handle only the Joy-Con Right device and a specific report ID.if(device.productId!==0x2007 &&reportId!==0x3f)return;constvalue=data.getUint8(0);if(value===0)return;constsomeButtons={1:"A",2:"X",4:"B",8:"Y"};console.log(`User pressed button${someButtons[value]}.`);});
See the Penwebhid-joycon-button demo.
Send output reports
To send an output report to an HID device, pass the 8-bit report ID associatedwith the output report (reportId
) and bytes as aBufferSource
(data
) todevice.sendReport()
. The returned promise resolves once the report has beensent. If the HID device does not use report IDs, setreportId
to 0.
The example below applies to a Joy-Con device and shows you how to make itrumble with output reports.
// First, send a command to enable vibration.// Magical bytes come from https://github.com/mzyy94/joycon-toolwebconstenableVibrationData=[1,0,1,64,64,0,1,64,64,0x48,0x01];awaitdevice.sendReport(0x01,newUint8Array(enableVibrationData));// Then, send a command to make the Joy-Con device rumble.// Actual bytes are available in the sample below.construmbleData=[/* ... */];awaitdevice.sendReport(0x10,newUint8Array(rumbleData));
See the Penwebhid-joycon-rumble demo.
Send and receive feature reports
Feature reports are the only type of HID data reports that can travel in bothdirections. They allow HID devices and applications to exchange non standardizedHID data. Unlike input and output reports, feature reports are not received orsent by the application on a regular basis.

To send a feature report to an HID device, pass the 8-bit report ID associatedwith the feature report (reportId
) and bytes as aBufferSource
(data
) todevice.sendFeatureReport()
. The returned promise resolves once the report hasbeen sent. If the HID device does not use report IDs, setreportId
to 0.
The example below illustrates the use of feature reports by showing you how torequest an Apple keyboard backlight device, open it, and make it blink.
constwaitFor=duration=>newPromise(r=>setTimeout(r,duration));// Prompt user to select an Apple Keyboard Backlight device.const[device]=awaitnavigator.hid.requestDevice({filters:[{vendorId:0x05ac,usage:0x0f,usagePage:0xff00}]});// Wait for the HID connection to open.awaitdevice.open();// Blink!constreportId=1;for(leti=0;i <10;i++){// Turn offawaitdevice.sendFeatureReport(reportId,Uint32Array.from([0,0]));awaitwaitFor(100);// Turn onawaitdevice.sendFeatureReport(reportId,Uint32Array.from([512,0]));awaitwaitFor(100);}
See the Penwebhid-apple-keyboard-backlight demo.
To receive a feature report from an HID device, pass the 8-bit report IDassociated with the feature report (reportId
) todevice.receiveFeatureReport()
. The returned promise resolves with aDataView
object that contains the contents of the feature report. If the HIDdevice does not use report IDs, setreportId
to 0.
// Request feature report.constdataView=awaitdevice.receiveFeatureReport(/* reportId= */1);// Read feature report contents with dataView.getInt8(), getUint8(), etc...
Listen to connection and disconnection
When the website has been granted permission to access an HID device, it canactively receive connection and disconnection events by listening to"connect"
and"disconnect"
events.
navigator.hid.addEventListener("connect",event=>{// Automatically open event.device or warn user a device is available.});navigator.hid.addEventListener("disconnect",event=>{// Remove |event.device| from the UI.});
Revoke access to an HID device
The website can clean up permissions to access an HID device it is no longerinterested in retaining by callingforget()
on theHIDDevice
instance. Forexample, for an educational web application used on a shared computer with manydevices, a large number of accumulated user-generated permissions creates a pooruser experience.
Callingforget()
on a singleHIDDevice
instance will revoke access to allthe HID interfaces on the same physical device.
// Voluntarily revoke access to this HID device.awaitdevice.forget();
Asforget()
is available in Chrome 100 or later, check if this feature issupported with the following:
if("hid"innavigator &&"forget"inHIDDevice.prototype){// forget() is supported.}
Dev Tips
Debugging HID in Chrome is easy with the internal page,about://device-log
where you can see all HID and USB device related events in one single place.

Check out theHID explorer for dumping HID deviceinfo into a human-readable format. It maps from usage values to names for eachHID usage.
On most Linux systems, HID devices are mapped with read-only permissions bydefault. To allow Chrome to open an HID device, you will need to add a newudevrule. Create a file at/etc/udev/rules.d/50-yourdevicename.rules
with thefollowing content:
KERNEL=="hidraw*", ATTRS{idVendor}=="[yourdevicevendor]", MODE="0664", GROUP="plugdev"
In the line above,[yourdevicevendor]
is057e
if your device is a Nintendo SwitchJoy-Con for instance.ATTRS{idProduct}
can also be added for a more specificrule. Make sure youruser
is amember of theplugdev
group. Then, justreconnect your device.
Browser support
The WebHID API is available on all desktop platforms (ChromeOS, Linux, macOS,and Windows) in Chrome 89.
Demos
Some WebHID demos are listed atweb.dev/hid-examples. Go have a look!
Security and privacy
The spec authors have designed and implemented the WebHID API using the coreprinciples defined inControlling Access to Powerful Web Platform Features,including user control, transparency, and ergonomics. The ability to use thisAPI is primarily gated by a permission model that grants access to only a singleHID device at a time. In response to a user prompt, the user must take activesteps to select a particular HID device.
To understand the security tradeoffs, check out theSecurity and PrivacyConsiderations section of the WebHID spec.
On top of this, Chrome inspects the usage of each top-level collection and if atop-level collection has a protected usage (e.g. generic keyboard, mouse), thena website won't be able to send and receive any reports defined in thatcollection. The full list of protected usages ispublicly available.
Note that security-sensitive HID devices (such as FIDO HID devices used forstronger authentication) are also blocked in Chrome. See theUSB blocklist andHID blocklist files.
Feedback
The Chrome team would love to hear about your thoughts and experiences with theWebHID API.
Tell us about the API design
Is there something about the API that doesn't work as expected? Or are theremissing methods or properties that you need to implement your idea?
File a spec issue on theWebHID API GitHub repo or add your thoughtsto an existing issue.
Report a problem with the implementation
Did you find a bug with Chrome's implementation? Or is the implementationdifferent from the spec?
Check outHow to file WebHID bugs. Be sure to include as muchdetail as you can, provide simple instructions for reproducing the bug, and haveComponents set toBlink>HID
.
Show support
Are you planning to use the WebHID API? Your public support helps the Chrometeam prioritize features and shows other browser vendors how critical it is tosupport them.
Send a tweet to@ChromiumDev using the hashtag#WebHID
and let us knowwhere and how you're using it.
Helpful links
- Specification
- Tracking bug
- ChromeStatus.com entry
- Blink Component:
Blink>HID
Acknowledgements
Thanks toMatt Reynolds andJoe Medley for their reviews of this article.Red and blue Nintendo Switch photo bySara Kurfeß, and black and silver laptopcomputer photo byAthul Cyriac Ajay on Unsplash.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2020-09-15 UTC.