APIs de la web, hoyLaboratorio · Alex Harto

Web Bluetooth

Dispositivos Bluetooth Low Energy desde una página: pulsómetros, sensores, juguetes, luces…

En tu navegador: comprobando…Revisado 1 oct 2026

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ónEscritorioMóvil
ChromeEdgeFirefoxSafariChrome AndroidFirefox AndroidSafari iOS
navigator.bluetooth561Chrome: 56 792Edge: 79 —Firefox: No—Safari: No56Chrome: 56 —Firefox: No—Safari: No
  1. 1macOS y ChromeOS desde 56; Windows 10 desde 70. En Linux hace falta activar las funciones experimentales.
  2. 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>

Novedades

  1. El WHATWG abre un área de hardware, de momento solo para Web Serial; Web Bluetooth queda a la espera.

Ten en cuenta

  1. requestDevice() debe ser lo primero que se espera dentro del clic, o se pierde el gesto del usuario.
  2. Declara en optionalServices cualquier servicio que vayas a usar y no esté en los filtros.
  3. Hay una lista de servicios y características bloqueados (GATT blocklist). En iframes, allow="bluetooth".

Más información

Fuentes