This document describes an API to discover and communicate with devices over the Bluetooth 4 wireless standard using the Generic Attribute Profile (GATT).

Changes to this document may be tracked at https://github.com/WebBluetoothCG/web-bluetooth/commits/gh-pages.

Introduction

Bluetooth is a standard for short-range wireless communication between devices. Bluetooth "Classic" (BR/EDR) defines a set of binary protocols and supports speeds up to about 24Mbps. Bluetooth 4.0 introduced a new "Low Energy" mode known as "Bluetooth Smart", BLE, or just LE which is limited to about 1Mbps but allows devices to leave their transmitters off most of the time. BLE provides most of its functionality through key/value pairs provided by the Generic Attribute Profile (GATT).

BLE defines multiple roles that devices can play. The Broadcaster and Observer roles are for transmitter- and receiver-only applications, respectively. Devices acting in the Peripheral role can receive connections, and devices acting in the Central role can connect to Peripheral devices.

A device acting in either the Peripheral or Central role can host a GATT Server, which exposes a hierarchy of Services, Characteristics, and Descriptors. See for more details about this hierarchy. Despite being designed to support BLE transport, the GATT protocol can also run over BR/EDR transport.

The first version of this specification allows web pages, running on a UA in the Central role, to connect to GATT Servers over either a BR/EDR or LE connection. While this specification cites the [[BLUETOOTH42]] specification, it intends to also support communication among devices that only implement Bluetooth 4.0 or 4.1.

Examples

Security and privacy considerations

Device access is powerful

When a website requests access to devices using requestDevice, it gets the ability to access all GATT services mentioned in the call. The UA MUST inform the user what capabilities these services give the website before asking which devices to entrust to it. If any services in the list aren't known to the UA, the UA MUST assume they give the site complete control over the device and inform the user of this risk. The UA MUST also allow the user to inspect what sites have access to what devices and revoke these pairings.

The UA MUST NOT allow the user to pair entire classes of devices with a website. It is possible to construct a class of devices for which each individual device sends the same Bluetooth-level identifying information. UAs are not required to attempt to detect this sort of forgery and MAY let a user pair this pseudo-device with a website.

To help ensure that only the entity the user approved for access actually has access, this specification requires that only secure contexts can access Bluetooth devices (requestDevice).

Attacks on devices

Communication from websites can break the security model of some devices, which assume they only receive messages from the trusted operating system of a remote device. Human Interface Devices are a prominent example, where allowing a website to communicate would allow that site to log keystrokes. This specification includes a blacklist of such vulnerable services, characteristics, and descriptors to prevent websites from taking advantage of them.

We expect that many devices are vulnerable to unexpected data delivered to their radio. In the past, these devices had to be exploited one-by-one, but this API makes it plausible to conduct large-scale attacks. This specification takes several approaches to make such attacks more difficult:

UAs can also take further steps to protect their users:

Bluetooth device identifiers

Each Bluetooth BR/EDR device has a unique 48-bit MAC address known as the BD_ADDR. Each Bluetooth LE device has at least one of a Public Device Address and a Static Device Address. The Public Device Address is a MAC address. The Static Device Address may be regenerated on each restart. A BR/EDR/LE device will use the same value for the BD_ADDR and the Public Device Address (specified in the Read BD_ADDR Command).

An LE device may also have a unique, 128-bit Identity Resolving Key, which is sent to trusted devices during the bonding process. To avoid leaking a persistent identifier, an LE device may scan and advertise using a random Resolvable or Non-Resolvable Private Address instead of its Static or Public Address. These are regenerated periodically (approximately every 15 minutes), but a bonded device can check whether one of its stored IRKs matches any given Resolvable Private Address using the Resolvable Private Address Resolution Procedure.

Each Bluetooth device also has a human-readable Bluetooth Device Name. These aren't guaranteed to be unique, but may well be, depending on the device type.

Identifiers for remote Bluetooth devices

If a website can retrieve any of the persistent device IDs, these can be used, in combination with a large effort to catalog ambient devices, to discover a user's location. A device ID can also be used to identify that a user who pairs two different websites with the same Bluetooth device is a single user. On the other hand, many GATT services are available that could be used to fingerprint a device, and a device can easily expose a custom GATT service to make this easier.

This specification generates a new device ID for each origin for a given device, which makes it difficult for websites to abuse the device address like this. Device makers can still design their devices to help track users, but it takes work.

The UA's Bluetooth address

In BR/EDR mode, or in LE mode during active scanning without the Privacy Feature, the UA broadcasts its persistent ID to any nearby Bluetooth radio. This makes it easy to scatter hostile devices in an area and track the UA. As of 2014-08, few or no platforms document that they implement the Privacy Feature, so despite this spec recommending it, few UAs are likely to use it. This spec does require a user gesture for a website to trigger a scan, which reduces the frequency of scans some, but it would still be better for more platforms to expose the Privacy Feature.

Device Discovery

        dictionary BluetoothScanFilter {
          sequence<BluetoothServiceUUID> services;
        };

        dictionary RequestDeviceOptions {
          required sequence<BluetoothScanFilter> filters;
          sequence<BluetoothServiceUUID> optionalServices = [];
        };

        interface Bluetooth {
          Promise<BluetoothDevice> requestDevice(RequestDeviceOptions options);
        };
        Bluetooth implements EventTarget;
        Bluetooth implements CharacteristicEventHandlers;
        Bluetooth implements ServiceEventHandlers;
      

requestDevice(options) asks the user to grant this origin access to a device that matches a filter in options.filters. The user will be shown devices that support all the GATT service UUIDs in the services list of any BluetoothScanFilter in filters.

After the user selects a device to pair with this origin, the origin is allowed to access to any service whose UUID was listed in the services list in any element of options.filters or in options.optionalServices.

A device matches a filter filter if the UA has received advertising data, an extended inquiry response, or a service discovery response indicating that the device supports each of the Service UUIDs included in filter.services as a primary (vs included) service.

The list of Service UUIDs that a device advertises might not include all the UUIDs the device supports. The advertising data does specify whether this list is complete. If a website filters for a UUID that a nearby device supports but doesn't advertise, that device might not be included in the list of devices presented to the user. The UA would need to connect to the device to discover the full list of supported services, which can impair radio performance and cause delays, so this spec doesn't require it.

The requestDevice(options) method, when invoked, MUST return a new promise promise and run the following steps in parallel:

  1. If the incumbent settings object is not a secure context, reject promise with a SecurityError and abort these steps.
  2. If the algorithm is not allowed to show a popup, reject promise with a SecurityError and abort these steps.
  3. In order to convert the arguments from service names and aliases to just UUIDs, do the following substeps:
    1. Let uuidFilters be a new Array and requiredServiceUUIDs be a new Set.
    2. For each filter in options.filters, do the following steps:
      1. If filter.services.length === 0, reject promise with a TypeError and abort these steps.
      2. Let services be Array.prototype.map.call(filter.services, BluetoothUUID.getService).
      3. If any of the BluetoothUUID.getService calls threw an exception, reject promise with that exception and abort these steps.
      4. If any service in services is blacklisted, reject promise with a SecurityError and abort these steps.
      5. Append {services: services} to uuidFilters.
      6. Add the elements of services to requiredServiceUUIDs.
    3. Let optionalServiceUUIDs be Array.prototype.map.call(options.optionalServices, BluetoothUUID.getService).
    4. If any of the BluetoothUUID.getService calls threw an exception, reject promise with that exception and abort these steps.
    5. Remove from optionalServiceUUIDs any UUIDs that are blacklisted.
  4. Scan for devices with requiredServiceUUIDs as the set of Service UUIDs, and let scanResult be the result.
  5. Remove devices from scanResult if they do not match a filter in uuidFilters.
  6. Even if scanResult is empty, display a prompt to the user requesting that the user select a device from it. The UA SHOULD show the user the human-readable name of each device. If this name is not available because the UA's Bluetooth system doesn't support privacy-enabled scans, the UA SHOULD allow the user to indicate interest and then perform a privacy-disabled scan to retrieve the name.

    The UA MAY allow the user to select a nearby device that does not match uuidFilters.

  7. Wait for the user to have selected a device or cancelled the prompt.
  8. If the user cancels the prompt, reject promise with a NotFoundError and abort these steps.
  9. Add device to the origin's allowed devices map. with the union of requiredServiceUUIDs and optionalServiceUUIDs as allowed services.
  10. Get the BluetoothDevice representing device and resolve promise with the result.

To scan for devices with an optional set of Service UUIDs, defaulting to the set of all UUIDs, the UA MUST perform the following steps:

  1. If the UA has scanned for devices recently TODO: Nail down the amount of time. with a set of UUIDs that was a superset of the UUIDs for the current scan, then the UA MAY return the result of that scan and abort these steps.
  2. Let nearbyDevices be a set of Bluetooth devices, initially empty.
  3. If the UA supports the LE transport, perform the General Discovery Procedure and add the discovered Bluetooth devices to nearbyDevices. The UA SHOULD enable the Privacy Feature.

    Both passive scanning and the Privacy Feature avoid leaking the unique, immutable device ID. We ought to require UAs to use either one, but none of the OS APIs appear to expose either. Bluetooth also makes it hard to use passive scanning since it doesn't require Central devices to support the Observation Procedure.

  4. If the UA supports the BR/EDR transport, perform the Device Discovery procedure and add the discovered Bluetooth devices to nearbyDevices.

    All forms of BR/EDR inquiry/discovery appear to leak the unique, immutable device address.

  5. Let result be a set of Bluetooth devices, initially empty.
  6. For each Bluetooth device device in nearbyDevices, do the following substeps:
    1. If device's supported physical transports include LE and its Bluetooth Device Name is partial or absent, the UA SHOULD perform the Name Discovery Procedure to acquire a complete name.
    2. If device's advertised Service UUIDs have a non-empty intersection with the set of Service UUIDs, add device to result and abort these substeps.

      For BR/EDR devices, there is no way to distinguish GATT from non-GATT services in the Extended Inquiry Response. If a site filters to the UUID of a non-GATT service, the user may be able to select a device for the result of requestDevice that this API provides no way to interact with.

    3. The UA MAY connect to device and populate the Bluetooth cache with all Services whose UUIDs are in the set of Service UUIDs. If device's supported physical transports include BR/EDR, then in addition to the standard GATT procedures, the UA MAY use the Service Discovery Protocol (Searching for Services) when populating the cache.

      Connecting to every nearby device to discover services costs power and can slow down other use of the Bluetooth radio. UAs should only discover extra services on a device if they have some reason to expect that device to be interesting.

      UAs should also help developers avoid relying on this extra discovery behavior. For example, say a developer has previously connected to a device, so the UA knows the device's full set of supported services. If this developer then filters using a non-advertised UUID, the dialog they see may include this device, even if the filter would likely exclude the device on users' machines. The UA could provide a developer option to warn when this happens or to include only advertised services in matching filters.

    4. If the Bluetooth cache contains known-present Services inside device with UUIDs in the set of Service UUIDs, the UA MAY add device to result.
  7. Return result from the scan.

We need a way for a site to register to receive an event when an interesting device comes within range.

Device Representation

The UA needs to track Bluetooth device properties at several levels: globally, per origin, and per script execution environment.

Global Bluetooth device properties

The physical Bluetooth device may be guaranteed to have some properties that the UA may not have received. Those properties are described as optional here.

A Bluetooth device has the following properties. Optional properties are not present, and sequence and map properties are empty, unless/until described otherwise. Other properties have a default specified or are specified when a device is introduced.

The UA SHOULD determine that two Bluetooth devices are the same device if and only if they have the same Public Bluetooth Address, Static Address, Private Address, or Identity Resolving Key, or if the Resolvable Private Address Resolution Procedure succeeds using one device's IRK and the other's Resolvable Private Address. However, because platform APIs don't document how they determine device identity, the UA MAY use another procedure.

Per-origin Bluetooth device properties

For each origin, the UA MUST maintain an allowed devices map, whose keys are the Bluetooth devices the origin is allowed to access, and whose values are pairs of a DOMString device id and an allowed services list consisting of UUIDs for GATT Primary Services the origin is allowed to access on the device.

The UA MAY remove devices from the allowed devices map at any time based on signals from the user. This needs a definition involving removing BluetoothDevice instances from device instance maps and clearing out their [[\representedDevice]] fields. For example, if the user chooses not to remember access, the UA might remove a device when the tab that was granted access to it is closed. Or the UA might provide a revocation UI that allows the user to explicitly remove a device even while a tab is actively using that device. If a device is removed from this list while a Promise is pending to do something with the device, it MUST be treated the same as if the device moved out of Bluetooth range.

To add an allowed Bluetooth device device to an origin's allowed devices map with an optional allowed services list of UUIDs, the UA MUST run the following steps.

  1. If device is the same device as an existing key in the allowed devices map, abort these steps.
  2. Let id be a new DOMString that isn't equal to any of the device ids in the origin's allowed devices map and isn't equal to or derived from any of device's Public Bluetooth Address, Static Address, or Identity Resolving Key. id MUST, with very high probability, be unequal to the device ids used for keys in any other origin's allowed devices map or previously in this origin's allowed devices map that are the same device as device.
  3. If allowed services wasn't provided, set it to an empty list.
  4. Add a mapping from device to a pair of id and allowed services in the allowed devices map.

BluetoothDevice

A BluetoothDevice instance represents a Bluetooth device inside a particular script execution environment.

          // Allocation authorities for Vendor IDs:
          enum VendorIDSource {
            "bluetooth",
            "usb"
          };

          interface BluetoothDevice {
            readonly attribute DOMString id;
            readonly attribute DOMString? name;
            readonly attribute BluetoothAdvertisingData adData;
            readonly attribute unsigned long? deviceClass;
            readonly attribute VendorIDSource? vendorIDSource;
            readonly attribute unsigned long? vendorID;
            readonly attribute unsigned long? productID;
            readonly attribute unsigned long? productVersion;
            readonly attribute boolean paired;
            readonly attribute BluetoothGATTRemoteServer? gattServer;
            readonly attribute UUID[] uuids;
            Promise<BluetoothGATTRemoteServer> connectGATT();
          };
          BluetoothDevice implements EventTarget;
          BluetoothDevice implements CharacteristicEventHandlers;
          BluetoothDevice implements ServiceEventHandlers;
        

id uniquely identifies a device to the extent that the UA can determine that two Bluetooth connections are to the same device. It is computed as the device id in add an allowed Bluetooth device. This ID can't be used to match a device across origins or after the user revokes and re-grants access to the device.

name is the human-readable name of the device.

adData contains the most recent advertising data received for this device. TODO: Write the algorithm to update this when an advertising packet is received.

deviceClass is the class of the device, a bit-field defined by [[!BLUETOOTH-ASSIGNED-BASEBAND]].

vendorIDSource is the Vendor ID Source field in the pnp_id characteristic in the device_information service.

vendorID is the 16-bit Vendor ID field in the pnp_id characteristic in the device_information service.

productID is the 16-bit Product ID field in the pnp_id characteristic in the device_information service.

productVersion is the 16-bit Product Version field in the pnp_id characteristic in the device_information service.

paired indicates whether or not the device is paired with the system.

If the UA is currently connected to this device's GATT server, gattServer provides a way to interact with it. While this device is disconnected, gattServer is null.

uuids lists the UUIDs of GATT services known to be on the device, that the current origin is allowed to access.

For each script execution environment, the UA must maintain a device instance map mapping Bluetooth devices to Promise<BluetoothDevice> instances. To get the BluetoothDevice representing a Bluetooth device device, the UA MUST run the following steps:

  1. If there is a key in the current script execution environment's device instance map that is the same device as device, return its value and abort these steps.
  2. Let promise be a new promise.
  3. Add a mapping from device to promise in the current script execution environment's device instance map.
  4. Return promise, and run the following steps in parallel.
    1. Let result be a new instance of BluetoothDevice.
    2. Initialize all of result's optional fields to null.
    3. Initialize an internal result@[[\representedDevice]] field to device.
    4. Find the key in this origin's allowed devices map that is the same device as device. If there is no such key, resolve promise with a SecurityError and abort these steps. Otherwise, initialize result.id to the device id this key maps to, and initialize an internal result@[[\allowedServices]] field to the allowed services list this key maps to.
    5. If device has a partial or complete Bluetooth Device Name, set result.name to that string.
    6. Create a BluetoothAdvertisingData from device and result@[[\allowedServices]], and set result.adData to the result.
    7. If device has a Class of Device, set result.deviceClass to that value.
    8. Populate the Bluetooth cache with the org.bluetooth.characteristic.pnp_id characteristic inside the org.bluetooth.service.device_information service. Ignore any errors from this step.
    9. If the Bluetooth cache now has a known-present entry for this characteristic, run the following substeps.
      1. Use any combination of the sub-procedures in the Characteristic Value Read procedure to retrieve the value of the org.bluetooth.characteristic.pnp_id characteristic into pnp. Handle errors as described in .
      2. If the previous step returned an error, abort these substeps.
      3. Parse pnp as specified by the org.bluetooth.characteristic.pnp_id characteristic definition. If it's not 7 bytes long or if the Vendor ID Source is not 1 or 2, abort these substeps.
      4. Set result.vendorIDSource according to the following table:
        Parsed Vendor Id SourcevendorIDSource
        1"bluetooth"
        2"usb"
      5. Set result.vendorID to the value parsed for Vendor ID.
      6. Set result.productID to the value parsed for Product ID.
      7. Set result.productVersion to the value parsed for Product Version.
    10. Initialize result.paired to the value of device's bonded flag.
    11. Let uuids be an empty set of UUIDs.
    12. Add device's advertised Service UUIDs to uuids.
    13. The UA MAY populate the Bluetooth cache with all Services inside device. Ignore any errors from this step.
    14. If the Bluetooth cache contains known-present Services inside device, add the UUIDs of those Services to uuids.
    15. Initialize result.uuids to a read only Array holding the elements of uuids that are also in result@[[\allowedServices]].
    16. Resolve promise with result.

The connectGATT() method, when invoked, MUST return a new promise promise and run the following steps in parallel:

  1. If this@[[\representedDevice]] has no ATT Bearer, attempt to create one using the procedures described in "Connection Establishment" under GAP Interoperability Requirements.
  2. If this attempt fails, reject promise with a NetworkError and abort these steps.
  3. Queue a task to do the following steps:
    1. If this.gattServer is null, set it to a new BluetoothGATTRemoteServer instance with its device attribute initialized to this and its connected attribute initialized to true.
    2. Resolve promise with this.gattServer.

BluetoothAdvertisingData

            interface BluetoothAdvertisingData {
              readonly attribute unsigned short? appearance;
              readonly attribute byte? txPower;
              readonly attribute byte? rssi;
              readonly attribute Map manufacturerData;
              readonly attribute Map serviceData;
            };
          

appearance is an Appearance, one of the values defined by the org.bluetooth.characteristic.gap.appearance characteristic.

txPower is the transmission power at which the device is broadcasting, measured in dBm. This is used to compute the path loss as this.txPower - this.rssi.

rssi is the power at which the device's packets are being received, measured in dBm. This is used to compute the path loss as this.txPower - this.rssi.

manufacturerData maps unsigned short Company Identifier Codes to ArrayBuffers.

serviceData maps UUIDs to ArrayBuffers.

All fields in BluetoothAdvertisingData return the last value they were initialized or set to.

To create a BluetoothAdvertisingData from a Bluetooth device device and an allowed services list, the UA must perform the following steps:

  1. Let adData be a new instance of BluetoothAdvertisingData.
  2. If device has an Appearance, initialize adData.appearance to its value. Otherwise, initialize it to null.
  3. If device has a TX Power Level, initialize adData.txPower to its value. Otherwise initialize it to null.
  4. If device has an RSSI, initialize adData.rssi to its value. Otherwise initialize it to null.
  5. Initialize adData.manufacturerData with the return value of these substeps:
    1. Let mdata be a new Map instance.
    2. For each mapping in device's Manufacturer Specific Data, make a new read only ArrayBuffer bytes containing the contents of its byte array, and add a mapping from the 16-bit code to bytes in mdata.
    3. Return a read only Map whose value is mdata.
  6. Initialize adData.serviceData with the return value of these substeps:
    1. Let sdata be a new Map instance.
    2. For each mapping in device's Service Data, if the UUID is in allowed services list, make a new read only ArrayBuffer bytes containing the contents of its byte array, and add a mapping from the UUID to bytes in sdata.
    3. Return a read only Map whose value is sdata.
  7. Return adData.

GATT Interaction

GATT Information Model

The GATT Profile Hierarchy describes how a GATT Server contains a hierarchy of Profiles, Primary Services, Included Services, Characteristics, and Descriptors.

Profiles are purely logical: the specification of a Profile describes the expected interactions between the other GATT entities the Profile contains, but it's impossible to query which Profiles a device supports.

GATT Clients can discover and interact with the Services, Characteristics, and Descriptors on a device using a set of GATT procedures. This spec refers to Services, Characteristics, and Descriptors collectively as Attributes. All Attributes have a type that's identified by a UUID. Each Attribute also has a 16-bit Attribute Handle that distinguishes it from other Attributes of the same type on the same GATT Server. Attributes are notionally ordered within their GATT Server by their Attribute Handle, but while platform interfaces provide these entities in some order, they do not guarantee that it's consistent with the Attribute Handle order.

A Service contains a collection of Included Services and Characteristics. The Included Services are references to other Services, and a single Service can be included by more than one other Service. Services are known as Primary Services if they appear directly under the GATT Server, and Secondary Services if they're only included by other Services, but Primary Services can also be included.

A Characteristic contains a value, which is an array of bytes, and a collection of Descriptors. Depending on the properties of the Characteristic, a GATT Client can read or write its value, or register to be notified when the value changes.

Finally, a Descriptor contains a value (again an array of bytes) that describes or configures its Characteristic.

The Bluetooth cache

The UA MUST maintain a Bluetooth cache of the hierarchy of Services, Characteristics, and Descriptors it has discovered on a device. The UA MAY share this cache between multiple origins accessing the same device. Each potential entity in the cache is either known-present, known-absent, or unknown. The cache MUST NOT contain two entities that are for the same attribute. Each known-present entity in the cache is associated with an optional Promise<BluetoothGATTService>, Promise<BluetoothGATTCharacteristic>, or Promise<BluetoothGATTDescriptor> instance for each script execution environment.

For example, if a user calls the serviceA.getCharacteristic(uuid1) function with an initially empty Bluetooth cache, the UA uses the Discover Characteristics by UUID procedure to fill the needed cache entries, and the UA ends the procedure early because it only needs one Characteristic to fulfil the returned Promise, then the first Characteristic with UUID uuid1 inside serviceA is known-present, and any subsequent Characteristics with that UUID remain unknown. If the user later calls serviceA.getCharacteristics(uuid1), the UA needs to resume or restart the Discover Characteristics by UUID procedure. If it turns out that serviceA only has one Characteristic with UUID uuid1, then the subsequent Characteristics become known-absent.

The known-present entries in the Bluetooth cache are ordered: Primary Services appear in a particular order within a device, Included Services and Characteristics appear in a particular order within Services, and Descriptors appear in a particular order within Characteristics. The order SHOULD match the order of Attribute Handles on the device, but UAs MAY use another order if the device's order isn't available.

To populate the Bluetooth cache with entries matching some description, the UA MUST run the following steps. Note that these steps can block, so uses of this algorithm must be in parallel.

  1. Attempt to make all matching entries in the cache either known-present or known-absent, using any sequence of GATT procedures that [[BLUETOOTH42]] specifies will return enough information. Handle errors as described in .
  2. If the previous step returns an error, return that error from this algorithm.

To query the Bluetooth cache for entries matching some description, the UA MUST return a new promise promise and run the following steps in parallel:

  1. Populate the Bluetooth cache with entries matching the description.
  2. If the previous step returns an error, reject promise with that error and abort these steps.
  3. Let entries be the sequence of known-present cache entries matching the description.
  4. Let result be a new sequence.
  5. For each entry in entries:
    1. If entry has no associated Promise<BluetoothGATT*> instance for the current script execution environment, create a BluetoothGATTService representing entry, create a BluetoothGATTCharacteristic representing entry, or create a BluetoothGATTDescriptor representing entry, depending on whether entry is a Service, Characteristic, or Descriptor, and associate the resulting Promise with entry.
    2. Append to result the Promise<BluetoothGATT*> instance associated with entry for the current script execution environment.
  6. Wait for all elements of result to settle.
  7. Let updatedEntries be the sequence of known-present cache entries now matching the description.
  8. If entries and updatedEntries have different elements, go back to step 3.

    This can happen if a Service Changed indication arrives while the new Promise<BluetoothGATT*> instances are settling. The algorithm restarts to make sure the result is consistent with serviceadded, servicechanged, and serviceremoved events that have already been delivered. Service Changed indications are expected to be rare, so this shouldn't cost too much.

  9. Resolve promise with the result of waiting for all elements of result.

Navigating the Bluetooth Hierarchy

To GetGATTChildren(attribute: GATT Attribute,
single: boolean,
uuidCanonicalizer: function,
uuid: optional (DOMString or unsigned int),
child type: GATT declaration type),

the UA MUST perform the following steps:

  1. If uuid is present, set it to uuidCanonicalizer(uuid). If uuidCanonicalizer threw an exception, return a promise rejected with that exception and abort these steps.
  2. If uuid is present and is blacklisted, return a promise rejected with a SecurityError and abort these steps.
  3. If attribute is known-absent in the Bluetooth cache, return a promise rejected with an InvalidStateError.
  4. Query the Bluetooth cache for entries that:
    • are within attribute,
    • have a type described by child type,
    • if uuid is present, have a UUID of uuid, and
    • if the single flag is set, are the first of these.
    Let promise be the result.
  5. If attribute has become known-absent in the Bluetooth cache since the first check, return a promise rejected with an InvalidStateError.
  6. Return the result of transforming promise with a fulfillment handler that:
    • If its argument is empty, throws a NotFoundError,
    • Otherwise, if the single flag is set, returns the first (only) element of its argument.
    • Otherwise, returns its argument.

Identifying Services, Characteristics, and Descriptors

When checking whether two Services, Characteristics, or Descriptors a and b are the same attribute, the UA SHOULD determine that they are the same if a and b are inside the same device and have the same Attribute Handle, but MAY use any algorithm it wants with the constraint that a and b MUST NOT be considered the same attribute if they fit any of the following conditions:

  • They are not both Services, both Characteristics, or both Descriptors.
  • They are both Services, but are not both primary or both secondary services.
  • They have different UUIDs.
  • Their parent Devices aren't the same device or their parent Services or Characteristics aren't the same attribute.

This definition is loose because platform APIs expose their own notion of identity without documenting whether it's based on Attribute Handle equality.

For two Javascript objects representing Services, Characteristics, or Descriptors, x === y returns whether the objects represent the same attribute, because of how the query the Bluetooth cache algorithm creates and caches new objects.

BluetoothGATTRemoteServer

BluetoothGATTRemoteServer represents a GATT Server on a remote device.

          interface BluetoothGATTRemoteServer {
            readonly attribute BluetoothDevice device;
            readonly attribute boolean connected;
            void disconnect();
            Promise<BluetoothGATTService> getPrimaryService(BluetoothServiceUUID service);
            Promise<sequence<BluetoothGATTService>>
              getPrimaryServices(optional BluetoothServiceUUID service);
          };
          BluetoothGATTRemoteServer implements EventTarget;
          BluetoothGATTRemoteServer implements CharacteristicEventHandlers;
          BluetoothGATTRemoteServer implements ServiceEventHandlers;
        

device is the device running this server.

connected is true while this script execution environment is connected to this.device. It can be false while the UA is physically connected.

The disconnect() method, when invoked, MUST perform the following steps:

  1. Set this.connected to false.
  2. In parallel: if, for all script execution environments, all BluetoothDevices device with device@[[\representedDevice]] the same device as this.device@[[\representedDevice]], device.gattServer === null or !device.gattServer.connected, the UA MAY destroy device@[[\representedDevice]]'s ATT Bearer.

The getPrimaryService(service) method, when invoked, MUST return

GetGATTChildren(attribute=this@[[\representedDevice]],
single=true,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
child type="GATT Primary Service")

The getPrimaryServices(service) method, when invoked, MUST return

GetGATTChildren(attribute=this@[[\representedDevice]],
single=false,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
child type="GATT Primary Service")

BluetoothGATTService

BluetoothGATTService represents a GATT Service, a collection of characteristics and relationships to other services that encapsulate the behavior of part of a device.

          interface BluetoothGATTService {
            readonly attribute BluetoothDevice device;
            readonly attribute UUID uuid;
            readonly attribute boolean isPrimary;
            Promise<BluetoothGATTCharacteristic>
              getCharacteristic(BluetoothCharacteristicUUID characteristic);
            Promise<sequence<BluetoothGATTCharacteristic>>
              getCharacteristics(optional BluetoothCharacteristicUUID characteristic);
            Promise<BluetoothGATTService>
              getIncludedService(BluetoothServiceUUID service);
            Promise<sequence<BluetoothGATTService>>
              getIncludedServices(optional BluetoothServiceUUID service);
          };
          BluetoothGATTService implements EventTarget;
          BluetoothGATTService implements CharacteristicEventHandlers;
          BluetoothGATTService implements ServiceEventHandlers;
        

device is the BluetoothDevice representing the remote peripheral that the GATT service belongs to.

uuid is the UUID of the service, e.g. '0000180d-0000-1000-8000-00805f9b34fb' for the Heart Rate service.

isPrimary indicates whether the type of this service is primary or secondary.

To create a BluetoothGATTService representing a Service service, the UA must return a new promise promise and run the following steps in parallel.

  1. Let result be a new instance of BluetoothGATTService.
  2. Get the BluetoothDevice representing the device in which service appears, and let devicePromise be the result.
  3. Wait for devicePromise to settle.
  4. If devicePromise rejected, resolve promise with devicePromise and abort these steps.
  5. Initialize result.device from the value of devicePromise.
  6. Initialize result.uuid from the UUID of service.
  7. If service is a Primary Service, initialize result.isPrimary to true. Otherwise initialize result.isPrimary to false.
  8. Resolve promise with result.

The getCharacteristic(characteristic) method retrieves a Characteristic inside this Service. When invoked, it MUST return

GetGATTChildren(attribute=this,
single=true,
uuidCanonicalizer=BluetoothUUID.getCharacteristic,
uuid=characteristic,
child type="GATT Characteristic")

The getCharacteristics(characteristic) method retrieves a list of Characteristics inside this Service. When invoked, it MUST return

GetGATTChildren(attribute=this,
single=false,
uuidCanonicalizer=BluetoothUUID.getCharacteristic,
uuid=characteristic,
child type="GATT Characteristic")

The getIncludedService(service) method retrieves an Included Service inside this Service. When invoked, it MUST return

GetGATTChildren(attribute=this,
single=true,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
child type="GATT Included Service")

The getIncludedServices(service) method retrieves a list of Included Services inside this Service. When invoked, it MUST return

GetGATTChildren(attribute=this,
single=false,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
child type="GATT Included Service")

BluetoothGATTCharacteristic

BluetoothGATTCharacteristic represents a GATT Characteristic, which is a basic data element that provides further information about a peripheral's service.

          interface BluetoothGATTCharacteristic {
            readonly attribute BluetoothGATTService service;
            readonly attribute UUID uuid;
            readonly attribute CharacteristicProperties properties;
            readonly attribute ArrayBuffer? value;
            Promise<BluetoothGATTDescriptor> getDescriptor(BluetoothDescriptorUUID descriptor);
            Promise<sequence<BluetoothGATTDescriptor>>
              getDescriptors(optional BluetoothDescriptorUUID descriptor);
            Promise<ArrayBuffer> readValue();
            Promise<void> writeValue(BufferSource value);
            Promise<void> startNotifications();
            Promise<void> stopNotifications();
          };
          BluetoothGATTCharacteristic implements EventTarget;
          BluetoothGATTCharacteristic implements CharacteristicEventHandlers;
        

service is the GATT service this characteristic belongs to.

uuid is the UUID of the characteristic, e.g. '00002a37-0000-1000-8000-00805f9b34fb' for the Heart Rate Measurement characteristic.

properties holds the properties of this characteristic.

value is the currently cached characteristic value. This value gets updated when the value of the characteristic is read or updated via a notification or indication.

To create a BluetoothGATTCharacteristic representing a Characteristic characteristic, the UA must return a new promise promise and run the following steps in parallel.

  1. Let result be a new instance of BluetoothGATTCharacteristic.
  2. Initialize result.service from the BluetoothGATTService instance representing the Service in which characteristic appears.
  3. Initialize result.uuid from the UUID of characteristic.
  4. Create a CharacteristicProperties instance from the Characteristic characteristic, and let propertiesPromise be the result.
  5. Wait for propertiesPromise to settle.
  6. If propertiesPromise was rejected, resolve promise with propertiesPromise and abort these steps.
  7. Initialize result.properties from the value propertiesPromise was fulfilled with.
  8. Initialize result.value to null. The UA MAY initialize result.value to a new ArrayBuffer containing the most recently read value from characteristic if this value is available.
  9. Resolve promise with result.

The getDescriptor(descriptor) method retrieves a Descriptor inside this Characteristic. When invoked, it MUST return

GetGATTChildren(attribute=this,
single=true,
uuidCanonicalizer=BluetoothUUID.getDescriptor,
uuid=descriptor,
child type="GATT Descriptor")

The getDescriptors(descriptor) method retrieves a list of Descriptors inside this Characteristic. When invoked, it MUST return

GetGATTChildren(attribute=this,
single=false,
uuidCanonicalizer=BluetoothUUID.getDescriptor,
uuid=descriptor,
child type="GATT Descriptor")

The readValue() method, when invoked, MUST return a new promise promise and run the following steps in parallel:

  1. If this.uuid is blacklisted for reads, return a promise rejected with a SecurityError and abort these steps.
  2. Let characteristic be the Characteristic that this represents.
  3. If the Read bit is not set in characteristic's properties, reject promise with a NotSupportedError and abort these steps.
  4. Use any combination of the sub-procedures in the Characteristic Value Read procedure to retrieve the value of characteristic. Handle errors as described in .
  5. If the previous step returned an error, reject promise with that error and abort these steps.
  6. Queue a task to perform the following steps:
    1. Create an ArrayBuffer holding the retrieved value, and assign it to this.value.
    2. Resolve promise with this.value.
    3. Fire an event named characteristicvaluechanged with its bubbles attribute initialized to true at this.

The writeValue(value) method, when invoked, MUST run the following steps:

  1. If this.uuid is blacklisted for writes, return a promise rejected with a SecurityError and abort these steps.
  2. Let characteristic be the Characteristic that this represents.
  3. Let bytes be a copy of the bytes held by value.
  4. If bytes is more than 512 bytes long (the maximum length of an attribute value, per Long Attribute Values) return a promise rejected with an InvalidModificationError and abort these steps.
  5. Return a new promise promise and run the following steps in parallel.
    1. Use any combination of the sub-procedures in the Characteristic Value Write procedure to write bytes to characteristic. Handle errors as described in .
    2. If the previous step returned an error, reject promise with that error and abort these steps.
    3. Queue a task to perform the following steps:
      1. Set this.value to a new ArrayBuffer containing bytes.
      2. Resolve promise with undefined.

For each known GATT Characteristic, the UA MUST maintain an active notification context set of Bluetooth objects. This is a single set for the whole UA, pointing to the navigator.bluetooth object for each separate script execution environment that has registered for notifications.

The startNotifications() method, when invoked, MUST return a new promise promise and run the following steps in parallel. See for details of receiving notifications.

  1. If this.uuid is blacklisted for reads, reject promise with a SecurityError and abort these steps.
  2. Let characteristic be the GATT Characteristic that this represents.
  3. If neither of the Notify or Indicate bits are set in characteristic's properties, reject promise with a NotSupportedError and abort these steps.
  4. If the active notification context set contains navigator.bluetooth, resolve promise with undefined and abort these steps.
  5. Use any of the Characteristic Descriptors procedures to ensure that one of the Notification or Indication bits in characteristic's Client Characteristic Configuration descriptor is set, matching the constraints in characteristic's properties. The UA SHOULD avoid setting both bits, and MUST deduplicate value-change events if both bits are set. Handle errors as described in .
  6. If the previous step returned an error, reject promise with that error and abort these steps.
  7. Add navigator.bluetooth to the active notification context set.
  8. Resolve promise with undefined.

After notifications are enabled, the resulting value-change events won't be delivered until after the current microtask checkpoint. This allows a developer to set up handlers in the .then handler of the result promise.

The stopNotifications() method, when invoked, MUST return a new promise promise and run the following steps in parallel:

  1. Let characteristic be the GATT Characteristic that this represents.
  2. If the active notification context set contains navigator.bluetooth, remove it.
  3. If the active notification context set became empty, the UA SHOULD use any of the Characteristic Descriptors procedures to clear the Notification and Indication bits in characteristic's Client Characteristic Configuration descriptor.
  4. Queue a task to resolve promise with undefined.

Queuing a task to resolve the promise ensures that no value change events due to notifications arrive after the promise resolves.

CharacteristicProperties

Each BluetoothGATTCharacteristic exposes its characteristic properties through a CharacteristicProperties object. These properties express what operations are valid on the characteristic.

            interface BluetoothCharacteristicProperties {
              readonly attribute boolean broadcast;
              readonly attribute boolean read;
              readonly attribute boolean writeWithoutResponse;
              readonly attribute boolean write;
              readonly attribute boolean notify;
              readonly attribute boolean indicate;
              readonly attribute boolean authenticatedSignedWrites;
              readonly attribute boolean reliableWrite;
              readonly attribute boolean writableAuxiliaries;
            };
          

To create a CharacteristicProperties instance from the Characteristic characteristic, the UA MUST return a new promise promise and run the following steps in parallel:

  1. Let propertiesObj be a new instance of CharacteristicProperties.
  2. Let properties be the characteristic properties of characteristic.
  3. Initialize the attributes of propertiesObj from the corresponding bits in properties:
    AttributeBit
    broadcastBroadcast
    readRead
    writeWithoutResponseWrite Without Response
    writeWrite
    notifyNotify
    indicateIndicate
    authenticatedSignedWrites Authenticated Signed Writes
  4. If the Extended Properties bit of the characteristic properties is not set, initialize propertiesObj.reliableWrite and propertiesObj.writableAuxiliaries to false. Otherwise, run the following steps:
    1. Discover the Characteristic Extended Properties descriptor for characteristic and read its value into extendedProperties. Handle errors as described in .

      Characteristic Extended Properties isn't clear whether the extended properties are immutable for a given Characteristic. If they are, the UA should be allowed to cache them.

    2. If the previous step returned an error, reject promise with that error and abort these steps.
    3. Initialize propertiesObj.reliableWrite from the Reliable Write bit of extendedProperties.
    4. Initialize propertiesObj.writableAuxiliaries from the Writable Auxiliaries bit of extendedProperties.
  5. Resolve promise with propertiesObj.

BluetoothGATTDescriptor

BluetoothGATTDescriptor represents a GATT Descriptor, which provides further information about a Characteristic's value.

          interface BluetoothGATTDescriptor {
            readonly attribute BluetoothGATTCharacteristic characteristic;
            readonly attribute UUID uuid;
            readonly attribute ArrayBuffer? value;
            Promise<ArrayBuffer> readValue();
            Promise<void> writeValue(BufferSource value);
          };
        

characteristic is the GATT characteristic this descriptor belongs to.

uuid is the UUID of the characteristic descriptor, e.g. '00002902-0000-1000-8000-00805f9b34fb' for the Client Characteristic Configuration descriptor.

value is the currently cached descriptor value. This value gets updated when the value of the descriptor is read.

To create a BluetoothGATTDescriptor representing a Descriptor descriptor, the UA must return a new promise promise and run the following steps in parallel.

  1. Let result be a new instance of BluetoothGATTDescriptor.
  2. Initialize result.characteristic from the BluetoothGATTCharacteristic instance representing the Characteristic in which descriptor appears.
  3. Initialize result.uuid from the UUID of descriptor.
  4. Initialize result.value to null. The UA MAY initialize result.value to a new ArrayBuffer containing the most recently read value from descriptor if this value is available.
  5. Resolve promise with result.

The readValue() method, when invoked, MUST return a new promise promise and run the following steps in parallel:

  1. If this.uuid is blacklisted for reads, return a promise rejected with a SecurityError and abort these steps.
  2. Let descriptor be the Descriptor that this represents.
  3. Use either the Read Characteristic Descriptors or the Read Long Characteristic Descriptors sub-procedure to retrieve the value of descriptor. Handle errors as described in .
  4. If the previous step returned an error, reject promise with that error and abort these steps.
  5. Queue a task to perform the following steps:
    1. Create an ArrayBuffer holding the retrieved value, and assign it to this.value.
    2. Resolve promise with this.value.

The writeValue(value) method, when invoked, MUST run the following steps:

  1. If this.uuid is blacklisted for writes, return a promise rejected with a SecurityError and abort these steps.
  2. Let descriptor be the Descriptor that this represents.
  3. Let bytes be a copy of the bytes held by value.
  4. If bytes is more than 512 bytes long (the maximum length of an attribute value, per Long Attribute Values) return a promise rejected with an InvalidModificationError and abort these steps.
  5. Return a new promise promise and run the following steps in parallel.
    1. Use either the Write Characteristic Descriptors or the Write Long Characteristic Descriptors sub-procedure to write bytes to descriptor. Handle errors as described in .
    2. If the previous step returned an error, reject promise with that error and abort these steps.
    3. Queue a task to perform the following steps:
      1. Set this.value to a new ArrayBuffer containing bytes.
      2. Resolve promise with undefined.

Events

Bluetooth Tree

navigator.bluetooth and objects implementing the BluetoothDevice, BluetoothGATTService, BluetoothGATTCharacteristic, or BluetoothGATTDescriptor interface participate in a tree, simply named the Bluetooth tree.

Event types

characteristicvaluechanged
Fired on a BluetoothGATTCharacteristic when its value changes, either as a result of a read request, or a value change notification/indication.
serviceadded
Fired on a new BluetoothGATTService when it has been discovered on a remote device, just after it is added to the Bluetooth tree.
servicechanged
Fired on a BluetoothGATTService when its state changes. This involves any characteristics and/or descriptors that get added or removed from the service, as well as Service Changed indications from the remote device.
serviceremoved
Fired on a BluetoothGATTService when it has been removed from its device, just before it is removed from the Bluetooth tree.

Responding to Notifications and Indications

When the UA receives a Bluetooth Characteristic Value Notification or Indication, it must perform the following steps:

  1. For each bluetoothGlobal in the active notification context set for the Characteristic, queue a task on the event loop of the script settings object of bluetoothGlobal to do the following steps:
    1. Let characteristicObject be the BluetoothGATTCharacteristic in the Bluetooth tree rooted at bluetoothGlobal that represents the Characteristic.
    2. Set characteristicObject.value to a new ArrayBuffer holding the new value of the Characteristic.
    3. Fire an event named characteristicvaluechanged with its bubbles attribute initialized to true at characteristicObject.

Responding to Service Changes

The Bluetooth Attribute Caching system allows clients to track changes to Services, Characteristics, and Descriptors. Before discovering any of these entities for the purpose of exposing them to a web page the UA MUST subscribe to Indications from the Service Changed characteristic, if it exists. When the UA receives an Indication on the Service Changed characteristic, it MUST perform the following steps.

  1. Let removedEntities be the list of entities in the range indicated by the Service Changed characteristic that the UA had discovered before the Indication.
  2. Use the Primary Service Discovery, Relationship Discovery, Characteristic Discovery, and Characteristic Descriptor Discovery procedures to re-discover entities in the range indicated by the Service Changed characteristic. The UA MAY skip discovering all or part of the indicated range if it can prove that the results of that discovery could not affect the events fired below.
  3. Let addedEntities be the list of entities discovered in the previous step.
  4. If an entity with the same definition, ignoring Characteristic and Descriptor values, appears in both removedEntities and addedEntities, remove it from both.
  5. Let changedServices be a set of Services, initially empty.
  6. If the same Service appears in both removedEntities and addedEntities, remove it from both, and add it to changedServices.
  7. Set each attribute in removedEntities to known-absent in the Bluetooth cache. Set each attribute in addedEntities to known-present in the Bluetooth cache.
  8. For each Characteristic and Descriptor in removedEntities and addedEntities, remove it from its original list, and add its parent Service to changedServices. After this point, removedEntities and addedEntities contain only Services.
  9. If a Service in addedEntities would not have been returned to any script execution environment if it had existed at the time of any previous call to getPrimaryService, getPrimaryServices, getIncludedService, or getIncludedServices, the UA MAY remove the Service from addedEntities.
  10. Let changedDevices be the set of Bluetooth devices that contain any Service in removedEntities, addedEntities, and changedServices.
  11. For each script execution environment that is connected to a device in changedDevices, queue a task on its event loop to do the following steps:
    1. For each Service in removedEntities, fire an event named serviceremoved with its bubbles attribute initialized to true at the BluetoothGATTService representing the Service. Then remove this BluetoothGATTService from the Bluetooth tree.
    2. For each Service in addedEntities, add the BluetoothGATTService representing this Service to the Bluetooth tree. Then fire an event named serviceadded with its bubbles attribute initialized to true at the BluetoothGATTService.
    3. For each Service in changedServices, fire an event named servicechanged with its bubbles attribute initialized to true at the BluetoothGATTService representing the Service.

IDL event handlers

            [NoInterfaceObject]
            interface CharacteristicEventHandlers {
              attribute EventHandler oncharacteristicvaluechanged;
            };
          

oncharacteristicvaluechanged is an Event handler IDL attribute for the characteristicvaluechanged event type.

            [NoInterfaceObject]
            interface ServiceEventHandlers {
              attribute EventHandler onserviceadded;
              attribute EventHandler onservicechanged;
              attribute EventHandler onserviceremoved;
            };
          

onserviceadded is an Event handler IDL attribute for the serviceadded event type.

onservicechanged is an Event handler IDL attribute for the servicechanged event type.

onserviceremoved is an Event handler IDL attribute for the serviceremoved event type.

Error handling

This section primarily defines the mapping from system errors to Javascript error names and allows UAs to retry certain operations. The retry logic and possible error distinctions are highly constrained by the operating system, so places these requirements don't reflect reality are likely spec bugs instead of browser bugs.

When the UA is using a GATT procedure to execute a step in an algorithm or to handle a query to the Bluetooth cache (both referred to as a "step", here), and the GATT procedure returns an Error Response, the UA MUST perform the following steps:

  1. If the procedure times out or the ATT Bearer (described in Profile Fundamentals) is terminated for any reason, return a NetworkError from the step and abort these steps.
  2. Take the following actions depending on the Error Code:
    Invalid PDU
    Invalid Offset
    Attribute Not Found
    Unsupported Group Type
    These error codes indicate that something unexpected happened at the protocol layer, likely either due to a UA or device bug. Return a NotSupportedError from the step.
    Invalid Handle
    This can happen if an attribute is removed from the GATT server during another procedure. Usually applications can avoid this error by listening for the servicechanged and serviceremoved events, but there's necessarily a gap between the Bluetooth message reporting a change and the Javascript event communicating it to a web page, in which the web page can start an invalid operation.

    Return an InvalidStateError from the step.

    Invalid Attribute Value Length
    Return an InvalidModificationError from the step.
    Attribute Not Long

    If this error code is received without having used a "Long" sub-procedure, this may indicate a device bug. Return a NotSupportedError from the step.

    Otherwise, retry the step without using a "Long" sub-procedure. If this is impossible due to the length of the value being written, return an InvalidModificationError from the step.

    Insufficient Authentication
    Insufficient Encryption
    Insufficient Encryption Key Size
    The UA SHOULD attempt to increase the security level of the connection. If this attempt fails or the UA doesn't support any higher security, Return a SecurityError from the step. Otherwise, retry the step at the new higher security level.
    Insufficient Authorization
    Return a SecurityError from the step.
    Application Error
    If the GATT procedure was a Write, return an InvalidModificationError from the step. Otherwise, return a NotSupportedError from the step.
    Read Not Permitted
    Write Not Permitted
    Request Not Supported
    Prepare Queue Full
    Insufficient Resources
    Unlikely Error
    Anything else
    Return a NotSupportedError from the step.

UUIDs

typedef DOMString UUID;

A UUID string represents a 128-bit [[!RFC4122]] UUID. A valid UUID is a string that matches the [[!ECMAScript]] regexp /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/. That is, a valid UUID is lower-case and does not use the 16- or 32-bit abbreviations defined by the Bluetooth standard. All UUIDs returned from functions and attributes in this specification MUST be valid UUIDs. If a function in this specification takes a parameter whose type is UUID or a dictionary including a UUID attribute, and the argument passed in any UUID slot is not a valid UUID, the function MUST return a promise rejected with a TypeError and abort its other steps.

This standard provides the BluetoothUUID.canonicalUUID(alias) function to map a 16- or 32-bit Bluetooth UUID alias to its 128-bit form.

Bluetooth devices are required to convert 16- and 32-bit UUIDs to 128-bit UUIDs before comparing them (as described in Attribute Type), but not all devices do so. To interoperate with these devices, if the UA has received a UUID from the device in one form (16-, 32-, or 128-bit), it should send other aliases of that UUID back to the device in the same form.

Standardized UUIDs

The Bluetooth SIG maintains a registry at [[BLUETOOTH-ASSIGNED]] of UUIDs that identify services, characteristics, descriptors, and other entities. This section provides a way for script to look up those UUIDs by name so they don't need to be replicated in each application.

          interface BluetoothUUID {
            static UUID getService((DOMString or unsigned long) name);
            static UUID getCharacteristic((DOMString or unsigned long) name);
            static UUID getDescriptor((DOMString or unsigned long) name);

            static UUID canonicalUUID([EnforceRange] unsigned long alias);
          };

          typedef (DOMString or unsigned long) BluetoothServiceUUID;
          typedef (DOMString or unsigned long) BluetoothCharacteristicUUID;
          typedef (DOMString or unsigned long) BluetoothDescriptorUUID;
        

The static BluetoothUUID.canonicalUUID(alias) method, when invoked, MUST return the 128-bit UUID represented by the 16- or 32-bit UUID alias alias.

This algorithm consists of replacing the top 32 bits of "00000000-0000-1000-8000-00805f9b34fb" with the bits of the alias. For example, canonicalUUID(0xDEADBEEF) returns "deadbeef-0000-1000-8000-00805f9b34fb".

BluetoothServiceUUID represents 16- and 32-bit UUID aliases, valid UUIDs, and names defined in [[BLUETOOTH-ASSIGNED-SERVICES]], or, equivalently, the values for which BluetoothUUID.getService does not throw an exception.

The static BluetoothUUID.getService(name) method, when invoked, MUST run the following steps:

  1. If name is an unsigned long, return BluetoothUUID.canonicalUUID(name) and abort these steps.
  2. If name is a valid UUID, return name and abort these steps.
  3. If org.bluetooth.service.name appears in [[!BLUETOOTH-ASSIGNED-SERVICES]], let alias be its assigned number, and return BluetoothUUID.canonicalUUID(alias).
  4. Otherwise, throw a SyntaxError.

BluetoothCharacteristicUUID represents 16- and 32-bit UUID aliases, valid UUIDs, and names defined in [[BLUETOOTH-ASSIGNED-CHARACTERISTICS]], or, equivalently, the values for which BluetoothUUID.getCharacteristic does not throw an exception.

The static BluetoothUUID.getCharacteristic(name) method, when invoked, MUST run the following steps:

  1. If name is an unsigned long, return BluetoothUUID.canonicalUUID(name) and abort these steps.
  2. If name is a valid UUID, return name and abort these steps.
  3. If org.bluetooth.characteristic.name appears in [[!BLUETOOTH-ASSIGNED-CHARACTERISTICS]], let alias be its assigned number, and return BluetoothUUID.canonicalUUID(alias).
  4. Otherwise, throw a SyntaxError.

BluetoothDescriptorUUID represents 16- and 32-bit UUID aliases, valid UUIDs, and names defined in [[BLUETOOTH-ASSIGNED-DESCRIPTORS]], or, equivalently, the values for which BluetoothUUID.getDescriptor does not throw an exception.

The static BluetoothUUID.getDescriptor(name) method, when invoked, MUST run the following steps:

  1. If name is an unsigned long, return BluetoothUUID.canonicalUUID(name) and abort these steps.
  2. If name is a valid UUID, return name and abort these steps.
  3. If org.bluetooth.descriptor.name appears in [[!BLUETOOTH-ASSIGNED-DESCRIPTORS]], let alias be its assigned number, and return BluetoothUUID.canonicalUUID(alias).
  4. Otherwise, throw a SyntaxError.

The GATT Blacklist

This specification relies on a blacklist file in the https://github.com/WebBluetoothCG/registries repository to restrict the set of GATT attributes a website can access.

The result of parsing the blacklist at a URL url is a map from valid UUIDs to tokens, or an error, produced by the following algorithm:

  1. Fetch url, and let contents be its body, decoded as UTF-8.
  2. Let lines be contents split on '\n'.
  3. Let result be an empty map.
  4. For each line in lines, do the following sub-steps:
    1. If line is empty or its first character is '#', continue to the next line.
    2. If line consists of just a valid UUID, let uuid be that UUID and let token be "exclude".
    3. If line consists of a valid UUID, a space (U+0020), and one of the tokens "exclude-reads" or "exclude-writes", let uuid be that UUID and let token be that token.
    4. Otherwise, return an error and abort these steps.
    5. If uuid is already in result, return an error and abort these steps.
    6. Add a mapping in result from uuid to token.
  5. Return result.

The GATT blacklist is the result of parsing the blacklist at https://github.com/WebBluetoothCG/registries/blob/master/gatt_blacklist.txt. The UA should re-fetch the blacklist periodically, but it's unspecified how often.

A UUID is blacklisted if either the GATT blacklist's value is an error, or the UUID maps to "exclude" in the GATT blacklist.

A UUID is blacklisted for reads if either the GATT blacklist's value is an error, or the UUID maps to either "exclude" or "exclude-reads" in the GATT blacklist.

A UUID is blacklisted for writes if either the GATT blacklist's value is an error, or the UUID maps to either "exclude" or "exclude-writes" in the GATT blacklist.

Extensions to the Navigator Interface

        partial interface Navigator {
          readonly attribute Bluetooth bluetooth;
        };
      

Terminology and Conventions

This specification uses a few conventions and several terms from other specifications. This section lists those and links to their primary definitions.

Inspired by the Streams specification, we use the notation x@[[\y]] to refer to internal slots of an object, instead of saying "the [[\y]] internal slot of x."

When an algorithm in this specification uses a name defined in this or another specification, the name MUST resolve to its initial value, ignoring any changes that have been made to the name in the current execution environment. For example, when the requestDevice algorithm says to call Array.prototype.map.call(filter.services, BluetoothUUID.getService), this MUST apply the Array.prototype.map algorithm defined in [[ECMAScript]] with filter.services as its this parameter and the algorithm defined in for BluetoothUUID.getService as its callbackfn parameter, regardless of any modifications that have been made to window, Array, Array.prototype, Array.prototype.map, Function, Function.prototype, BluetoothUUID, BluetoothUUID.getService, or other objects.

This specification uses a few read-only types that are similar to WebIDL's read only Array.

[[!BLUETOOTH42]]
  1. Architecture & Terminology Overview
    1. Architecture
      1. Communication Topology and Operation
        1. Operational Procedures and Modes
          1. BR/EDR Procedures
            1. Inquiry (Discovering) Procedure
              1. Extended Inquiry Response
  2. Core System Package [BR/EDR Controller volume]
    1. Host Controller Interface Functional Specification
      1. HCI Commands and Events
        1. Informational Parameters
          1. Read BD_ADDR Command
        2. Status Parameters
          1. Read RSSI Command
  3. Core System Package [Host volume]
    1. Service Discovery Protocol (SDP) Specification
      1. Overview
        1. Searching for Services
          1. UUID (defines UUID aliases and the algorithm to compute the 128-bit UUID represented by a UUID alias)
    2. Generic Access Profile
      1. Profile Overview
        1. Profile Roles
          1. Roles when Operating over an LE Physical Transport
            1. Broadcaster Role
            2. Observer Role
            3. Peripheral Role
            4. Central Role
      2. User Interface Aspects
        1. Representation of Bluetooth Parameters
          1. Bluetooth Device Name (the user-friendly name)
          2. Class of Device
      3. Idle Mode Procedures — BR/EDR Physical Transport
        1. Device Discovery
      4. Operational Modes and Procedures — LE Physical Transport
        1. Broadcast Mode and Observation Procedure
          1. Observation Procedure
        2. Discovery Modes and Procedures
          1. General Discovery Procedure
          2. Name Discovery Procedure
        3. Connection Modes and Procedures
        4. Bonding Modes and Procedures
          1. Bonding Procedure
      5. Security Aspects — LE Physical Transport
        1. Privacy Feature
        2. Random Device Address
          1. Static Address
          2. Private address
            1. Resolvable Private Address Resolution Procedure
      6. Advertising Data and Scan Response Data Format
      7. Bluetooth Device Requirements
        1. Bluetooth Device Address (defines BD_ADDR)
          1. Bluetooth Device Address Types
            1. Public Bluetooth Address
    3. Attribute Protocol (ATT)
      1. Protocol Requirements
        1. Basic Concepts
          1. Attribute Type
          2. Attribute Handle
          3. Long Attribute Values
        2. Attribute Protocol Pdus
          1. Error Handling
            1. Error Response
    4. Generic Attribute Profile (GATT)
      1. Profile Overview
        1. Configurations and Roles (defines GATT Client and GATT Server)
        2. Profile Fundamentals, defines the ATT Bearer
        3. Attribute Protocol
          1. Attribute Caching
        4. GATT Profile Hierarchy
          1. Service
          2. Included Services
          3. Characteristic
      2. Service Interoperability Requirements
        1. Characteristic Definition
          1. Characteristic Declaration
            1. Characteristic Properties
          2. Characteristic Descriptor Declarations
            1. Characteristic Extended Properties
            2. Client Characteristic Configuration
      3. GATT Feature Requirements — defines the GATT procedures.
        1. Primary Service Discovery
          1. Discover All Primary Services
          2. Discover Primary Service by Service UUID
        2. Relationship Discovery
          1. Find Included Services
        3. Characteristic Discovery
          1. Discover All Characteristics of a Service
          2. Discover Characteristics by UUID
        4. Characteristic Descriptor Discovery
          1. Discover All Characteristic Descriptors
        5. Characteristic Value Read
        6. Characteristic Value Write
        7. Characteristic Value Notification
        8. Characteristic Value Indications
        9. Characteristic Descriptors
            Read Characteristic Descriptors
            Read Long Characteristic Descriptors
            Write Characteristic Descriptors
            Write Long Characteristic Descriptors
        10. Procedure Timeouts
      4. GAP Interoperability Requirements
        1. BR/EDR GAP Interoperability Requirements
          1. Connection Establishment
        2. LE GAP Interoperability Requirements
          1. Connection Establishment
      5. Defined Generic Attribute Profile Service
        1. Service Changed
    5. Security Manager Specification
      1. Security Manager
        1. Security in Bluetooth Low Energy
          1. Definition of Keys and Values, defines the Identity Resolving Key (IRK)
  4. Core System Package [Low Energy Controller volume]
    1. Link Layer Specification
      1. General Description
        1. Device Address
          1. Public Device Address
          2. Random Device Address
            1. Static Device Address
      2. Air Interface Protocol
        1. Non-Connected States
          1. Scanning State
            1. Passive Scanning
[[!BLUETOOTH-ASSIGNED]]
[[!BLUETOOTH-SUPPLEMENT5]]
  1. Data Types Specification
    1. Data Types Definitions and Formats
      1. Service UUID Data Type
      2. Local Name Data Type
      3. Flags Data Type
      4. Manufacturer Specific Data
      5. TX Power Level
      6. Service Data
      7. Appearance
[[!dom]]
[[!ECMAScript]]
[[!HTML]]
[[!powerful-features]]
[[!WebIDL]]
Writing Promise-Using Specifications