Capabilities · API
Web Serial API: navigator.serial device access
Published Updated
In one line: the Web Serial API lets a page ask the user to pick a serial port with
navigator.serial.requestPort(), then read and write bytes through the returned
SerialPort’s readable/writable streams. MDN marks the Serial interface
not Baseline — “because it does not work in some of the most widely-used browsers” —
and exposes it only in secure contexts.
Requesting and reusing a port
Section titled “Requesting and reusing a port”const port = await navigator.serial.requestPort();await port.open({ baudRate: 9600 });Per MDN, requestPort() “must be called via transient activation” — trigger it from a
click handler or similar user gesture, not automatically on load. navigator.serial.getPorts()
returns an array of the currently connected ports the origin already has permission to
access, without prompting again:
const ports = await navigator.serial.getPorts();Access can also be blocked by the serial Permissions Policy; per MDN, a blocked page
never shows the device picker and the user is not prompted.
Where it is supported
Section titled “Where it is supported”Per the compatibility data above, desktop Chrome and Edge have supported the API since version 89, and desktop Firefox added support later, at version 151. Safari does not support it on macOS or iOS. On Android, Chrome has full support from version 148 per MDN browser-compat-data; in Chrome 138-146 serial ports there were “only available if they are provided by Bluetooth RFCOMM serial port emulation”. Firefox for Android does not support it.
Reading and writing
Section titled “Reading and writing”const reader = port.readable.getReader();try { while (true) { const { value, done } = await reader.read(); if (done) break; console.log(value); }} finally { reader.releaseLock();}navigator.serial also fires connect and disconnect events — bubbling from
SerialPort — so a page can react when an already-authorized device is attached or
removed instead of polling getPorts().
How to detect it at runtime
Section titled “How to detect it at runtime”async function connectSerial() { if (!('serial' in navigator)) { // Web Serial unsupported here — fall back to WebUSB, or point the user at a // native companion app instead of calling navigator.serial. return null; } const port = await navigator.serial.requestPort(); await port.open({ baudRate: 9600 }); return port;}What goes wrong
Section titled “What goes wrong”-
requestPort()requires transient activation — call it from a click handler, not automatically on page load, or the returned promise rejects. - Feature-detect
'serial' in navigatorbefore calling anything on it; MDN marks Web Serial not Baseline, so absence is expected in some browsers. - Serve the page over HTTPS — the
Serialinterface is exposed only in secure contexts. - On Android, check the Chrome version before assuming USB-connected devices are reachable — per MDN browser-compat-data, Chrome 138-146 covered Bluetooth RFCOMM emulation only; 148+ is full.
- Call
getPorts()on load, before falling back torequestPort(), to reuse a previously granted port without a new prompt. - A page can also be blocked from prompting at all by the
serialPermissions Policy — check for that failure mode separately from a user simply declining.
Where to go next
Section titled “Where to go next”- WebUSB API — the related reference for USB devices not claimed by an OS driver.
- WebHID API — the related reference for USB HID class input devices.
Specifications
| Specification | Status |
|---|---|
| Web Serial API | WICG draft |
- Legend
- Yes
- Partial
- Flag
- No
- Unknown
| Browser / Platform | Support | Versions | Confidence | Source | Notes |
|---|---|---|---|---|---|
| Chrome (Desktop) | Yes | 89 | high | source | — |
| Chrome (Android) | Yes | 148 | high | source | — |
| Edge (Desktop) | Yes | 89 | high | source | 1 |
| Firefox (Desktop) | Yes | 151 | high | source | — |
| Firefox (Android) | No | — | high | source | 2 |
| Safari (macOS) | No | — | high | source | 3 |
| Safari (iOS) | No | — | high | source | 45 |
| Samsung Internet | Partial | 30.0 | high | source | 67 |
| WebView (Android) | No | — | high | source | 8 |
- Derived by browser-compat-data mirroring from Chrome.
- No Firefox for Android support is recorded in browser-compat-data.
- No Safari support is recorded in browser-compat-data.
- No Safari on iOS support is recorded in browser-compat-data.
- Derived by browser-compat-data mirroring from Safari.
- Serial ports are only available if they're provided by Bluetooth RFCOMM serial port emulation.
- Derived by browser-compat-data mirroring from Chrome Android.
- Implementation tracking: https://crbug.com/40740509.