> For the complete documentation index, see [llms.txt](https://docs.thryve.health/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.thryve.health/integrate-your-mobile-app/real-time-bluetooth-device-data.md).

# Real-time bluetooth device data

Access real-time data on your device using Thryve SDK. Users simply connect their BLE device with Bluetooth broadcasting capabilities. Once connected, the data flows instantly to your mobile application, provided the connection is active.&#x20;

Enhance your health or fitness application with easy access to real-time data using the Thryve SDK. Users can effortlessly connect their devices that support Bluetooth broadcasting and your application will have real-time data available, provided the connection is active.&#x20;

Use the real-time heart rate and other data types availability via Thryve to build experiences for fitness enthusiasts to optimize their workouts using instantaneous heart rate feedback or allow for real-time heart rate monitoring in medical use-cases for improved care journeys.&#x20;

<details>

<summary>Verified Devices with real-time BLE broadcasting capabilities</summary>

Correct functionality has been verified for the following devices:

* Coros Heart Rate Monitor
* Garmin HRM-Dual
* Polar H7 Heart Rate Sensor
* Polar H9 Heart Rate Sensor
* Polar H10 Heart Rate Sensor
* Suunto Smart Heart Rate Belt
* Whoop 4.0 (requires [enabled Heart Rate Broadcast](https://support.whoop.com/s/article/Heart-Rate-Broadcast?language=en_US))
* Whoop 5.0 (requires [enabled Heart Rate Broadcast](https://support.whoop.com/s/article/Heart-Rate-Broadcast?language=en_US))
* [Garmin Companion Devices](https://developer.garmin.com/health-sdk/overview/)

</details>

## Connect BLE Device

Please refer to the [direct bluetooth device connection](/integrate-your-mobile-app/direct-bluetooth-device-connection.md) documentation for information on how to connect a BLE device.

## Access real-time data

Capture live data via the `onDeviceReadingReceived` event in `ThryveDeviceEventListener`. This event provides immediate access to data from connected heart rate monitors and garmin devices.

{% tabs %}
{% tab title="iOS" %}

<pre class="language-swift"><code class="lang-swift"><strong>import ThryveCore
</strong>import ThryveCommons
import ThryveBLE

class BLEViewModel: ObservableObject, ThryvDeviceEventListener {
---    
    //onDeviceReadingReceived method is a ThryveDeviceEventListener event listener callback.
    //It is automatically triggered by ThryveSDK each time a ThryveDevice is connected 
    //The data recorded by BLE device is shared with the host application 
    func onDeviceReadingReceived(device: ThryveDevice, dataType: any ThryveDataType, response: ThryveResponse&#x3C;ThryveDeviceReading>) {
        guard let reading = response.data else {
            if let error = response.errors?.first {
               // Process all [ThryveErrors] in response.errors
            }
            return
        }
        let isGarmin = device.source == .garminCompanion
        Task { @MainActor in
            if isGarmin {
                switch reading.item {
                case .heartRate(let hr):         self.garminLatestHR = hr.beatsPerMinute
                case .spo2(let s):               self.garminLatestSpO2 = s.spo2Reading.map { Double($0) }
                case .beatToBeatInterval(let b): self.garminLatestBBI = b.bbi
                case .respiration(let r):        self.garminLatestRespiration = r.breathsPerMinute
                case .stress(let s):             self.garminLatestStress = s.stressScore
                case .steps(let s):              self.garminLatestSteps = s.steps
                case .calories(let c):           self.garminLatestCalories = c.activeCalories ?? c.totalCalories
                case .floorsClimbed(let f):      self.garminLatestFloors = f.floorsClimbed
                case .bodyBattery(let b):        self.garminLatestBodyBattery = b.bodyBatteryLevel
                case .intensityMinutes(let i):   self.garminLatestIntensityMinutes = i.dailyIntensityMinutes
                case .bloodGlucose:              break
                @unknown default:
                    break
                }
            } else {
                switch reading.item {
                case .heartRate(let hr):
                    self.bleLatestHR = hr.beatsPerMinute
                case .bloodGlucose(let g):
                    self.bleLatestGlucose = String(format: "%.1f %@", g.value, g.unit)
                default:
                    break
                }
            }
        }
    }
---
}
</code></pre>

{% endtab %}

{% tab title="Android" %}

```kotlin
package com.thryve.sample.thryvedevice

import androidx.lifecycle.ViewModel
import com.thryve.sdk.model.ThryveDataType
import com.thryve.sdk.model.ThryveResponse
import com.thryve.sdk.model.device.ThryveDevice
import com.thryve.sdk.model.device.ThryveDeviceEventListener
import com.thryve.sdk.model.device.ThryveDeviceReading
import com.thryve.sdk.network.Source

class ThryveDeviceViewModel : ViewModel(), ThryveDeviceEventListener {
    ------
    // Called whenever ThryveSDK receives a new reading from a connected ThryveDevice.
    override fun onDeviceReadingReceived(
        device: ThryveDevice,
        dataType: ThryveDataType,
        response: ThryveResponse<ThryveDeviceReading>,
    ) {
        val reading = response.data ?: run {
            response.errors.forEach { error ->
                // Process ThryveError.
            }
            return
        }

        when (device.source) {
            Source.GARMIN_COMPANION -> when (reading.item) {
                is ThryveDeviceReading.Item.ThryveHeartRateItem -> { /* Process heart rate */ }
                is ThryveDeviceReading.Item.ThryveSpO2Item -> { /* Process SpO2 */ }
                is ThryveDeviceReading.Item.ThryveBBIItem -> { /* Process BBI */ }
                is ThryveDeviceReading.Item.Respiration -> { /* Process respiration */ }
                is ThryveDeviceReading.Item.ThryveStressItem -> { /* Process stress */ }
                is ThryveDeviceReading.Item.ThryveStepsItem -> { /* Process steps */ }
                is ThryveDeviceReading.Item.ThryveCaloriesItem -> { /* Process calories */ }
                is ThryveDeviceReading.Item.ThryveFloorsItem -> { /* Process floors climbed */ }
                is ThryveDeviceReading.Item.ThryveBodyBatteryItem -> { /* Process body battery */ }
                is ThryveDeviceReading.Item.ThryveIntensityMinutesItem -> { /* Process intensity minutes */ }
                else -> Unit
            }

            Source.THRYVE_BLUETOOTH -> when (reading.item) {
                is ThryveDeviceReading.Item.ThryveHeartRateItem -> { /* Process heart rate */ }
                else -> Unit
            }

            else -> Unit
        }
    }
    --------
}

```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Data of connected devices is periodically uploaded to the Thryve backend in batches, rather than in real-time. This approach ensures persistent data storage while minimizing network and battery usage on devices.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.thryve.health/integrate-your-mobile-app/real-time-bluetooth-device-data.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
