Web Bluetooth
Dispositivos Bluetooth Low Energy desde una página: pulsómetros, sensores, juguetes, luces…
requestDevice() abre un selector del navegador; tras elegir, la página se conecta al servidor GATT del dispositivo, lee y escribe características y recibe notificaciones. Los servicios estándar (batería, frecuencia cardiaca) tienen nombre; los propios, un UUID.
Chrome y Edge en Windows, macOS, ChromeOS y Android; en Linux hay que activar las funciones experimentales. Firefox y Safari no la implementan y se han posicionado en contra. getDevices() y watchAdvertisements() siguen sin activarse por defecto.
Para qué sirve
- Configurar y actualizar dispositivos IoT
- Deporte y salud: pulsómetros, básculas, rodillos
- Educación y robótica (micro:bit, kits)
Demo
Dos servicios estándar de Bluetooth LE: el nivel de batería (relojes, auriculares, mandos, ratones…) y la frecuencia cardiaca de un pulsómetro o una banda de pecho. El navegador te deja elegir el dispositivo; la página no ve nada más.
—
Compatibilidad
Disponibilidad limitada| Función | Escritorio | Móvil | |||||
|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Safari | Chrome Android | Firefox Android | Safari iOS | |
| navigator.bluetooth | 561Chrome: 56 | 792Edge: 79 | —Firefox: No | —Safari: No | 56Chrome: 56 | —Firefox: No | —Safari: No |
- 1macOS y ChromeOS desde 56; Windows 10 desde 70. En Linux hace falta activar las funciones experimentales.
- 2En Linux, tras una flag.
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 Bluetooth · ejemplo mínimo</title>
<!-- Lee el nivel de batería de un dispositivo Bluetooth LE que publique el servicio estándar «battery_service».
Chrome y Edge (escritorio y Android). HTTPS o localhost. -->
<button id="connect">Leer batería</button>
<pre id="out"></pre>
<script>
const out = document.querySelector('#out');
document.querySelector('#connect').onclick = async () => {
if (!('bluetooth' in navigator)) return (out.textContent = 'Web Bluetooth no está disponible en este navegador.');
try {
// requestDevice debe ser lo primero que se espera dentro del clic
const device = await navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] });
const server = await device.gatt.connect();
const service = await server.getPrimaryService('battery_service');
const level = await service.getCharacteristic('battery_level');
const show = (value) => (out.textContent = `${device.name ?? 'Dispositivo'}: ${value.getUint8(0)} %`);
show(await level.readValue());
// Si el dispositivo lo permite, recibe los cambios
if (level.properties.notify) {
level.addEventListener('characteristicvaluechanged', (e) => show(e.target.value));
await level.startNotifications();
}
device.addEventListener('gattserverdisconnected', () => (out.textContent += '\nDesconectado'));
} catch (err) {
out.textContent = err.name === 'NotFoundError' ? 'No se eligió ningún dispositivo.' : err.message;
}
};
</script><!doctype html>
<meta charset="utf-8">
<title>Web Bluetooth · ejemplo mínimo</title>
<!-- Lee el nivel de batería de un dispositivo Bluetooth LE que publique el servicio estándar «battery_service».
Chrome y Edge (escritorio y Android). HTTPS o localhost. -->
<button id="connect">Leer batería</button>
<pre id="out"></pre>
<script>
const out = document.querySelector('#out');
document.querySelector('#connect').onclick = async () => {
if (!('bluetooth' in navigator)) return (out.textContent = 'Web Bluetooth no está disponible en este navegador.');
try {
// requestDevice debe ser lo primero que se espera dentro del clic
const device = await navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] });
const server = await device.gatt.connect();
const service = await server.getPrimaryService('battery_service');
const level = await service.getCharacteristic('battery_level');
const show = (value) => (out.textContent = `${device.name ?? 'Dispositivo'}: ${value.getUint8(0)} %`);
show(await level.readValue());
// Si el dispositivo lo permite, recibe los cambios
if (level.properties.notify) {
level.addEventListener('characteristicvaluechanged', (e) => show(e.target.value));
await level.startNotifications();
}
device.addEventListener('gattserverdisconnected', () => (out.textContent += '\nDesconectado'));
} catch (err) {
out.textContent = err.name === 'NotFoundError' ? 'No se eligió ningún dispositivo.' : err.message;
}
};
</script>Novedades
Ten en cuenta
- requestDevice() debe ser lo primero que se espera dentro del clic, o se pierde el gesto del usuario.
- Declara en optionalServices cualquier servicio que vayas a usar y no esté en los filtros.
- Hay una lista de servicios y características bloqueados (GATT blocklist). En iframes, allow="bluetooth".
Más información
Fuentes
- MDN browser-compat-data 8.1.324 sep 2026
- Blink · watchAdvertisements no se activará10 oct 2023
- Mozilla standards-positions #95consultado el 1 oct 2026
- WebKit standards-positions #570consultado el 1 oct 2026