Web APIs, todayLab · Alex Harto

WebHID

Uncommon HID devices from a web page: special controllers, pedals, tablets, programmable keyboards…

In your browser: checking…Reviewed 1 Oct 2026

HID is the protocol behind keyboards, mice and controllers. WebHID lets a page talk to devices the operating system does not fully handle: it reads their raw input reports and sends them output and feature reports (lights, rumble, configuration).

Desktop Chrome and Edge only, since 89. Chrome for Android has it as a developer trial in 154 and plans to ship it in 157. Mozilla and WebKit oppose it on security grounds.

What it is for

  • Configuring peripherals without installing software
  • Advanced controller features (lights, gyroscope)
  • Pedals, button boxes and studio controllers

Demo

Connect a HID device and pick it in the chooser: a PlayStation or Switch controller, a drawing tablet, a pedal, a button box… You will see its raw input reports, byte by byte; changing bytes light up. Keyboards and mice are blocked for security.

Browser support

Limited availability
FeatureDesktopMobile
ChromeEdgeFirefoxSafariChrome AndroidFirefox AndroidSafari iOS
navigator.hid89Chrome: 89 89Edge: 89 —Firefox: No—Safari: No154flag1Chrome: 154 flag—Firefox: No—Safari: No
  1. 1Developer trial in 154; planned to ship in Chrome 157.

Compatibility generated on every deploy from MDN browser-compat-data 8.1.3 (24 Sep 2026) · web-features 3.40.0 · checked by hand: 1 Oct 2026

Minimal code

<!doctype html>
<meta charset="utf-8">
<title>WebHID · ejemplo mínimo</title>
<!-- Lee los informes de entrada en bruto de un dispositivo HID (mando, teclado especial, pedal…).
     Chrome y Edge de escritorio. HTTPS o localhost. -->
<button id="connect">Conectar dispositivo HID</button>
<pre id="out"></pre>
<script>
  const out = document.querySelector('#out');
  const hex = (view) => [...new Uint8Array(view.buffer, view.byteOffset, view.byteLength)].map((b) => b.toString(16).padStart(2, '0')).join(' ');

  document.querySelector('#connect').onclick = async () => {
    if (!('hid' in navigator)) return (out.textContent = 'WebHID no está disponible en este navegador.');
    // Sin filtros se listan todos; en producción filtra por vendorId/productId o por usagePage
    const [device] = await navigator.hid.requestDevice({ filters: [] });
    if (!device) return;
    await device.open();
    out.textContent = `${device.productName} · vendor 0x${device.vendorId.toString(16)} · product 0x${device.productId.toString(16)}\n`;
    device.addEventListener('inputreport', (e) => {
      out.textContent = `${device.productName}\ninforme ${e.reportId}: ${hex(e.data)}`;
    });
  };

  // Los dispositivos ya autorizados vuelven sin preguntar
  navigator.hid?.getDevices().then((devices) => devices.length && console.log('Autorizados:', devices));
</script>

What’s new

  1. Chrome 154 for Android: developer trial; planned to ship in Chrome 157.
  2. Intent to Prototype for WebHID on Android.
  3. WHATWG opens a hardware workstream, for now covering Web Serial only; WebHID and the rest are on hold.

Keep in mind

  1. requestDevice() needs a user gesture; getDevices() returns already-authorised devices without asking.
  2. Keyboards, mice and other sensitive devices are blocked by design.
  3. Works in dedicated workers since Chrome 131 (but requestDevice() only in the window).

Further reading

Sources