Skip to content

Web Serial API

Published Updated

Web Serial API — The Web Serial API lets a web app request access to a serial port via navigator.serial.requestPort() and read from or write to it using the port’s readable and writable streams.

  • Legend
  • Yes
  • Partial
  • Flag
  • No
  • Unknown
Browser / PlatformSupportVersionsConfidenceSourceNotes
Chrome (Desktop)Yes89highsource—
Chrome (Android)Yes148highsource—
Edge (Desktop)Yes89highsource1
Firefox (Desktop)Yes151highsource—
Firefox (Android)No—highsource2
Safari (macOS)No—highsource3
Safari (iOS)No—highsource45
Samsung InternetPartial30.0highsource67
WebView (Android)No—highsource8
  1. Derived by browser-compat-data mirroring from Chrome.
  2. No Firefox for Android support is recorded in browser-compat-data.
  3. No Safari support is recorded in browser-compat-data.
  4. No Safari on iOS support is recorded in browser-compat-data.
  5. Derived by browser-compat-data mirroring from Safari.
  6. Serial ports are only available if they're provided by Bluetooth RFCOMM serial port emulation.
  7. Derived by browser-compat-data mirroring from Chrome Android.
  8. Implementation tracking: https://crbug.com/40740509.

Source data: /compatibility/web-serial.json · Global usage: 72 % (StatCounter 2026-05)

Source: spec · MDN · Last verified 2026-10-03 · Confidence: high (computed from sources)

Requesting a port must happen inside a user gesture, and filters narrows the picker to ports matching a USB vendor ID. Once the user selects a port, open it with a baud rate before reading or writing:

async function connectSerialPort() {
const port = await navigator.serial.requestPort({
filters: [{ usbVendorId: 0x2341 }],
});
await port.open({ baudRate: 9600 });
return port;
}

Check for navigator.serial before offering the feature, and give the reader a fallback path when it is absent:

if ('serial' in navigator) {
connectButton.hidden = false;
} else {
connectButton.hidden = true;
fallbackNotice.textContent = 'This browser cannot access serial ports from the page.';
}
  • Requires a secure context — plain HTTP origins other than potentially trustworthy ones like localhost cannot use it.
  • requestPort() needs transient user activation (a click or keydown handler); without it, the returned promise rejects with a SecurityError DOMException.
  • port.readable and port.writable are null until you call port.open({ baudRate }); get the reader/writer from those streams only after open() resolves.
  • The picker only lists ports matching the filters you pass, so a request with no matching device leaves the user with nothing to select, which rejects the returned promise.
  • Support is not uniform across browsers or platforms: per MDN browser-compat-data, Chrome for Android has full support from version 148; in Chrome 138-146 it only exposed serial ports provided through Bluetooth RFCOMM serial port emulation, not a wired connection — check the support table above before relying on the feature for a given target.

See WebUSB API for raw access to USB devices not claimed by an OS driver — a related but distinct low-level device access API.

See also WebHID API for input/output device access via HID reports.

← Back to the Compatibility explorer.