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

# Installation

The tiun React Native SDK renders the tiun snippet inside a `WebView` and bridges login and checkout to native, with the user's session bound to a hardware-backed device key.

{% hint style="info" %}
**NPM:** [@tiun/react-native-sdk](https://www.npmjs.com/package/@tiun/react-native-sdk)
{% endhint %}

***

## Install the SDK

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

```bash
npm install @tiun/react-native-sdk
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm add @tiun/react-native-sdk
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn add @tiun/react-native-sdk
```

{% endtab %}
{% endtabs %}

***

## Install the native dependencies

The SDK relies on native modules for the WebView, the device key, session storage, and the payment redirect. All of them are **peer dependencies** — install them alongside the SDK. There are no JavaScript fallbacks; a missing module fails at bundle time.

| Package                           | Role                                                            |
| --------------------------------- | --------------------------------------------------------------- |
| `react-native-webview`            | Hosts the tiun snippet.                                         |
| `react-native-secure-sign`        | Hardware-backed device key (Secure Enclave / Android Keystore). |
| `react-native-keychain`           | Stores the session token in the Keychain / Keystore.            |
| `react-native-inappbrowser-nitro` | Opens the payment redirect in the in-app browser.               |
| `react-native-nitro-modules`      | Runtime required by the in-app browser.                         |

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

```bash
npm install react-native-webview react-native-secure-sign \
  react-native-keychain react-native-inappbrowser-nitro \
  react-native-nitro-modules
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm add react-native-webview react-native-secure-sign \
  react-native-keychain react-native-inappbrowser-nitro \
  react-native-nitro-modules
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn add react-native-webview react-native-secure-sign \
  react-native-keychain react-native-inappbrowser-nitro \
  react-native-nitro-modules
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
**`react-native-webview` is verified against 13.x.** The SDK's peer range is permissive, but 13.x is the line it's developed and tested against — pin it there unless you have a reason not to.
{% endhint %}

On iOS, install the pods afterwards:

```bash
cd ios && bundle exec pod install
```

{% hint style="warning" %}
**These are native modules, so you need a native rebuild.** Adding the SDK is not a JavaScript-only change — rebuild and reinstall the app on your device or emulator after installing.
{% endhint %}

***

## Register the return deep link

After payment, the provider redirects back to your app through a deep link. You pick the URL — for example `myapp://tiun/return` — pass it to the SDK as `returnUrl`, and register its scheme in your native config. Checkout cannot complete without it.

### iOS

Add the scheme to `ios/<YourApp>/Info.plist`:

```xml
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLName</key>
    <string>tiun.checkout.return</string>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string>
    </array>
  </dict>
</array>
```

Then forward incoming links to React Native's `Linking` module, which is what the SDK listens on. Add this to `ios/<YourApp>/AppDelegate.swift`:

```swift
// Forward incoming deep links (e.g. myapp://tiun/return) to React Native's
// Linking module so the tiun SDK can resolve checkout on return.
func application(
  _ application: UIApplication,
  open url: URL,
  options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
  return RCTLinkingManager.application(application, open: url, options: options)
}
```

{% hint style="warning" %}
**Registering the scheme in `Info.plist` is not enough on its own.** Without the `RCTLinkingManager` forwarding above, iOS hands the return link to your app and it stops there — React Native never sees it, and the checkout doesn't resolve.
{% endhint %}

### Android

Add an intent filter to your main activity in `android/app/src/main/AndroidManifest.xml`:

```xml
<activity
  android:name=".MainActivity"
  android:launchMode="singleTask"
  android:exported="true">

  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>

  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="myapp" android:host="tiun" android:pathPrefix="/return" />
  </intent-filter>
</activity>
```

{% hint style="warning" %}
**`android:launchMode="singleTask"` is required.** Without it, returning from payment starts a second instance of your activity instead of delivering the link to the running app, and the checkout never resolves.
{% endhint %}

The scheme, host, and path here must match the `returnUrl` you pass to the SDK. See [Configuration](/sdk/react-native-sdk/configuration.md).

***

## Device requirements

The user's session is bound to a non-exportable key in the device's secure hardware, which affects where you can test.

| Target                  | Login and checkout                                                                  |
| ----------------------- | ----------------------------------------------------------------------------------- |
| Physical iPhone         | Works.                                                                              |
| **iOS Simulator**       | **Not supported** — there is no Secure Enclave, so the device key can't be created. |
| Android emulator        | Works.                                                                              |
| Physical Android device | Works.                                                                              |

{% hint style="warning" %}
**Make sure Metro can actually reach your device.** Because iOS testing has to happen on a physical iPhone, your phone and your Mac need to be on a network that lets them talk to each other. Networks with client isolation — most office and guest Wi-Fi — block it, and the symptom is misleading: the app keeps running your **last cached bundle**, so code changes appear to have no effect and fixes look like they didn't work. If you're debugging something that won't budge, put the phone on Personal Hotspot and confirm the bundle actually reloaded before trusting the result.
{% endhint %}

{% hint style="info" %}
**On iOS, checkout shows a one-time system prompt** — *"…wants to use…to sign in"*. This is expected: it's the only iOS mechanism that can hand a custom-scheme redirect back to your app after payment. Android shows no such prompt.
{% endhint %}

***

Next: mount the provider and configure it in [Configuration](/sdk/react-native-sdk/configuration.md).


---

# 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.tiun.io/sdk/react-native-sdk/installation.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.
