How Web Bluetooth Enables BLE Communication in Chromium
This article explains how the Web Bluetooth API in the Chromium web browser allows websites to directly communicate with nearby Bluetooth Low Energy (BLE) peripherals. It covers the strict security and user-permission protocols required to establish a connection, the role of the Generic Attribute Profile (GATT) in structuring data, the step-by-step process of reading and writing data using JavaScript, and how Chromium bridges the gap between web code and the operating system's native Bluetooth stack.
Security and User Gesture Requirements
To protect user privacy and security, Chromium enforces strict rules
before any Bluetooth communication can occur. First, the Web Bluetooth
API is only available in secure contexts, meaning the website must be
served over HTTPS (or localhost during development).
Second, a website cannot automatically scan for or connect to nearby BLE
devices upon loading. The communication process must be initiated by a
deliberate user gesture, such as a mouse click or a screen tap.
Device Discovery and the Permission Prompt
Once the user triggers an action, the website calls the
navigator.bluetooth.requestDevice() JavaScript method.
Developers pass filters into this method to specify what kind of devices
the website wants to communicate with, based on device names, service
UUIDs (Universally Unique Identifiers), or manufacturer data.
Chromium intercepts this API call and displays a native browser prompt to the user. This prompt scans for and lists nearby BLE peripherals that match the developer's filters. The user must manually select a device from this list and click "Pair" to grant the website permission to access that specific peripheral. This prevents malicious websites from silently tracking users via nearby Bluetooth beacons.
The GATT Architecture
The Web Bluetooth API relies entirely on the Generic Attribute Profile (GATT) to structure data exchange. Once a peripheral is connected, Chromium interacts with it as a GATT Server. GATT organizes data hierarchically into Services and Characteristics:
- Services: Logical groups of data that accomplish a specific function on the device (e.g., a "Heart Rate Service" or a "Battery Service").
- Characteristics: Specific data points contained within a service (e.g., the actual heart rate measurement or the current battery percentage).
Every service and characteristic is identified by a standardized 16-bit or custom 128-bit UUID. To prevent websites from accessing sensitive system hardware, Chromium maintains a blocklist of restricted UUIDs (such as Human Interface Devices like Bluetooth keyboards) that the Web Bluetooth API is forbidden from accessing.
Connecting and Transferring Data
After the user selects a device from the Chromium prompt, the API
returns a JavaScript Promise that resolves with a
BluetoothDevice object. The website then connects to the
device's GATT server using the device.gatt.connect()
method.
Once the connection is established, the website traverses the GATT hierarchy using asynchronous JavaScript Promises to interact with the hardware:
- Get the Service: The website requests the target
service using its UUID via
server.getPrimaryService(). - Get the Characteristic: From that service, the
website requests the desired characteristic via
service.getCharacteristic(). - Read Data: The website can read the
characteristic's current state by calling
characteristic.readValue(). This returns a JavaScriptDataViewobject containing raw byte data, which the website can parse into usable information. - Write Data: The website can send commands or data
to the peripheral by passing an
ArrayBufferorDataViewof bytes into thecharacteristic.writeValue()method. - Subscribe to Notifications: For continuous data
streams, such as a fitness tracker broadcasting real-time telemetry, the
website calls
characteristic.startNotifications(). It then listens for thecharacteristicvaluechangedevent to process incoming data packets automatically as the peripheral sends them.
Chromium's OS Abstraction Layer
Behind the scenes, Chromium acts as a translator between the web page's sandboxed JavaScript environment and the host operating system's native Bluetooth stack. Because Windows, macOS, Linux, Android, and ChromeOS all manage Bluetooth hardware differently, Chromium utilizes an internal C++ abstraction layer.
When a website executes a Web Bluetooth API command, the Chromium renderer process sends an Inter-Process Communication (IPC) message to the main browser process. The browser process validates the security permissions, translates the JavaScript request into the appropriate OS-level Bluetooth API call (such as CoreBluetooth on macOS, WinRT on Windows, or BlueZ on Linux), and routes the hardware's response back to the web page as a standard JavaScript Promise.