> For the complete documentation index, see [llms.txt](https://docs.tryterra.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tryterra.co/mobile-sdks/react-native.md).

# React Native SDK 1.x

Connect Apple Health, Samsung Health and Health Connect users with the terra-react 1.x package: install it, initialise it, connect a user and enable background delivery.

This page shows how to integrate Apple Health, Samsung Health and Health Connect in your React Native app with `terra-react` 1.x. It covers SDK initialization, user connection, background delivery, and reading and writing data.

{% hint style="info" %}
`terra-react` 1.x is no longer the current version. For new apps, use the [React Native SDK](/mobile-sdks/react-native-sdk-2.md) (`@tryterra/react-native` 2.x). To move an existing app, follow [React Native upgrade guide](/mobile-sdks/react-native-migrating-to-2.md).
{% endhint %}

## Install and set up the plugin

1. Install the [`terra-react` package](https://www.npmjs.com/package/terra-react) using npm (`npm install terra-react`).
2. Complete the following iOS and/or Android setup.

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

1. In your terminal, cd to your `/ios` folder, and run `pod install` to install all the dependencies.
2. **Add Capabilities:**
   1. Healthkit > Healthkit Background Delivery
   2. Background Modes > Background processing
   3. Background modes > Background fetch
3. **Add the following keys to your info.plist:**

**Option 1: Use Xcode**

* 1\) Go to the `/ios` directory of your project, open the `.xcworkspace` in XCode.
* 2\) Go to ***info.plist,*** and add the following keys and values:

<table><thead><tr><th width="370.9501953125">Key</th><th>Value</th></tr></thead><tbody><tr><td>Privacy - Health Share Usage Description</td><td><p>Description of how Health data is used</p><p><strong>(Min 3 words)</strong></p></td></tr><tr><td>Privacy - Health Records Usage Description</td><td><p>Description of how Health data is used</p><p><strong>(Min 3 words)</strong></p></td></tr><tr><td>Privacy - Health Update Usage Description</td><td><p>Description of how Health data is used</p><p><strong>(Min 3 words)</strong></p></td></tr><tr><td>Permitted background task scheduler</td><td><code>co.tryterra.data.post.request</code></td></tr></tbody></table>

**Option 2: Edit info.plist directly**

* 1\) In your app project, go to your `/ios` folder
* 2\) Go to ***info.plist,*** and add the following tags:

{% code title="info.plist" lineNumbers="true" %}

```xml
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
  <string>co.tryterra.data.post.request</string>
</array>
  
<key>NSHealthClinicalHealthRecordsShareUsageDescription</key>
<string>Using TerraiOS to gather health data</string>

<key>NSHealthShareUsageDescription</key>
<string>Using TerraiOS as a mean of getting Health Data</string>

<key>NSHealthUpdateUsageDescription</key>
<string>Allow writing data to health kit</string>
```

{% endcode %}
{% endtab %}

{% tab title="Android Setup" %}

#### Access Samsung Health

Terra has a privileged partnership with Samsung that gives you direct access to the Samsung Health SDK, with no Health Connect intermediary. This is the recommended route for Samsung devices.

**1. Apply for Samsung Health access**

Submit your application through the [Samsung Health partnership portal](https://developer.samsung.com/SHealth/business-partner/m48wvqi1mt9w2w4c).

{% hint style="info" %}
While waiting for approval, you can start development immediately using the **Health Connect** route below. Switching to Samsung direct later is a version bump with no code changes.
{% endhint %}

**2. Install the Samsung-tagged SDK**

After approval, install the Samsung-tagged version of the Terra SDK:

* **React Native:** `npm install terra-react@<samsung-version>`. Find Samsung-tagged versions on the [npm versions page](https://www.npmjs.com/package/terra-react?activeTab=versions)
* **Flutter:** Use the Samsung-tagged version of `terra_flutter_bridge`. Find versions on [pub.dev](https://pub.dev/packages/terra_flutter_bridge/versions)

**3. Add the ProGuard rule (required for release builds)**

In your `android/app/proguard-rules.pro`, add:

```proguard
-keep class com.samsung.android.** { *; }
```

Without this, R8 minification will strip Samsung SDK classes and cause runtime crashes in production.

**4. Check the requirements**

* **Samsung Health** app must be installed on the device
* **Android 28 (minSDK 28)** and above
* Enable **Developer Mode** in Samsung Health on test devices (Settings > About Samsung Health > tap version number repeatedly)
* No additional manifest or Gradle changes needed: the Terra SDK handles everything

#### Access Health Connect

**1. Grant permissions in the Health Connect app**

Give all permissions between the apps you wish to read from (e.g. **Samsung Health, Google Fit, etc**) & Health Connect.

**2. Add the Health Connect capability to your app**

In your app project, go to the `/android` folder.

Include the permission tags under the Activity you wish to link the user to when they click the **privacy policy** link in the Health Connect permission screen. Here are the steps:

1. Go to your Android App's `AndroidManifest.xml`
2. Go to your **Privacy Policy** <mark style="color:purple;">`<activity>`</mark> and include the following tags under this <mark style="color:purple;">`<activity>`</mark> tag.

"Your Android manifest needs to have an Activity that displays your app's **privacy policy**, which is your app's rationale of the requested permissions, describing how the user's data is used and handled." (Health Connect)

<pre class="language-xml" data-title="AndroidManifest.xml" data-line-numbers><code class="lang-xml"><strong>&#x3C;intent-filter>
</strong>  &#x3C;action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE"/>
 &#x3C;/intent-filter>
  
&#x3C;intent-filter>
   &#x3C;action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/>
  &#x3C;category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
&#x3C;/intent-filter>
</code></pre>

{% hint style="warning" %}
**Apply for Health Connect access**

Before going **live** (release), you will need to apply for permissions to access the Health Connect API with Google.

1. Use this [application form](https://developer.android.com/health-and-fitness/guides/health-connect/publish/declare-access#explain-use-data-types).
2. For each permission which you are ***not*** using, please add the following lines to your AndroidManifest.xml

{% code title="AndroidManifest.xml" overflow="wrap" %}

```xml
<uses-permission android:name="android.permission.health.READ_HEART_RATE" tools:node="remove"/>
```

{% endcode %}

with `android.permission.health.XXX` for each permission you aren't using
{% endhint %}
{% endtab %}
{% endtabs %}

## Initialize the SDK

The first step is to initialize the Terra SDK.

The initialization only needs to be done once on app start (for example in your `app.tsx` or an equivalent file), and ideally every time the app is brought into the foreground. This ensures that the SDK is properly set up and ready to be used.

{% hint style="warning" %}
The SDK should be initialized every time your app is opened.

This is a necessary prerequisite for other SDK functions to run as expected
{% endhint %}

### Import the Terra plugin

In your project, you should now be able to import function from the Terra Plugin. Here is an example:

{% code title="app.tsx" lineNumbers="true" %}

```tsx
import { initTerra } from 'terra-react';
```

{% endcode %}

### Call `initTerra`

In order to interact with the SDK, you need to call `initTerra` first.

Call `initTerra()` with the following arguments:

* `devId`: Your **Developer ID** provided by Terra.
* `referenceId`: An **ID of your choice** to identify your app user.

Find more details in the SDK Reference: [React Native SDK reference](https://docs.tryterra.co/reference/mobile-sdks/react-native)

{% code title="app.tsx" lineNumbers="true" %}

```typescript
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import { initTerra } from 'terra-react';

const App = () => {
  const [initialized, setInitialized] = useState<boolean>(false);
  
  useEffect(() => {
    const initializeTerra = async () => {
      try {
        const devID = 'YOUR_DEV_ID';
        const referenceId = 'YOUR_REFERENCE_ID';
        
        const successMessage = await initTerra(devID, referenceId);
        if (successMessage.error !== null) {
          throw new Error("Terra manager failed to initialise");
        }
        // Can proceed with other Terra plugin methods
        setInitialized(true);
      } catch (error) {
        console.error('Failed to initialize Terra:', error);
      }
    };

    initializeTerra();
  }, []);

  return (
    <View>
      <Text>Welcome to the App using Terra</Text>
    </View>
  );
};

export default App;
```

{% endcode %}

This call is asynchronous. Make sure it completes before you use other SDK functions.

## Connect a user

Once Terra is initialized, you can create a connection by calling the function `initConnection()` to trigger a permission screen pop up.

### Call `initConnection()`

From `terra-react`, import `initConnection` and call the function with the following arguments:

* `type`: Specify the connection type: `Connections.APPLE_HEALTH`, `Connections.SAMSUNG`, or `Connections.HEALTH_CONNECT`
* `token`: A **one-time authentication token** generated from your backend server. This ensures secure communication between your app and the Terra servers.
* `schedulerOn`:
  * **iOS**: This parameter has no effect. Background delivery is controlled by calling `Terra.setUpBackgroundDelivery()` in your AppDelegate. See [Set up background delivery](#set-up-background-delivery) below.
  * **Android**: Enables background delivery, so Terra keeps syncing while your app is in the background. See [Set up background delivery](#set-up-background-delivery) below.
* `customPermissions`: A **set of permissions** that define what data you want to request (e.g., heart rate, steps). If empty, it defaults to all available permissions. See [Permissions mapping](https://docs.tryterra.co/reference/mobile-sdks/permissions-mapping) for every value and what it requests on each platform.

{% tabs %}
{% tab title="Apple Health (iOS)" %}
{% code title="app.tsx" lineNumbers="true" %}

```tsx
import { Connections, initConnection } from 'terra-react';

const initializeConnection = async () => {
  try {
    const token = 'example_token';

    const successMessage = await initConnection(
      Connections.APPLE_HEALTH,
      token,
      true,   // schedulerOn: no effect on iOS, see setUpBackgroundDelivery() below
      [],     // customPermissions: empty defaults to all
    );
    if (successMessage.error !== null) {
      throw new Error("Error initialising a connection");
    }
  } catch (error) {
    console.error('Connection failed:', error);
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="Samsung Health (Android)" %}
{% code title="app.tsx" lineNumbers="true" %}

```tsx
import { Connections, initConnection } from 'terra-react';

const initializeConnection = async () => {
  try {
    const token = 'example_token';

    const successMessage = await initConnection(
      Connections.SAMSUNG,
      token,
      true,   // schedulerOn: enables background delivery, see Set up background delivery
      [],     // customPermissions: empty defaults to all
    );
    if (successMessage.error !== null) {
      throw new Error("Error initialising a connection");
    }
  } catch (error) {
    console.error('Connection failed:', error);
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="Health Connect (Android)" %}
{% code title="app.tsx" lineNumbers="true" %}

```tsx
import { Connections, initConnection } from 'terra-react';

const initializeConnection = async () => {
  try {
    const token = 'example_token';

    const successMessage = await initConnection(
      Connections.HEALTH_CONNECT,
      token,
      true,   // schedulerOn: enables background delivery, see Set up background delivery
      [],     // customPermissions: empty defaults to all
    );
    if (successMessage.error !== null) {
      throw new Error("Error initialising a connection");
    }
  } catch (error) {
    console.error('Connection failed:', error);
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**Apple Health shows the permission popup once.** Calling `initConnection()` multiple times won’t trigger the popup again unless:

* you call `initConnection` with an expanded set of `customPermissions`
* the app is deleted and reinstalled.
  {% endhint %}

{% hint style="info" %}
**`initConnection` only needs to be called a single time.**

Health Connect prohibits the permission popup to appear more than once for any given permission, so calling `initConnection` more than once will result in no action at all.

The only case where it would re-appear is if:

* you call `initConnection` with an expanded set of `customPermissions`
* the app is deleted and reinstalled
* the app requested a permission that Google did not grant for release
  {% endhint %}

{% hint style="info" %}
**WebView apps.**

* Apple HealthKit implements the permissions popup as a WebView.
* If your app is also based on a WebView, you will need to interrupt your WebView, call `initConnection`, then upon completion re-open your WebView.
  {% endhint %}

#### Generate an auth token

To be able to call the `initConnection()` method, you need to pass a `token` as an argument.

This `token` is a **single-use token** created to ensure the authentication endpoint for creating a connection (and connecting the SDK to Terra's servers) does not get abused.

Generate the token with this endpoint <mark style="color:orange;">`POST`</mark>`https://api.tryterra.co/v2/auth/generateAuthToken` . Make sure to call it with your Terra `x-api-key` and `dev-id` in the headers from **your backend server.** After you generate the token, provide the response to your client side using your own logic.

{% code title="CLI" %}

```bash
curl --request POST \
  --url https://api.tryterra.co/v2/auth/generateAuthToken \
  --header 'dev-id: <YOUR-DEV-ID>' \
  --header 'x-api-key: <YOUR-API-KEY>'
```

{% endcode %}

For every parameter, see the [`/auth/generateAuthToken` endpoint](https://docs.tryterra.co/reference/health-and-fitness-api/authentication#post-auth-generateauthtoken) in the API reference.

{% hint style="warning" %}

* During the development phase, it it acceptable to place this call on the **client** side, exposing your API key in your mobile app.
* For a production implementation, **DO NOT** expose your API key this way, and make sure to **only** make this call from your **backend.**
  {% endhint %}

## Validate the connection

To ensure a connection is still valid on the client side, use the [`getUserId`](https://docs.tryterra.co/reference/mobile-sdks/react-native#getuserid) method. This function returns the `user_id` for the connection or null if none exists.

{% hint style="info" %}
**Always validate the connection before using the SDK**

Check if a `user_id` exists right after **initializing the Terra SDK** to see if the connection still exists.

1. **Check if the User is Connected**
   1. If the function returns a user ID, the user is still connected, 🎉 keep vibing along!
   2. If the function returns <mark style="color:red;">`nil`</mark>, the user needs to reconnect.
2. **Re-connect if Needed**\
   If the connection is lost, you can call `terra.initConnection()` again to re-establish the connection.

Calling `terra.initConnection()` when the user is already connected or just needs a reconnection will re-establish the connection if necessary, and the user flow will remain uninterrupted.

On Apple Health, note that a `user_id` only tells you the connection exists on our side, not that your app still holds HealthKit access. Deleting an app clears its HealthKit authorization while the Terra connection survives, so the permission screen can still appear on the next `initConnection()` if iOS has not yet determined permissions for the current install.
{% endhint %}

## Set up background delivery

Background delivery allows data to be synced even when your app is not brought to the foreground. iOS needs a setup step in your AppDelegate; on Android it is enabled through `initConnection`.

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

1. Go to your `/ios` folder in the React Native project
2. Call the function `setUpBackgroundDelivery` in your AppDelegate's `didFinishLaunchingWithOptions` function

This will ensure you get updates for the user's Apple Health data automatically sent to your destination.

<pre class="language-objectivec" data-title="AppDelegate.m" data-line-numbers><code class="lang-objectivec">#import "AppDelegate.h"

#import &#x3C;React/RCTBundleURLProvider.h>
#import &#x3C;TerraiOS/TerraiOS-Swift.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.moduleName = @"AwesomeProject";
  // You can add your custom initial props in the dictionary below.
  // They will be passed down to the ViewController used by React Native.
  self.initialProps = @{};
  [Terra setUpBackgroundDelivery];
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
<strong>}
</strong></code></pre>

{% hint style="success" %}

## iOS Background Delivery Behaviour:

* Data will still be triggered if the **app** **is** **killed** (with much lower frequency)
* Data will only be triggered when **phone** **is** **unlocked**
* Data can only be triggered where there is **network connection**
* Only enabled **Data** **Types** from [the Terra Dashboard](https://dashboard.tryterra.co) will be triggered by background delivery.
* If you are using **CustomPermissions,** please ensure the following permissions are enabled for Background Delivery to work correctly:
  * For **Daily: CustomPermissions.STEPS**
  * For **Sleep: CustomPermissions.SLEEP\_ANALYSIS**
  * For **Body: CustomPermissions.BMI, CustomPermissions.HEART\_RATE**
  * For **Activity: CustomPermissions.WORKOUT\_TYPE**
  * For **Nutrition: CustomPermissions.NUTRITION\_CALORIES**
    {% endhint %}
    {% endtab %}

{% tab title="Android (Health Connect & Samsung)" %}
No AppDelegate step is needed. Passing `true` as the third argument (`schedulerOn`) to `initConnection` enables background delivery.

On Health Connect connections, Terra requests Health Connect's background-read permission during the connection flow and schedules the periodic sync as soon as the user grants it.

{% code title="app.tsx" lineNumbers="true" %}

```typescript
import { initConnection, Connections } from 'terra-react';

await initConnection(
  Connections.HEALTH_CONNECT,
  token,
  true,   // schedulerOn: enables background delivery
  [],     // customPermissions: empty defaults to all
);
```

{% endcode %}

{% hint style="info" %}
We recommend `terra-react` 1.9.12 or later, which bundles `terra-android` 1.7.3. Earlier versions scheduled the periodic sync even when the background-read permission had not been granted, so it could run without being able to read.

If the user declines that permission, background sync is not scheduled. The React Native bridge does not currently expose a method to prompt again, so the user would need to grant it in the Health Connect app settings.
{% endhint %}
{% endtab %}
{% endtabs %}

## Optional: Filter by source app on iOS

Apple Health aggregates data from every health app on the user's device. If a user has both a cloud-based Terra connection (e.g. WHOOP, Garmin) and the same provider's companion app syncing into Apple Health, you'll receive duplicate data: once from the cloud API and once from the Apple Health SDK.

Use `setIgnoredSources` to tell the SDK to skip data from specific apps in HealthKit. Call this **once on every app launch**, after `initTerra()` completes. It is not persisted across app restarts. On Android, this function is a no-op.

```typescript
import { setIgnoredSources } from 'terra-react';

// After initTerra() completes:
setIgnoredSources(["com.whoop.app", "com.garmin.connect.mobile"]);
```

Common bundle identifiers:

| App            | Bundle identifier           |
| -------------- | --------------------------- |
| WHOOP          | `com.whoop.app`             |
| Garmin Connect | `com.garmin.connect.mobile` |
| Fitbit         | `com.fitbit.FitbitMobile`   |
| Oura           | `com.ouraring.oura`         |

{% hint style="info" %}
To find a specific app's bundle identifier, have the user check **Settings → Health → Data Access & Devices** on their iPhone.
{% endhint %}

You now receive health data events automatically at your destination (for example, a webhook).

You can also request historical data to backfill, to verify that data exists, or as a fallback.

Check out the [React Native SDK reference](https://docs.tryterra.co/reference/mobile-sdks/react-native) for details about all the functions in the SDK.

## Disconnect a user

In order to disconnect an SDK user, you may use [the same endpoint as for Web API-based integrations](https://docs.tryterra.co/reference/health-and-fitness-api/authentication#delete-auth-deauthenticateuser), called from your backend.

## Request historical data

You can request for historical data using one of the [data retrieval functions.](https://docs.tryterra.co/reference/mobile-sdks/react-native#data-retrieval)

You may set `toWebhook` to false if you wish for the callback function to return the data payload on the client side.

{% code lineNumbers="true" %}

```tsx
import { Connections, getDaily } from 'terra-react';

const requestData = async () => {
  try {
    const connection = Connections.APPLE_HEALTH;
    const endDate = new Date();
    const startDate = new Date(endDate);
    startDate.setDate(startDate.getDate() - 1);

    const dataMessage = await getDaily(connection, startDate, endDate, false);
  
    if (dataMessage.error !== null) {
      throw new Error("Failed to get data for user");
    }
    if (dataMessage.success) {
      // process data here
      console.log('Daily data:', dataMessage.data);
    }
  
  } catch (error) {
    // Handle failure (network error, etc.)
    console.error('Failed to get daily data:', error);
  }
}
```

{% endcode %}

Check out the [React Native SDK reference](https://docs.tryterra.co/reference/mobile-sdks/react-native) for details about all the functions in the SDK

## Write data

You may write data into Apple Health (Health Connect not yet supported) through one of the helper functions in the SDK

* [postActivity](https://docs.tryterra.co/reference/mobile-sdks/react-native)

{% tabs %}
{% tab title="postActivity" %}
{% hint style="warning" %}
`device_data` must be passed in for postActivity to succeed.
{% endhint %}

{% code lineNumbers="true" %}

```typescript
import { Activity, postActivity, Connections } from 'terra-react';

const postActivityToAppleHealth = async () => {
  const activityPayload: Activity = {
    metadata: {
      name: 'Morning Run',
      start_time: '2024-11-01T07:30:00.000000+00:00',
      end_time: '2024-11-01T08:30:00.000000+00:00',
      type: 8, // RUNNING, see ActivityType enum in terra-react for all values
    },
    device_data: {
      name: 'Terra',
    },
    distance_data: {
      summary: { distance_meters: 5000 },
    },
    calories_data: {
      total_burned_calories: 400,
    },
  };

  const resp = await postActivity(Connections.APPLE_HEALTH, activityPayload);
  if (resp.error !== null) {
    throw new Error('Failed to post activity to Apple Health');
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**The mobile SDKs are only for Apple Health, Health Connect and Samsung Health.** These have no web API, so your app reads them on the phone and sends the data to Terra. Every other provider connects through the [Unified API](https://docs.tryterra.co/unified-api/getting-started) with no SDK.
{% endhint %}
