WebHID in Chrome Extensions: Connect to Hardware Devices (2026)
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
| Page | Hex | Description |
|---|---|---|
| Generic Desktop | 0x01 | Keyboards, mice, joysticks |
| Consumer | 0x0C | Media controls, volume |
| Digitizer | 0x0D | Touch, stylus |
| LED | 0x08 | LED indicators |
| Vendor-defined | 0xFF00+ | 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
I Built the Same Chrome Extension With 5 Different Frameworks. Here's What Actually Happened.
WXT vs Plasmo vs CRXJS vs Extension.js vs Bedframe. Real benchmarks, honest opinions, and the framework with 12K stars that's quietly dying.
5 Best Email Marketing Services to Grow Your Chrome Extension (2026)
Compare the top email marketing platforms for SaaS and Chrome extension developers. MailerLite, Mailchimp, Brevo, ActiveCampaign, and Drip reviewed.
15 Best Practices to Build a Browser Extension That Users Love (2026 Guide)
Master browser extension development in 2026. Manifest V3, security, performance, and UX best practices to build extensions users love.