Talk to Real Hardware From a Web Page.
No plugins, no Electron, no native drivers to install: modern Chromium can open serial ports, pair with Bluetooth devices, read raw HID input, flash USB microcontrollers, and receive MIDI — all from JavaScript, all permission-gated. This guide covers each API with working patterns and the honest limits (because every one of these has sharp edges).
Universal rules first: these APIs require HTTPS (or localhost), a user gesture to request access, and — with few exceptions — they are Chromium-only. If your users are on Firefox or Safari, you need a fallback plan.
Web Serial: Arduino and IoT debugging
The most practical of the bunch. Talk to Arduinos, ESP32s, and industrial controllers over USB-serial straight from the page:
await port.open({ baudRate: 115200 });
const writer = port.writable.getWriter();
await writer.write(new TextEncoder().encode('LED_ON\n'));
writer.releaseLock();
// Reading: port.readable is a stream of Uint8Array chunks.
const reader = port.readable.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) break;
console.log(new TextDecoder().decode(value));
}
Same API works for industrial hardware — PLCs, sensors, barcode scanners — anything speaking serial. Always releaseLock() your readers/writers and close() the port, or the device stays locked until the tab closes.
WebUSB: flashing microcontrollers
Serial covers UART devices; WebUSB goes lower — raw USB transfers for flashing firmware or talking to devices without a serial interface:
filters: [{ vendorId: 0x2341 }] // e.g. Arduino's VID
});
await device.open();
await device.selectConfiguration(1);
await device.claimInterface(0);
// Now: device.transferOut(endpoint, firmwareChunk)
Honest caveat: the OS must not have already claimed the device with a kernel driver, and devices in bootloader/DFU mode sometimes need specific handling. This is genuinely how browser-based firmware flashers (like ESP Web Tools) work — it's production-proven, just fiddly.
WebHID: raw keyboards and custom controllers
WebHID exposes Human Interface Devices at the raw report level — great for custom macro pads, game controllers, and reading keyboard scancodes the OS would normally swallow:
await device.open();
device.addEventListener('inputreport', (e) => {
const { data, reportId } = e;
handleRawInput(reportId, new Uint8Array(data.buffer));
});
Security note: for obvious reasons, the browser blocks access to protected usages like standard keyboards and mice via WebHID — you get niche/custom devices, not a keylogger API.
Web Bluetooth: BLE peripherals
Connect to Bluetooth Low Energy devices — heart-rate monitors, smart bulbs, sensor tags:
filters: [{ services: ['battery_service'] }]
});
const server = await device.gatt.connect();
const service = await server.getPrimaryService('battery_service');
const char = await service.getCharacteristic('battery_level');
const value = await char.readValue();
console.log('Battery:', value.getUint8(0) + '%');
Web Bluetooth realities: GATT only — no classic Bluetooth audio. Range and reliability vary wildly by OS. And every connection starts with a browser picker the page can't bypass; there's no silent background scanning for websites.
Web MIDI: hardware knobs for your app
MIDI controllers make fantastic physical interfaces — map knobs to app parameters, pads to macros:
for (const input of access.inputs.values()) {
input.onmidimessage = (e) => {
const [status, note, velocity] = e.data;
if (status === 144 && velocity > 0) triggerMacro(note);
};
}
Fun fact: this works for far more than music. A $30 MIDI pad becomes 16 physical macro buttons for any web app — streamers and video editors have used this trick for years.
WebNN: local AI, with eyes open
WebNN (navigator.ml) promises GPU/NPU-accelerated ML inference in the browser. The honest status: it's still emerging, with real implementations only in some Chromium builds and APIs that have changed between drafts. If you need local inference today, WASM-based runtimes (like ONNX Runtime Web or Transformers.js) are the proven path; keep an eye on WebNN for the future.
Prototype the dashboard in NitroIDE: every snippet above runs in a real browser preview. Build your device dashboard UI — charts, controls, log viewers — against mocked data first, then wire in the hardware APIs when you're on a machine with the actual device plugged in.
Build Hardware Dashboards in the Browser.
Prototype device UIs with zero setup — then connect real hardware.
Launch NitroIDE