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