# React Native

## Prerequisites

1. Install the [`react-native-terra-rt-react`](https://www.npmjs.com/package/react-native-terra-rt-react) package:

```bash
npm install react-native-terra-rt-react
```

2. **iOS:** In your `Info.plist`, add:
   * `Privacy - Bluetooth Always Usage Description`: Justification for BLE usage
   * `Privacy - Motion Usage Description`: Justification for motion sensor usage (required if streaming accelerometer, gyroscope, or step data from the phone's built-in sensors via `Connections.APPLE`)
3. **iOS:** Run `pod install` in your `/ios` directory.
4. **Android:** Permissions are requested automatically by the SDK on initialization.

## SDK Initialization

{% hint style="info" %}
Initialize the SDK every time the app is opened or brought into the foreground.
{% endhint %}

Set up event emitters for receiving data, then initialize:

```tsx
import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
import {
  initTerra, initConnection, startDeviceScan, startRealtime,
  stopRealtime, disconnect, getUserId,
  Connections, DataTypes,
} from 'react-native-terra-rt-react';
import type { Update, Device, SuccessMessage } from 'react-native-terra-rt-react';

// Set up event listeners (do this once, e.g. in useEffect)
const updateEmitter = new NativeEventEmitter(NativeModules.UpdateHandler);
updateEmitter.addListener('Update', (update: Update) => {
  console.log(`${update.type}: ${update.val}`);
});

const deviceEmitter = new NativeEventEmitter(NativeModules.DeviceHandler);
deviceEmitter.addListener('Device', (device: Device) => {
  console.log(`Found device: ${device.name}`);
});

const connectionEmitter = new NativeEventEmitter(NativeModules.ConnectionHandler);
connectionEmitter.addListener('ConnectionUpdate', (connected: boolean) => {
  console.log(`Websocket connected: ${connected}`);
});

// Initialize the SDK
const result = await initTerra('YOUR_DEV_ID', 'YOUR_REFERENCE_ID');
if (!result.success) {
  console.error('Failed to initialize:', result.error);
}
```

## Initializing a Connection

Register the device with Terra using an authentication token generated **from your backend**:

```tsx
const token = 'yourAuthToken'; // Generated from your backend

const connResult = await initConnection(token);
if (connResult.success) {
  console.log('Connection initialized!');
}
```

To generate the **token**, make the below call **from your backend**:

{% openapi src="<https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/v5.yml>" path="/auth/generateAuthToken" method="post" %}
<https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/v5.yml>
{% endopenapi %}

## Device Scanning

BLE device scanning works differently on iOS and Android:

{% tabs %}
{% tab title="Android" %}
On Android, use `startDeviceScan` which shows a built-in device picker:

```tsx
const scanResult = await startDeviceScan(Connections.BLE);
if (scanResult.success) {
  console.log('Device connected!');
}
```

{% endtab %}

{% tab title="iOS" %}
On iOS, `startDeviceScan` is not supported. Instead, use the `BLWidget` native view component:

```tsx
import { requireNativeComponent } from 'react-native';

const BLWidget = requireNativeComponent('BLWidget');

// In your JSX:
<BLWidget
  style={{ flex: 1 }}
  withCache={false}
  onSuccessfulConnection={(event) => {
    console.log('Connected:', event.nativeEvent.success);
  }}
/>
```

Render this component when you want to show the BLE scanner. It displays a list of discovered devices and handles connection automatically.
{% endtab %}
{% endtabs %}

**Platform-conditional pattern:**

```tsx
const startScanning = () => {
  if (Platform.OS === 'android') {
    startDeviceScan(Connections.BLE).then((result) => {
      console.log('Connected:', result.success);
    });
  } else {
    // Show BLWidget in your UI (see iOS tab above)
  }
};
```

## Real-Time Data Streaming

Once a device is connected, start streaming data. Updates arrive via the `Update` event emitter you set up earlier.

```tsx
const dataTypes = [DataTypes.HEART_RATE, DataTypes.STEPS];

// Start streaming locally (no server)
await startRealtime(Connections.BLE, dataTypes);
```

To also stream to Terra's server, see [Your App → Terra](/streaming-api/your-app-greater-than-terra/react-native.md).

## Stop & Disconnect

```tsx
await stopRealtime(Connections.BLE);
await disconnect(Connections.BLE);
```

## WatchOS Integration

To stream data from an Apple Watch, call `connectWithWatchOS()` on the iOS companion app side, then start streaming with `Connections.WATCH_OS`:

```tsx
import { connectWithWatchOS } from 'react-native-terra-rt-react';

// Connect to paired Apple Watch (iOS only — rejects on Android)
await connectWithWatchOS();

// Start receiving watch data
await startRealtime(Connections.WATCH_OS, [DataTypes.HEART_RATE]);
```

{% hint style="info" %}
The watchOS app itself must be written in native Swift using the `Terra` class from the `TerraRTiOS` framework. See the [iOS WatchOS guide](/streaming-api/connect-wearable-to-sdk/ios-swift.md#watchos-integration) for the watch-side setup.
{% endhint %}


---

# 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.tryterra.co/streaming-api/connect-wearable-to-sdk/react-native.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.
