WebHID in Chrome Extensions: Connect to Hardware Devices (2026)

AppBooster Team · · 3 min read
Hardware devices connected to a computer

What Is WebHID and Why Use It in Extensions?

WebHID (Human Interface Device) enables bidirectional communication between your Chrome extension and hardware devices — keyboards, gamepads, barcode scanners, LED controllers, and more. Any device that uses the HID protocol can be accessed.

Chrome extensions are ideal for WebHID because they persist in the background, run across all tabs, and can react to device input globally — something regular web pages can’t do.

Requirements: Chrome 117+. No special manifest permissions needed.


The Service Worker Limitation

navigator.hid.requestDevice() cannot be called from a service worker — it requires a user gesture in a visible UI context. The solution: request device access from a popup or options page, then use the device from the service worker.


Implementation Pattern

popup.js — Device Selection

document.getElementById('connect-btn').addEventListener('click', async () => {
  try {
    const [device] = await navigator.hid.requestDevice({
      filters: [
        { vendorId: 0x1234, productId: 0x5678 },
        { usagePage: 0x01, usage: 0x06 } // Generic Desktop — Keyboard
      ]
    });

    if (device) {
      document.getElementById('status').textContent = `Connected: ${device.productName}`;
      chrome.runtime.sendMessage({ action: 'deviceSelected' });
    }
  } catch (error) {
    document.getElementById('status').textContent = `Error: ${error.message}`;
  }
});

service-worker.js — Device Communication

chrome.runtime.onMessage.addListener(async (message) => {
  if (message.action === 'deviceSelected') {
    const devices = await navigator.hid.getDevices();

    for (const device of devices) {
      if (!device.opened) {
        await device.open();
      }

      device.addEventListener('inputreport', (event) => {
        const { data, reportId } = event;
        const value = data.getUint8(0);
        handleDeviceInput(reportId, value);
      });

      // Send data to device
      const outputData = new Uint8Array([0x01, 0x00, 0xFF]);
      await device.sendReport(0x00, outputData);
    }
  }
});

function handleDeviceInput(reportId, value) {
  console.log(`Report ${reportId}: ${value}`);

  // Example: update badge based on device input
  chrome.action.setBadgeText({ text: String(value) });
}

Device Filters

Filter devices by vendor/product ID or HID usage:

// Specific device
{ vendorId: 0x1234, productId: 0x5678 }

// By HID usage page
{ usagePage: 0x01 }           // Generic Desktop Controls
{ usagePage: 0x01, usage: 0x04 } // Joystick
{ usagePage: 0x01, usage: 0x05 } // Game Pad
{ usagePage: 0x0C }           // Consumer Control (media keys)
{ usagePage: 0x0D }           // Digitizers (touchscreen, pen)

Common HID Usage Pages

PageHexDescription
Generic Desktop0x01Keyboards, mice, joysticks
Consumer0x0CMedia controls, volume
Digitizer0x0DTouch, stylus
LED0x08LED indicators
Vendor-defined0xFF00+Custom device protocols

Sending and Receiving Data

Feature Reports (Configuration)

// Read device configuration
const featureReport = await device.receiveFeatureReport(reportId);
const config = new DataView(featureReport.buffer);

// Write configuration
const data = new Uint8Array([0x01, 0x02, 0x03]);
await device.sendFeatureReport(reportId, data);

Output Reports (Commands)

// Send LED color command to a device
const colorData = new Uint8Array([
  0x01,  // Command: set color
  0xFF,  // Red
  0x00,  // Green
  0x80   // Blue
]);
await device.sendReport(0x00, colorData);

Keeping the Connection Alive

Active HID connections keep the service worker alive. However, if the device disconnects:

navigator.hid.addEventListener('disconnect', (event) => {
  console.log(`Device disconnected: ${event.device.productName}`);
  chrome.action.setBadgeText({ text: '!' });
});

navigator.hid.addEventListener('connect', (event) => {
  console.log(`Device connected: ${event.device.productName}`);
  // Auto-reconnect if previously paired
  reconnectDevice(event.device);
});

What’s Next

WebHID opens up powerful hardware integration possibilities for Chrome extensions. Request device access from your popup, communicate from the service worker, and build experiences that bridge the gap between web and hardware.

Explore more extension capabilities at ExtensionBooster.

Share this article

Build better extensions with free tools

Icon generator, MV3 converter, review exporter, and more — no signup needed.

Related Articles