Web Bluetooth API for BLE Device Integration in Your Website

Typical scenario: you have a BLE device—a heart rate monitor, smart lamp, or industrial sensor. The manufacturer only provides a mobile app. You want users to control the device directly from your website without installing any software. Web Bluetooth API solves this, but requires careful protocol h

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1414
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    982
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    995

Typical scenario: you have a BLE device—a heart rate monitor, smart lamp, or industrial sensor. The manufacturer only provides a mobile app. You want users to control the device directly from your website without installing any software. Web Bluetooth API solves this, but requires careful protocol handling, reconnection logic, and error management. Over 5 years, we have completed more than 20 BLE integrations, from fitness bands to medical monitors. By using the browser, you can save up to 70% on mobile app development and reduce time to market by a factor of three. Typical integration costs $500–$2,000, saving thousands compared to native development. Want to connect a BLE device to your site? We can assess your project in one day—just reach out to us.

Which BLE Devices Can You Connect to a Website?

We connect to heart rate monitors, thermometers, lamps, controllers—any device with Bluetooth Low Energy. The user opens a page, clicks "Connect," selects a device from the list, and the site starts reading sensor data, changing brightness, or turning on a motor. The key is understanding GATT services and characteristics. If documentation exists, integration takes days. If not, we reverse engineer the protocol using a sniffer.

Why Web Bluetooth API Is an Alternative to a Mobile App

Browser-based implementation is three times faster than native development and requires no app store publication. The user doesn't download an app—they simply follow a link. Updates apply instantly on the server, with no versioning. For businesses, this lowers the entry barrier and saves up to 70% on maintaining two platforms.

How to Ensure Stable Connection After a Disconnect

This is critical for devices that need a continuous data stream. We implement automatic reconnection with exponential backoff: first attempt after 1 second, second after 2, third after 4. After three failures, we show a notification. Below is example code in TypeScript.

Connecting to a Device

interface BluetoothDevice { name: string gatt: BluetoothRemoteGATTServer } async function connectToDevice(serviceUUID: string): Promise<BluetoothRemoteGATTServer> { const device = await navigator.bluetooth.requestDevice({ filters: [{ services: [serviceUUID] }], }) console.log(`Connecting to: ${device.name}`) device.addEventListener('gattserverdisconnected', () => { console.log('Device disconnected') }) const server = await device.gatt!.connect() return server } 

Reading Data: Heart Rate Monitor

class HeartRateMonitor { private server: BluetoothRemoteGATTServer | null = null private characteristic: BluetoothRemoteGATTCharacteristic | null = null async connect() { this.server = await connectToDevice('heart_rate') const service = await this.server.getPrimaryService('heart_rate') this.characteristic = await service.getCharacteristic('heart_rate_measurement') await this.characteristic.startNotifications() this.characteristic.addEventListener( 'characteristicvaluechanged', this.handleHeartRateMeasurement.bind(this) ) } private handleHeartRateMeasurement(event: Event) { const value = (event.target as BluetoothRemoteGATTCharacteristic).value! const flags = value.getUint8(0) let heartRate: number if (flags & 0x01) { heartRate = value.getUint16(1, true) } else { heartRate = value.getUint8(1) } const rrIntervals: number[] = [] if (flags & 0x10) { for (let i = 2; i + 1 < value.byteLength; i += 2) { rrIntervals.push(value.getUint16(i, true) / 1024 * 1000) } } console.log(`Heart rate: ${heartRate} bpm, RR: [${rrIntervals.join(', ')}] ms`) } async disconnect() { await this.characteristic?.stopNotifications() this.server?.disconnect() } } 

Writing Data: Controlling a Smart Lamp

class SmartLightController { private server: BluetoothRemoteGATTServer | null = null private controlChar: BluetoothRemoteGATTCharacteristic | null = null private readonly SERVICE_UUID = '00010203-0405-0607-0809-0a0b0c0d1910' private readonly CONTROL_UUID = '00010203-0405-0607-0809-0a0b0c0d2b11' async connect() { this.server = await connectToDevice(this.SERVICE_UUID) const service = await this.server.getPrimaryService(this.SERVICE_UUID) this.controlChar = await service.getCharacteristic(this.CONTROL_UUID) } async setColor(r: number, g: number, b: number) { const command = new Uint8Array([ 0x33, 0x05, 0x02, r, g, b, 0x00, 0x00, 0x00, r ^ g ^ b, ]) await this.controlChar!.writeValueWithResponse(command) } async setBrightness(level: number) { const command = new Uint8Array([ 0x33, 0x04, Math.round(level * 2.55), 0x00, ]) await this.controlChar!.writeValueWithoutResponse(command) } async readBatteryLevel(): Promise<number> { const service = await this.server!.getPrimaryService('battery_service') const char = await service.getCharacteristic('battery_level') const value = await char.readValue() return value.getUint8(0) } } 

React Hook for Managing Connections

function useBluetooth() { const [device, setDevice] = useState<BluetoothRemoteGATTServer | null>(null) const [isConnected, setIsConnected] = useState(false) const [isSupported] = useState(() => 'bluetooth' in navigator) const [error, setError] = useState<string | null>(null) const connect = useCallback(async (serviceUUID: string) => { try { setError(null) const server = await connectToDevice(serviceUUID) setDevice(server) setIsConnected(true) } catch (err) { if ((err as Error).name === 'NotFoundError') { setError('No device selected') } else { setError((err as Error).message) } } }, []) const disconnect = useCallback(() => { device?.disconnect() setDevice(null) setIsConnected(false) }, [device]) return { device, isConnected, isSupported, error, connect, disconnect } } 

Reconnection After Disconnect

device.addEventListener('gattserverdisconnected', async () => { let retries = 0 while (retries < 3) { await new Promise((r) => setTimeout(r, 1000 * (retries + 1))) try { await device.gatt!.connect() await resubscribeCharacteristics() console.log('Reconnected') return } catch { retries++ } } console.error('Failed to reconnect') }) 

Real-World Case: Fitness Platform Integration

In one project for a fitness tracking startup, we integrated a BLE heart rate monitor that transmitted data every second. The original implementation had a 4-second delay due to inefficient GATT service discovery. By caching service handles and optimizing characteristic notification subscriptions, we reduced the initial connection time to 0.5 seconds and eliminated data lag. The platform now supports real-time heart rate display with automatic reconnection, serving over 10,000 daily active users.

Comparison: Web Bluetooth API vs Native App

Criteria Web Bluetooth API Native App
Development time 1–2 weeks 2–3 months
Delivery Link App stores
Updates Instant Manual, via store
Platforms Chrome/Edge iOS, Android
Complexity Medium High
Cost From $500 From $5,000

Typical Mistakes in BLE Integration

Device not appearing during scanning. Ensure your site is served over HTTPS and request Bluetooth permission. Often the cause is missing optionalServices. Connection drops when going into background. Use navigator.wakeLock or implement automatic reconnection. Incorrect data parsing. Check bit flags and endianness (little-endian).

Which Browsers Support Web Bluetooth?

Currently, the API works in Chrome 70+, Edge 79+, and Chrome Android. Firefox and Safari do not support it. If your audience uses those browsers, we can suggest workarounds: Native Messaging, PWA with Service Worker, or a hybrid app. For most B2B scenarios, Chrome is the standard choice.

Work Plan and Timeline

Phase Duration
Document analysis and reverse engineering 1–3 days
Architecture and UI design 1–2 days
Implementation of connections and error handling 2–4 days
Testing on real device 1–2 days
Deployment and monitoring 0.5–1 day

Integration with a documented device: 3–5 days. For undocumented devices (protocol reverse engineering): 7–12 days. Cost ranges from $500 to $2,000 depending on complexity and UI needs. We can assess your project within one business day—just contact us. Get a consultation on BLE integration today.

What’s Included

  • Full documentation of the protocol and integration code.
  • Access to a repository with source code and deployment instructions.
  • Training for your team on how to maintain and extend the integration.
  • 30-day post-launch support (bug fixes, consultations).
  • Guaranteed uptime with automatic reconnection.
  • Certified engineers with 5+ years of BLE experience.

With 5+ years of BLE experience and 20+ successful integrations, our team delivers reliable solutions.

Step-by-Step Guide

  1. Check browser support: if ('bluetooth' in navigator).
  2. Request the device: navigator.bluetooth.requestDevice({ filters: [...] }).
  3. Connect to the GATT server: device.gatt.connect().
  4. Get the desired service and characteristic.
  5. Start reading or writing data.
  6. Handle disconnection: subscribe to the gattserverdisconnected event.
What are GATT services and characteristics? GATT (Generic Attribute Profile) is a protocol that defines the data structure of a BLE device. A service is a group of characteristics (e.g., "Battery" service). A characteristic is a specific parameter (e.g., battery level). Each service and characteristic has a unique UUID.

More about the technology: official documentation and Wikipedia article.