
Progressive Web App Road Show 2016
Stopping in New York, Chicago, Austin, Toronto, Mountain View and Seattle. Learn more and sign up now.

Progressive Web App Road Show 2016
Stopping in New York, Chicago, Austin, Toronto, Mountain View and Seattle. Learn more and sign up now.
What if I told you websites could communicate with nearby Bluetooth devices in a secure and privacy-preserving way? This way, heart rate monitors, singing lightbulbs, turtles and flying grumpy cats could interact directly with a website.
Until now, the ability to interact with bluetooth devices has been possible only for native apps. The Web Bluetooth API aims to change this and brings it to web browsers as well. Alongside efforts like Physical Web, people can walk up to and interact with devices straight from the web. Check out this drone controlled from a web app video to get a sense of how that would work.
This article assumes you have some basic knowledge of how Bluetooth Low Energy (BLE) and the Generic Attribute Profile (GATT) work.
Even though the Web Bluetooth API specification is not finalized yet, the Chrome Team is actively looking for enthusiastic developers (I mean you) to try out this work-in-progress API and give feedback on the spec and feedback on the implementation.
Web Bluetooth API is currently available to be enabled experimentally on your origin in Origin Trials, or locally on your machine using an experimental flag. The implementation is partially complete and currently available on Chrome OS, Chrome for Android M, Linux, and Mac.
Go to chrome://flags/#enable-web-bluetooth, enable the highlighted flag, restart Chrome and you should be able to scan for and connect to nearby Bluetooth devices, read/write Bluetooth characteristics, receive GATT Notifications and know when a Bluetooth device gets disconnected.

In order to get as much feedback as possible from developers using the Web Bluetooth API in the field, we’re also adding this feature in Chrome 53 as an origin trial for Chrome OS, Android M, and Mac. Origin Trials allow you to temporarily enable the feature for all of users of your website. During the origin trial, the API may still change in backward-incompatible ways before we freeze it into the web platform. To use this experimental API in Chrome with no flag, you’ll need to request a token for your origin and insert it in your application.
The trial will end in January 2017. By that point, we expect to have figured out any changes necessary to stabilize the feature and move it out from Origin Trials.
Because this experimental API is a powerful new feature added to the Web, Google Chrome aims to make it available only to secure contexts. This means you’ll need to build with TLS in mind.
We care deeply about security, so you will notice that new Web capabilities require HTTPS. The Web Bluetooth API is no different, and is yet another good reason to get HTTPS up and running on your site.
During development you’ll be able to interact with Web Bluetooth through http://localhost by using tools like the Chrome Dev Editor or the handy python -m SimpleHTTPServer, but to deploy it on a site you’ll need to have HTTPS set up on your server. I personally enjoy GitHub Pages for demo purposes.
To add HTTPS to your server you’ll need to get a TLS certificate and set it up. Be sure to check out the Security with HTTPS article for best practices there. For info, you can now get free TLS certificates with the new Certificate Authority Let’s Encrypt.
As a security feature, discovering nearby Bluetooth devices with navigator.bluetooth.requestDevice must be called via a user gesture like a touch or mouse click.
The Web Bluetooth API relies heavily on JavaScript Promises. If you’re not familiar with them, check out this great Promises tutorial. One more thing, () => {} are simply ECMAScript 2015 Arrow functions – they have a shorter syntax compared to function expressions and lexically bind the this value.
This version of the Web Bluetooth API specification allows websites, running in the Central role, to connect to remote GATT Servers over a BLE connection. It supports communication among devices that implement Bluetooth 4.0 or later.
When a website requests access to nearby devices using navigator.bluetooth.requestDevice, Google Chrome will prompt user with a device chooser where they can pick one device or simply cancel the request.

The navigator.bluetooth.requestDevice function takes a mandatory Object that defines filters. These filters are used to return only devices that match some advertised Bluetooth GATT services and/or the device name.
For instance, scanning for Bluetooth devices advertising the Bluetooth GATT Battery Service is this simple:
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* ... */ })
.catch(error => { console.log(error); });If your Bluetooth GATT Service is not on the list of the standardized Bluetooth GATT services though, you may provide either the full Bluetooth UUID or a short 16- or 32-bit form.
navigator.bluetooth.requestDevice({
filters: [{
services: [0x1234, 0x12345678, '99999999-0000-1000-8000-00805f9b34fb']
}]
})
.then(device => { /* ... */ })
.catch(error => { console.log(error); });You can also scan for Bluetooth devices based on the device name being advertised with the name filters key, or even a prefix of this name with the namePrefix filters key. Note that in this case, you will also need to define the optionalServices key to be able to access some services. If you don’t, you’ll get an error later when trying to access them.
navigator.bluetooth.requestDevice({
filters: [{
name: 'Francois robot'
}],
optionalServices: ['battery_service']
})
.then(device => { /* ... */ })
.catch(error => { console.log(error); });So what do you do now that you have a BluetoothDevice returned from navigator.bluetooth.requestDevice’s Promise? Let’s connect to the Bluetooth remote GATT Server which holds the service and characteristic definitions.
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => {
// Human-readable name of the device.
console.log(device.name);
// Filtered UUIDs of GATT services the website origin has access to.
console.log(device.uuids);
// Attempts to connect to remote GATT Server.
return device.gatt.connect();
})
.then(server => { /* ... */ })
.catch(error => { console.log(error); });Here we are connected to the GATT Server of the remote Bluetooth device. Now we want to get a Primary GATT Service and read a characteristic that belongs to this service. Let’s try, for instance, to read the current charge level of the device’s battery.
In the example below, battery_level is the standardized Battery Level Characteristic.
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => device.gatt.connect())
.then(server => {
// Getting Battery Service...
return server.getPrimaryService('battery_service');
})
.then(service => {
// Getting Battery Level Characteristic...
return service.getCharacteristic('battery_level');
})
.then(characteristic => {
// Reading Battery Level...
return characteristic.readValue();
})
.then(value => {
console.log('Battery percentage is ' + value.getUint8(0));
})
.catch(error => { console.log(error); });If you use a custom Bluetooth GATT characteristic, you may provide either the full Bluetooth UUID or a short 16- or 32-bit form to service.getCharacteristic.
Note that you can also add a characteristicvaluechanged event listener on a characteristic to handle reading its value. Check out Read Characteristic Value Changed Sample to see how to optionally handle upcoming GATT notifications as well.
...
.then(characteristic => {
// Set up event listener for when characteristic value changes.
characteristic.addEventListener('characteristicvaluechanged',
handleBatteryLevelChanged);
// Reading Battery Level...
return characteristic.readValue();
})
.catch(error => { console.log(error); });
function handleBatteryLevelChanged(event) {
let batteryLevel = event.target.value.getUint8(0);
console.log('Battery percentage is ' + batteryLevel + '%');
}Writing to a Bluetooth GATT Characteristic is as easy as reading it. This time, let’s use the Heart Rate Control Point to reset the value of the Energy Expended field to 0 on a heart rate monitor device.
I promise there is no magic here. It’s all explained in the Heart Rate Control Point Characteristic page.
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_control_point'))
.then(characteristic => {
// Writing 1 is the signal to reset energy expended.
var resetEnergyExpended = new Uint8Array([1]);
return characteristic.writeValue(resetEnergyExpended);
})
.then(_ => {
console.log('Energy expended has been reset.');
})
.catch(error => { console.log(error); });Now, let’s see how to be notified when the Heart Rate Measurement characteristic changes on the device:
navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_measurement'))
.then(characteristic => {
return characteristic.startNotifications()
.then(_ => {
characteristic.addEventListener('characteristicvaluechanged',
handleCharacteristicValueChanged);
});
})
.then(_ => {
console.log('Notifications have been started.');
})
.catch(error => { console.log(error); });
function handleCharacteristicValueChanged(event) {
var value = event.target.value;
console.log('Received ' + value);
// TODO: Parse Heart Rate Measurement value.
// See https://github.com/WebBluetoothCG/demos/blob/gh-pages/heart-rate-sensor/heartRateSensor.js
}The Notifications Sample will show you to how to stop notifications with stopNotifications() and properly remove the added characteristicvaluechanged event listener.
To provide a better user experience, you may want to show a warning message if the BluetoothDevice gets disconnected to invite the user to reconnect.
navigator.bluetooth.requestDevice({ filters: [{ name: 'Francois robot' }] })
.then(device => {
// Set up event listener for when device gets disconnected.
device.addEventListener('gattserverdisconnected', onDisconnected);
// Attempts to connect to remote GATT Server.
return device.gatt.connect();
})
.then(server => { /* ... */ })
.catch(error => { console.log(error); });
function onDisconnected(event) {
let device = event.target;
console.log('Device ' + device.name + ' is disconnected.');
}You can also call device.gatt.disconnect() to disconnect your web app from the Bluetooth device. This will trigger existing gattserverdisconnected event listeners. Note that it will NOT stop bluetooth device communication if another app is already communicating with the Bluetooth device. Check out the Device Disconnect Sample and the Automatic Reconnect Sample to dive deeper.
All Web Bluetooth samples below have been tested with the Web Bluetooth flag enabled. To enjoy these samples to their fullest, I recommend you install the BLE Peripheral Simulator Android App which simulates a BLE Peripheral with a Battery Service or a Heart Rate Service.
Check out our curated Web Bluetooth Demos and official Web Bluetooth Codelabs as well.
A Bluetooth Console is available in Chrome OS developer shell. Press [ Ctrl ] [ Alt ] [ T ] to open a browser tab terminal and use the bt_console command to start poking around your bluetooth settings. The help command will give you a list of all available commands.

I would recommend you check out the official Bluetooth debug page as debugging Bluetooth can be hard sometimes.
Check the browser and platform implementation status first to know which parts of the Web Bluetooth API are currently being implemented.
Though it’s still incomplete, here’s a sneak peek of what to expect in the coming months:
navigator.bluetooth.requestLEScan().serviceadded event will track newly discovered Bluetooth GATT Services while serviceremoved event will track removed ones. A new servicechanged event will fire when any characteristic and/or descriptor gets added or removed from a Bluetooth GATT Service.At the time of writing, Chrome OS, Android M, Linux, and Mac are the most advanced platforms. Windows 8.1+ and iOS will be supported as much as feasible by the platforms.
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License. For details, see our Terms of Service.