Web Bluetooth API: Connect Hardware Using JavaScript

The Web Bluetooth API allows web applications to communicate directly with nearby Bluetooth Low Energy (BLE) peripheral devices securely and natively using JavaScript. This guide explains the core concepts behind the Web Bluetooth API, its security architecture, and the step-by-step implementation process required to discover, connect, read, and write data to peripheral hardware.

What is the Web Bluetooth API?

The Web Bluetooth API provides web developers with the ability to connect web pages directly to Bluetooth Low Energy (BLE) devices using the Generic Attribute Profile (GATT). Traditionally, communicating with external hardware required dedicated native applications built in languages like Swift, Kotlin, or C++. With Web Bluetooth, standard web browsers can interface directly with physical devices like heart rate monitors, smart light bulbs, industrial sensors, and IoT microcontrollers (e.g., Arduino, ESP32).

Core Concepts: Understanding BLE and GATT

Web Bluetooth operates strictly over Bluetooth Low Energy using the GATT hierarchy:

Security and Operational Prerequisites

Browsers enforce strict security mechanisms to protect users from unauthorized hardware access:

  1. Secure Context (HTTPS): Web Bluetooth is only accessible on origins served via HTTPS or localhost.
  2. Explicit User Interaction: Hardware discovery cannot trigger automatically on page load. It must be initiated by an explicit user gesture, such as clicking a button or tapping a screen.
  3. User Consent: The browser displays a native device chooser dialog where the user must explicitly select and pair the hardware.

How JavaScript Connects to Peripheral Hardware

Connecting to a BLE device involves a sequential, Promise-based workflow:

1. Requesting the Device

Use navigator.bluetooth.requestDevice() with predefined filters to scan for devices broadcasting specific services or matching name patterns.

const device = await navigator.bluetooth.requestDevice({
  filters: [{ services: ['heart_rate'] }],
  // Or: acceptAllDevices: true, optionalServices: ['battery_service']
});

2. Connecting to the GATT Server

Once the user selects a device, establish a connection to its GATT server:

const server = await device.gatt.connect();

3. Accessing the Primary Service

Retrieve the specific service from the connected GATT server using standard names or custom UUIDs:

const service = await server.getPrimaryService('heart_rate');

4. Retrieving Characteristics

Obtain a reference to the characteristic you want to read, write, or listen to:

const characteristic = await service.getCharacteristic('heart_rate_measurement');

5. Performing Data Operations

6. Handling Disconnections

Always monitor hardware disconnections to update your application state gracefully:

device.addEventListener('gattserverdisconnected', () => {
  console.log('Device disconnected.');
});

Browser Compatibility

Web Bluetooth is supported natively in Chromium-based browsers, including Google Chrome, Microsoft Edge, and Opera across Android, ChromeOS, macOS, Linux, and Windows. Apple Safari and Mozilla Firefox do not currently support the Web Bluetooth API due to privacy and platform architecture policies.