Web Serial
Puerto serie desde el navegador: Arduino, ESP32, impresoras 3D, instrumentos de laboratorio.
requestPort() pide al usuario un puerto (USB o Bluetooth), open() fija la velocidad, y después se lee y escribe con streams. Sirve para cargar firmware, consolas de depuración o configurar aparatos sin instalar nada.
Chrome y Edge de escritorio desde la 89. Firefox lo activó en la 151 (mayo de 2026) con un complemento de permiso que el propio navegador genera para cada sitio. Chrome para Android, desde la 148; por USB, solo en los dispositivos con la nueva API serie de Android. Safari no.
Para qué sirve
- Cargar firmware en placas desde la web
- Consolas serie y depuración de microcontroladores
- Controlar impresoras 3D, CNC e instrumentos
Demo
Un terminal serie completo: conecta un Arduino, un ESP32, una micro:bit o cualquier adaptador USB‑serie, elige la velocidad y escribe. En el ejemplo mínimo tienes un sketch de Arduino que devuelve lo que recibe.
Compatibilidad
Disponibilidad limitada| Función | Escritorio | Móvil | |||||
|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Safari | Chrome Android | Firefox Android | Safari iOS | |
| navigator.serial | 89Chrome: 89 | 89Edge: 89 | 1511Firefox: 151 | —Safari: No | 1482Chrome: 148 | —Firefox: No | —Safari: No |
- 1Escritorio. La primera vez pide instalar un complemento de permiso generado para el sitio.
- 2Bluetooth (RFCOMM) desde 138; USB desde 148 solo en los dispositivos con la nueva API serie de Android.
Compatibilidad generada en cada publicación desde MDN browser-compat-data 8.1.3 (24 sep 2026) · web-features 3.40.0 · revisión manual: 1 oct 2026
Código mínimo
<!doctype html>
<meta charset="utf-8">
<title>Web Serial · ejemplo mínimo</title>
<!-- Terminal serie: abre un puerto (Arduino, micro:bit, ESP32…), muestra lo que llega y envía líneas.
Chrome y Edge 89+; Firefox 151+ (pide instalar un complemento de permiso); Chrome Android 148+. HTTPS o localhost. -->
<button id="connect">Abrir puerto</button>
<input id="line" placeholder="Texto a enviar" disabled> <button id="send" disabled>Enviar</button>
<pre id="out"></pre>
<script>
const $ = (s) => document.querySelector(s);
let writer;
$('#connect').onclick = async () => {
if (!('serial' in navigator)) return ($('#out').textContent = 'Web Serial no está disponible en este navegador.');
const port = await navigator.serial.requestPort();
await port.open({ baudRate: 115200 });
// Escribir: texto → bytes
const encoder = new TextEncoderStream();
encoder.readable.pipeTo(port.writable);
writer = encoder.writable.getWriter();
$('#line').disabled = $('#send').disabled = false;
// Leer: bytes → texto, hasta que se cierre el puerto
const reader = port.readable.pipeThrough(new TextDecoderStream()).getReader();
while (true) {
const { value, done } = await reader.read();
if (done) break;
$('#out').textContent += value;
}
};
$('#send').onclick = async () => {
await writer.write($('#line').value + '\n');
$('#line').value = '';
};
</script><!doctype html>
<meta charset="utf-8">
<title>Web Serial · ejemplo mínimo</title>
<!-- Terminal serie: abre un puerto (Arduino, micro:bit, ESP32…), muestra lo que llega y envía líneas.
Chrome y Edge 89+; Firefox 151+ (pide instalar un complemento de permiso); Chrome Android 148+. HTTPS o localhost. -->
<button id="connect">Abrir puerto</button>
<input id="line" placeholder="Texto a enviar" disabled> <button id="send" disabled>Enviar</button>
<pre id="out"></pre>
<script>
const $ = (s) => document.querySelector(s);
let writer;
$('#connect').onclick = async () => {
if (!('serial' in navigator)) return ($('#out').textContent = 'Web Serial no está disponible en este navegador.');
const port = await navigator.serial.requestPort();
await port.open({ baudRate: 115200 });
// Escribir: texto → bytes
const encoder = new TextEncoderStream();
encoder.readable.pipeTo(port.writable);
writer = encoder.writable.getWriter();
$('#line').disabled = $('#send').disabled = false;
// Leer: bytes → texto, hasta que se cierre el puerto
const reader = port.readable.pipeThrough(new TextDecoderStream()).getReader();
while (true) {
const { value, done } = await reader.read();
if (done) break;
$('#out').textContent += value;
}
};
$('#send').onclick = async () => {
await writer.write($('#line').value + '\n');
$('#line').value = '';
};
</script>Novedades
Ten en cuenta
- requestPort() necesita un gesto del usuario; getPorts() devuelve los ya autorizados.
- Antes de cerrar, cancela el lector y libera el escritor; si no, port.close() falla.
- En Firefox para empresas viene desactivado por defecto (DefaultSerialGuardSetting).
Más información
Fuentes
- MDN · Firefox 151 for developers19 may 2026
- Mozilla Hacks · Web Serial support in Firefox19 may 2026
- Chrome 148 release notes5 may 2026
- Blink · PSA Web Serial on Android10 feb 2026
- WHATWG · Web Serial2 jun 2026