# Apple Health, Health Connect & Samsung Health

Once a user connects Apple Health, Health Connect, or Samsung Health, the Thryve SDK can retrieve and sync data from these native sources either automatically or manually.&#x20;

We generally recommend manually synchronizing connected native data sources whenever your app comes to the foreground to ensure all data is up-to-date, as automatic background data synchronization is highly dependent on the operating system and its resource and battery management, allowing for regular synchronizations.

{% hint style="info" %}
Web data sources are seamlessly managed by the Thryve backend. This page is only related to data sources where health data is directly retrieved from the end user device via the Thryve SDK.
{% endhint %}

## SDK Module Configuration

When using Apple Health, Health Connect & Samsung Health, you will need the optional SDK modules Apple Health, Health Connect or Samsung Health. Make sure to initialize the corresponding configurations `ThryveAppleHealthConfig`, `ThryveHealthConnectConfig` and `ThryveSamsungHealthConfig` for correct functionality.&#x20;

<table><thead><tr><th width="99.609375">Parameter</th><th width="547.76953125">Description</th><th width="100.421875">Mandatory</th></tr></thead><tbody><tr><td><code>configs</code></td><td>List of  <code>ThryveSDKModulesConfig</code> for imported SDK modules.</td><td>yes</td></tr></tbody></table>

{% tabs %}
{% tab title="Apple Health" %}
When using the Apple Health module, make sure to define the data types in the `ThryveAppleHealthConfig` . *This* is *only relevant for iOS integration.*

<table><thead><tr><th width="198.4617919921875">Parameter</th><th width="458.33642578125">Description</th><th width="99.81640625">Mandatory</th></tr></thead><tbody><tr><td><code>dataTypes</code></td><td>The Apple Health data types <code>Set&#x3C;ThryveAppleHealthDataType></code> required by your app. Ensure to <a data-footnote-ref href="#user-content-fn-1">limit types to data described in your data privacy policy</a>. Always ensure the configured <code>dataTypes</code> are consistent across your application. Please refer to this document to understand the data types.</td><td>yes</td></tr><tr><td><code>enableBackgroundSync</code></td><td><p>Configures background data synchronization on SDK initialization (retrieving data when your app is closed or idle). <br><br>Default state is <code>true</code> which requires <a href="/pages/mF5OcudXCdbsedmKWCl9">Background Delivery</a> to be enabled for a <strong>HealthKit Capability.</strong></p><p></p><p>Alternatively, <a href="/pages/WJgf11wpT55T53iDeyFx#automatic-background-data-synchronization">use the <code>executeBackgroundSync</code> method</a> in <code>AppDelegate</code>        </p></td><td>no</td></tr></tbody></table>
{% endtab %}

{% tab title="Health Connect" %}
When using the Health Connect module, make sure to define the data types in the `ThryveHealthConnectConnectorConfig` . *This* is *only relevant for Android integration*

<table><thead><tr><th width="169.7265625">Parameter</th><th width="342.26171875">Description</th><th>Mandatory</th></tr></thead><tbody><tr><td><code>dataTypes</code></td><td>Health Connect data types required by your app. Ensure to <a data-footnote-ref href="#user-content-fn-2">limit types to data described in your data privacy policy</a>. Always ensure the configured <code>dataTypes</code> are consistent across your application. Please refer to this document to understand the data types.</td><td>no, defaults to all supported data types</td></tr><tr><td><code>enableBackgroundSync</code></td><td>Will request background data sync permissions. If permissions are granted, <a href="https://developer.android.com/develop/background-work/background-tasks">background tasks</a> using WorkManager will be scheduled by the Thryve SDK.</td><td>no, defaults to <code>true</code></td></tr><tr><td><code>enableReadHealthDataHistory</code></td><td>Will request historical data sync permissions. If permissions are granted, timeframes older than 30 days can be requested when using manual data synchronization methods.</td><td>no, defaults to <code>true</code></td></tr></tbody></table>
{% endtab %}

{% tab title="Samsung Health" %}
When using the Samsung Health module, make sure to define the data types in the `ThryveSamsungHealthConfig` . *This* is *only relevant for Android integration*

<table><thead><tr><th width="169.7265625">Parameter</th><th width="342.26171875">Description</th><th>Mandatory</th></tr></thead><tbody><tr><td><code>dataTypes</code></td><td>The Samsung Health data types required by your app. Please refer to <a href="https://docs.thryve.health/thryve-product-overview/access/data-types-biomarker">this document</a> to understand the data types. Ensure to <a data-footnote-ref href="#user-content-fn-2">limit types to data described in your data privacy policy</a>. Always ensure the configured <code>dataTypes</code> are consistent across your application.</td><td>no, defaults to all supported data types</td></tr><tr><td><code>enableBackgroundSync</code></td><td>Schedules <a href="https://developer.android.com/develop/background-work/background-tasks">background tasks</a> using WorkManager for data synchronization when app is closed or idle.</td><td>no, defaults to <code>true</code></td></tr></tbody></table>
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Please ensure you have set-up your [iOS](/integrate-your-mobile-app/setup-thryve-sdk/ios.md) and [Android](/integrate-your-mobile-app/setup-thryve-sdk/android.md) project with correct configuration for Apple HealthKit, .
{% endhint %}

## Automatic Background Data Synchronization

We utilize different technologies for automatic background data retrieval on iOS and Android. On iOS, the Thryve SDK employs HealthKit’s native background synchronization API. For Android, synchronization is scheduled and managed via [WorkManager](https://developer.android.com/develop/background-work/background-tasks/persistent).&#x20;

The availability of background data synchronizations is configurable for both Apple Health and Health Connect data sources in the corresponding config objects. Samsung Health automatically synchronizes data in the background once the user successfully connects.

{% tabs %}
{% tab title="Apple Health" %}
To enable background data synchronization (retrieving data when your app is closed or idle), use the `executeBackgroundSync` method within the `didFinishLaunchingWithOptions` function in `AppDelegate` right after connecting to Apple Health.&#x20;

Apple mandates that this logic runs within the first few seconds of app startup for data delivery, hence its placement in `AppDelegate`. Refer to the sample code for further details.

```swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // When Apple's Health app initiates contact, it triggers your application 
        // via didFinishLaunchingWithOptions. Once activated, HealthKit waits 
        // briefly to determine if your app wishes to renew its query contracts. 
        // Calling the relevant method as early as possible renews these contracts, 
        // enabling the app to fetch new data promptly from Apple Health.
        ThryveSDK.get().executeBackgroundSync(
                  dataSource: .apple,
                  dataTypes: ThryveAppleHealthDataType.allTypes)
        // Override point for customization after application launch.
        return true
    }
```

{% hint style="danger" %}
Ensure your project is configured correctly and `Background Delivery` is enabled in your apps HealthKit Capabilities as [documented](https://docs.thryve.health/integrate-your-mobile-app/pages/hnewAJjjtf5jP9Ks2p3L#add-healthkit-to-project-and-configure-info.plist).
{% endhint %}
{% endtab %}

{% tab title="Health Connect" %}
To enable background data synchronization (retrieving data when your app is closed or idle) in native Android, using Kotlin, enable background sync in the `ThryveHealthConnectConfig` .

```javascript
val healthConnectConfig = ThryveHealthConnectConfig(
        dataTypes = ThryveHealthConnectDataType.entries.toList(),
        enableBackgroundSync = true,
        enableReadHealthDataHistory = true
    ) 
```

{% hint style="danger" %}
Background sync will only execute if the user has granted corresponding Health Connect permission.
{% endhint %}
{% endtab %}

{% tab title="Samsung Health" %}
When connected to Samsung Health, background data retrieval and synchronization are automatically enabled. No actions required by developers.
{% endtab %}

{% tab title="React Native (All Sources)" %}
In React Native, using javascript or Typescript, enable  enableBackgroundSync[^3] sync  in your configuration

<pre class="language-javascript"><code class="lang-javascript">const thryveSDKConfig = {
    authId: appId,
    authSecret: appSecret,
    endUserAlias: "YOUR_UNIQUE_USER_IDENTIFIER",
    locale: 'en',
    config: [
      {
        source: Source.APPLE,
        dataTypes: appleHealthDataTypes,
      },
      {
        source: Source.HEALTH_CONNECT,
        dataTypes: healthConnectDataTypes,
        <a data-footnote-ref href="#user-content-fn-3">enableBackgroundSync</a>: true,
        enableReadHealthDataHistory: true,
      },
      {
        source: Source.SAMSUNG,
        dataTypes: samsungHealthDataTypes,
      },
      {
        source: Source.SHENAI,
        apiKey: "SHEN_AI_API_KEY",
      },
    ],
  };
  thryveSDK.getOrCreate(thryveSDKConfig);
   
</code></pre>

{% endtab %}

{% tab title="Flutter(All Sources)" %}
The background data sychronization in the Flutter SDK is enabled in the ThryveSDKConfig durint initialization. Check the [Flutter SDK initialization section](/integrate-your-mobile-app/connect-data-sources.md#flutter)
{% endtab %}
{% endtabs %}

## Manual Data Synchronization

Manual data synchronization is recommended to ensure all recent data is available when the user opens your app. Therefore, we recommend using `synchronize`  whenever your app moves to the foreground.

`synchronize` will ensure that both epoch and daily data added since the last data synchronization will be fetched from Apple Health, Health Connect, or Samsung Health. The initial execution of `synchronize` will fetch all data for today.

{% tabs %}
{% tab title="Apple Health" %}

<pre class="language-swift"><code class="lang-swift">import ThryveCore
import ThryveAppleHealth

<strong>// synchronous function
</strong>func synchronize() {
  ThryveSDK.get().synchronize(
    dataSource: .apple,
    dataTypes: ThryveAppleHealthDataType.allTypes
  ) { (thryveResponse) in
    guard thryveResponse.successful else {
      thryveResponse.errors?.forEach { error in
        //synchronize failed process errors
        Logger.e { error }
      }
      return
    }
    //synchronize was successful
  }
}
    
// asynchronous function
func synchronize() {
  Task {
    let thryveResponse = await ThryveSDK.get().synchronize(
      dataSource: .apple,
      dataTypes: ThryveAppleHealthDataType.allTypes)
    guard thryveResponse.successful else {
      thryveResponse.errors?.forEach { error in
        //synchronize failed process errors
        Logger.e { error }
      }
      return
    }
    //synchronize was successful
  }
}
</code></pre>

{% endtab %}

{% tab title="Health Connect" %}

```kotlin
ThryveSDK.get().synchronize(dataSource = Source.HEALTH_CONNECT) { thryveResponse ->
    if (thryveResponse.successful) {
        // synchronization was successful
    } else {
        thryveResponse.errors.map { error -> // synchronization failed, process errors }
        }
    }
}
```

{% endtab %}

{% tab title="Samsung Health" %}

```kotlin
ThryveSDK.get().synchronize(dataSource = Source.SAMSUNG) { thryveResponse ->
    if (thryveResponse.successful) {
        // synchronization was successful
    } else {
        thryveResponse.errors.map { error -> // synchronization failed, process errors }
        }
    }
}
```

{% endtab %}

{% tab title="React Native (All Sources)" %}

```javascript
import { 
Source,
ThryveSamsungHealthDataType,
ThryveHealthConnectDataType,
ThryveAppleHealthDataType,
ThryveSDK 
} from '@thryve/react-native-sdk';

//Synchronize Apple Health data
export async function synchronize() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const allAppleHealthDataTypes = Object.values(ThryveAppleHealthDataType);
    const response = await sdk.synchronize(Souce.APPLE, allAppleHealthDataTypes);
    if (response?.data) {
      //synchronize was successfull
    } else {
      //synchronize failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Apple Health synchronize error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }
}

//Synchronize Health Connect data
export async function synchronize() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const allHealthConnectDataTypes = Object.values(ThryveHealthConnectDataType);
    const response = await sdk.synchronize(Souce.HEALTH_CONNECT, allHealthConnectDataTypes);
    if (response?.data) {
      //synchronize was successfull
    } else {
      //synchronize failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Health Connect synchronize error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }
}

//Synchronize Samsung Health data
export async function synchronize() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const allSamsungHealthDataTypes = Object.values(ThryveSamsungHealthDataType);
    const response = await sdk.synchronize(Souce.SAMSUNG, allSamsungHealthDataTypes);
    if (response?.data) {
      //synchronize was successfull
    } else {
      //synchronize failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Samsung Health synchronize error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }
}
```

{% endtab %}

{% tab title="Flutter  (All Sources)" %}

```dart
import 'package:module_apple_health/module_apple_health.dart';
import 'package:thryve_sdk/thryve_sdk.dart';

final class AppleHealthPageBloc {
  final ThryveSDK _thryveSDK;
  final Source _dataSource;
  List<HKConnectorType> _hkConnectorTypes;

  AppleHealthPageBloc(this._thryveSDK, this._hkConnectorTypes) : _dataSource = Source.apple;

  Future<ThryveResponse<void>> synchronize() => _thryveSDK.synchronize(_dataSource.id);

  Future<void> synchronizeAppleHealth() async {
    final ThryveResponse<void> response = await synchronize();

    if (!response.isSuccessful) {
      final Iterable<ThryveError> errors = response.errors.whereType<ThryveError>();

      for (final ThryveError error in errors) {
        //process each error here
      }

      throw StateError('Unable to synchronize all Apple Health data types.');
    }
  }
}

```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
The manual data retrieval methods will return a `ThryveResponse`. This response will be `true` if the data is uploaded successfully. If issues occur during retrieval or upload, the response will be `false`, and a list of `ThryveError` will be provided. Each `ThryveError` contains details about the error encountered.
{% endhint %}

### Historic data backfill

To access data predating the initial synchronization, the Thryve SDK provides methods for backfilling historical data. These methods allow synchronization of epoch and daily data within a specified timeframe.

{% tabs %}
{% tab title="Apple Health" %}

```swift

import ThryveCore
import ThryveAppleHealth

func backfillEpoch() {
  ThryveSDK.get().backfillEpoch(
    dataSource: .apple,
    startDate: from,
    endDate: to,
    dataTypes: ThryveAppleHealthDataType.allTypes
  ) { (thryveResponse) in
    guard thryveResponse.successful else {
      thryveResponse.errors?.forEach { error in
        //synchronize failed process errors
        Logger.e { error }
      }
      return
    }
    //synchronize was successful
  }
}
```

```swift
func backfillDaily() {
  ThryveSDK.get().backfillDaily(
    dataSource: .apple,
    startDate: from,
    endDate: to,
    dataTypes: ThryveAppleHealthDataType.allTypes
  ) { (thryveResponse) in
    guard thryveResponse.successful else {
      thryveResponse.errors?.forEach { error in
        //synchronize failed process errors
        Logger.e { error }
      }
      return
    }
    //synchronize was successful
  }
}

```

{% endtab %}

{% tab title="Health Connect" %}

```kotlin
ThryveSDK.get().backfillEpoch(
    dataSource = Source.HEALTH_CONNECT,
    startDate = Date().daysAgo(30),
    endDate = Date()
) { thryveResponse ->
    if (thryveResponse.successful) {
        // backfill was successful
    } else {
        thryveResponse.errors.map { error -> // backfill failed, process errors }
        }
    }
}
```

```kotlin
ThryveSDK.get().backfillDaily(
    dataSource = Source.HEALTH_CONNECT,
    startDate = Date().daysAgo(30),
    endDate = Date()
) { thryveResponse ->
    if (thryveResponse.successful) {
        // backfill was successful
    } else {
        thryveResponse.errors.map { error -> // backfill failed, process errors }
        }
    }
}
```

{% endtab %}

{% tab title="Samsung  Health" %}

```kotlin
ThryveSDK.get().backfillEpoch(
    dataSource = Source.SAMSUNG,
    startDate = Date().daysAgo(30),
    endDate = Date()
) { thryveResponse ->
    if (thryveResponse.successful) {
        // backfill was successful
    } else {
        thryveResponse.errors.map { error -> // backfill failed, process errors }
        }
    }
}
```

```kotlin
ThryveSDK.get().backfillDaily(
    dataSource = Source.SAMSUNG,
    startDate = Date().daysAgo(30),
    endDate = Date()
) { thryveResponse ->
    if (thryveResponse.successful) {
        // backfill was successful
    } else {
        thryveResponse.errors.map { error -> // backfill failed, process errors }
        }
    }
}
```

{% endtab %}

{% tab title="React Native (All Sources)" %}
{% code overflow="wrap" %}

```javascript
import { 
Source,
ThryveSamsungHealthDataType,
ThryveHealthConnectDataType,
ThryveAppleHealthDataType,
ThryveSDK 
} from '@thryve/react-native-sdk';

//backfillEpoch Apple Health data
export async function backfillEpoch() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const allAppleHealthDataTypes = Object.values(ThryveAppleHealthDataType);
    const response = await sdk.backfillEpoch(Souce.APPLE, startDate, endDate, allAppleHealthDataTypes);
    if (response?.data) {
      //backfillEpoch was successfull
    } else {
      //backfillEpoch failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Apple Health backfillEpoch error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }
}

//backfillDaily Apple Health data
export async function backfillEpoch() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const allAppleHealthDataTypes = Object.values(ThryveAppleHealthDataType);
    const response = await sdk.backfillDaily(Souce.APPLE, startDate, endDate, allAppleHealthDataTypes);
    if (response?.data) {
      //backfillDaily was successfull
    } else {
      //backfillDaily failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Apple Health backfillDaily error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="Flutter (All Sources)" %}

```dart
import 'package:module_apple_health/module_apple_health.dart';
import 'package:thryve_sdk/thryve_sdk.dart';

final class AppleHealthPageBloc {
  final ThryveSDK _thryveSDK;
  final Source _dataSource;
  List<HKConnectorType> _hkConnectorTypes;

  AppleHealthPageBloc(this._thryveSDK, this._hkConnectorTypes) : _dataSource = Source.apple;

  Future<ThryveResponse<void>> backfillEpoch(
    DateTime startDate,
    DateTime endDate,
  ) =>
      _thryveSDK.backfillEpoch(
          _dataSource.id, startDate, endDate, _hkConnectorTypes.map((e) => e.name).toList());

  Future<ThryveResponse<void>> backfillDaily(
    DateTime startDate,
    DateTime endDate,
  ) =>
      _thryveSDK.backfillDaily(
          _dataSource.id, startDate, endDate, _hkConnectorTypes.map((e) => e.name).toList());

  Future<void> backfillEpochAppleHealth(
    DateTime startDate,
    DateTime endDate,
  ) async {
    final ThryveResponse<void> response = await backfillEpoch(startDate, endDate);

    if (!response.isSuccessful) {
      final Iterable<ThryveError> errors = response.errors.whereType<ThryveError>();

      for (final ThryveError error in errors) {
        //process each error here
      }

      throw StateError('Unable to backfill all Apple Health data types.');
    }
  }
  
 Future<void> backfillDailyAppleHealth(
    DateTime startDate,
    DateTime endDate,
  ) async {
    final ThryveResponse<void> response = await backfillDaily(startDate, endDate);

    if (!response.isSuccessful) {
      final Iterable<ThryveError> errors = response.errors.whereType<ThryveError>();

      for (final ThryveError error in errors) {
        //process each error here
      }

      throw StateError('Unable to backfill all Apple Health data types.');
    }
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
`backfillEpoch` fetches epoch data for the given timeframe, with a maximum of 30 days. If the difference between `startDate` and `endDate` is more than 30 days, the SDK will count from the end date 30 days back

`backfillDaily` fetches daily data for the given timeframe, with a maximum of 365 days. If the difference between `startDate` and `endDate` is more than 365 days, the SDK will count from the end date 365 days back
{% endhint %}

<table><thead><tr><th width="156.66796875">Parameter </th><th width="427.1875">Description</th><th>Mandatory</th></tr></thead><tbody><tr><td><code>dataSource</code></td><td>The data source to synchronize data from. iOS defaults to <code>.apple</code></td><td>yes, on Android.<br>no, on iOS</td></tr><tr><td><code>dataTypes</code></td><td>The data types to synchronize. It defaults to the data types defined in the data source config.</td><td>no</td></tr><tr><td><code>startDate</code></td><td>The date to start data retrieval and synchronization from. It is applicable only to the backfiill functions</td><td>yes</td></tr><tr><td><code>endDate</code></td><td>The date to end data retrieval and synchronization on. It defaults to today and applicable only to the backfiill functions. </td><td>no</td></tr></tbody></table>

{% hint style="info" %}
The manual data retrieval methods will return a `ThryveResponse`. This response will be `true` if the data is uploaded successfully. If issues occur during retrieval or upload, the response will be `false`, and a list of `ThryveError` will be provided. Each `ThryveError` contains details about the error encountered.
{% endhint %}

[^1]: The use of data types beyond the means described in your privacy policy may lead to your app being rejected by Apple in the App Store.\
    \
    Ensure to explain why your app needs access to the different types and why this is important for the user experience to avoid rejection.

[^2]: The use of data types beyond the means described in your privacy policy may lead to your app being rejected by Google in the Google Play Store.\
    \
    Ensure to explain why your app needs access to the different types and why this is important for user experience to avoid rejection.

[^3]: set to true to Health Connect background synchronization


---

# Agent Instructions: 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:

```
GET https://docs.thryve.health/integrate-your-mobile-app/apple-health-health-connect-and-samsung-health.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
