The Web Serial API allows websites to communicate with serial devices — microcontrollers, 3D printers, GPS receivers, oscilloscopes — connected via physical serial ports, USB-to-serial adapters, or Bluetooth serial emulation. Launched in Chrome 89, it is the successor to workarounds involving native helper apps or WebUSB serial emulation.
馃搶 What Is the Web Serial API?
Serial communication is one of the oldest and most widely-used protocols in computing. Almost every microcontroller (Arduino, ESP32, Raspberry Pi Pico, STM32, etc.) has a UART interface. The Web Serial API wraps the native OS serial port API and exposes it to JavaScript through the Streams API — making reads and writes asynchronous and composable.
Key distinction: Web Serial works with devices that expose a serial port to the OS (via CDC-ACM USB class or Bluetooth SPP) — not with raw USB endpoints. For raw USB access, use WebUSB. For HID devices, use WebHID.
馃寪 Browser Support
| Browser | Support | Notes |
|---|---|---|
| Chrome 89+ (Desktop) | ✅ Full support | Windows, Mac, Linux, ChromeOS. Not Android (OS limitation). |
| Edge 89+ (Desktop) | ✅ Full support | Chromium-based Edge, same as Chrome. |
| Firefox | ❌ Not supported | Not on Firefox roadmap. Position: not harmful but not prioritised. |
| Safari | ❌ Not supported | Apple has not shipped Web Serial API. |
⚙️ How It Works — The API
// Feature detection
if ('serial' in navigator) { /* supported */ }
// 1. Request a port — requires user gesture
const port = await navigator.serial.requestPort({
filters: [{ usbVendorId: 0x2341 }] // Arduino
});
// 2. Open at 9600 baud
await port.open({ baudRate: 9600 });
// 3. Read data using Streams API
const reader = port.readable.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) { reader.releaseLock(); break; }
console.log(new TextDecoder().decode(value));
}
// 4. Write data
const writer = port.writable.getWriter();
await writer.write(new TextEncoder().encode('hello
'));
writer.releaseLock();
// 5. Close the port
await port.close();馃攢 Reading with Transform Streams
Serial data arrives in arbitrary chunks. Transform streams let you parse it into meaningful units:
// Parse incoming serial data line-by-line
const textDecoder = new TextDecoderStream();
port.readable.pipeTo(textDecoder.writable);
const reader = textDecoder.readable
.pipeThrough(new TransformStream(new LineBreakTransformer()))
.getReader();
class LineBreakTransformer {
constructor() { this.chunks = ''; }
transform(chunk, controller) {
this.chunks += chunk;
const lines = this.chunks.split('\r\n');
this.chunks = lines.pop();
lines.forEach(l => controller.enqueue(l));
}
flush(controller) { controller.enqueue(this.chunks); }
}馃彚 Who Uses Web Serial?
| Project | Use Case | URL |
|---|---|---|
| Arduino Create / Cloud | Serial monitor for Arduino boards in browser | create.arduino.cc |
| Betaflight Configurator | Configure drone flight controllers over serial | github.com/betaflight |
| Espruino Web IDE | REPL and code upload to Espruino boards | espruino.com/ide |
| Microsoft MakeCode | Serial console for BBC micro:bit in browser | makecode.com |
| Octoprint (via WebSerial) | 3D printer control — send G-code, monitor temps | octoprint.org |
| Serial Terminal (Chrome Demo) | Reference implementation — full terminal emulator | googlechromelabs.github.io/serial-terminal |
馃摝 Open Source Tooling
Official W3C WICG spec repository for the Web Serial API. Issue tracker and living specification.
On Android, WebUSB + the Serial API polyfill provides USB-based serial port support as a fallback.
Full-featured browser serial terminal — ANSI colors, line ending options, hex view. Great reference app.
WebUSB-based polyfill for Web Serial API — provides the navigator.serial interface on top of WebUSB.
馃敀 Security Model
- User gesture required —
navigator.serial.requestPort()only callable from user interaction - Picker dialog — browser shows OS-level port list; site can filter by USB vendor/product ID
- HTTPS required — only secure contexts (or localhost for development)
- Permissions Policy — restrict serial access in iframes:
<iframe allow="serial"> - Revocable access — via
port.forget()(Chrome 103+) or chrome://settings/content/serialPorts - One port at a time — each
requestPort()grants access to one port only
Written by Alex R. | Coding with Alex | Tags: Web Serial, Browser APIs, Arduino, 3D Printers, Chrome, Serial Communication