> 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/guides/react-native/monetize-in-react-native.md).

# Monetize in React Native

This guide walks through a complete React Native integration: creating products, installing the SDK, wiring checkout, gating content on what the user has bought, and going live.

The tiun React Native SDK covers **authentication and checkout** — subscriptions and one-time purchases. It renders the tiun overlays inside your app and binds the user's session to a hardware-backed device key, so the session survives restarts without you storing anything.

***

## 1. Set up your environment and products

In the dashboard's **Get Started** modal, pick **Native app** as your platform. Then create one product per plan — for example **Light** and **Pro** — and copy their product IDs. The full walkthrough is in [creating your first product](/guides/getting-started/creating-first-product.md).

Copy your **snippet ID** from the same environment you'll point the app at. Most teams build against sandbox first; see [setting up your environment](/guides/getting-started/set-up-environment.md).

***

## 2. Install the SDK

Install the SDK and its native dependencies, then rebuild:

```bash
npm install @tiun/react-native-sdk react-native-webview \
  react-native-secure-sign react-native-keychain \
  react-native-inappbrowser-nitro react-native-nitro-modules
```

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

These are native modules, so a JavaScript reload isn't enough — rebuild and reinstall the app. The full list of what each dependency does is in [Installation](https://app.gitbook.com/s/NH7Oo7FWeLjynlddH6r8/react-native-sdk/installation).

***

## 3. Register the return deep link

After payment, the provider redirects back into your app through a deep link that you choose — for example `myapp://tiun/return`. Register its scheme natively, or checkout can never complete.

On iOS, add it to `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>
```

Still on iOS, forward incoming links to React Native's `Linking` module in `AppDelegate.swift` — the `Info.plist` entry alone doesn't get the link to React Native, and checkout won't resolve without it:

```swift
func application(
  _ application: UIApplication,
  open url: URL,
  options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
  return RCTLinkingManager.application(application, open: url, options: options)
}
```

On Android, add an intent filter to your main activity and set `android:launchMode="singleTask"`:

```xml
<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>
```

***

## 4. Add the provider

Keep your config and product IDs in one module so every screen references the same values:

```tsx
// tiun.ts
import type { TiunConfig } from '@tiun/react-native-sdk';

export const TIUN_CONFIG: TiunConfig = {
  snippetId: 'YOUR_SANDBOX_SNIPPET_ID',
  host: 'https://api-sandbox.tiun.live',
  returnUrl: 'myapp://tiun/return',
  language: 'en',
  debug: true,
};

export const TIUN_PRODUCTS = {
  light: 'p-test-light',
  pro: 'p-test-pro',
} as const;
```

Wrap your app root in `<TiunProvider>`. The one rule is that it sits above everything that uses the tiun hooks — the overlay sizes itself to the window, so it covers your UI from anywhere in the tree:

```tsx
import { TiunProvider } from '@tiun/react-native-sdk';
import { TIUN_CONFIG } from './tiun';

export default function App() {
  return (
    <TiunProvider config={TIUN_CONFIG}>
      <RootNavigator />
    </TiunProvider>
  );
}
```

The provider takes up no space on screen until the user opens login or checkout.

***

## 5. Build a pricing screen

One button per plan, each calling `checkout()` with its product ID:

```tsx
import { Button, View } from 'react-native';
import { useTiun } from '@tiun/react-native-sdk';
import { TIUN_PRODUCTS } from './tiun';

function PricingScreen() {
  const { checkout } = useTiun();

  return (
    <View>
      <Button
        title="Light — EUR 19/mo"
        onPress={() => checkout({ productId: TIUN_PRODUCTS.light })}
      />
      <Button
        title="Pro — EUR 199/mo"
        onPress={() => checkout({ productId: TIUN_PRODUCTS.pro })}
      />
    </View>
  );
}
```

tiun opens the checkout overlay — it collects the user's email, verifies their identity, takes payment, and grants access in one flow. Payment itself happens in the in-app browser and returns to your app through the deep link you registered in step 3. For what the overlay does behind the scenes, see [Checkout / How it works](/reference/checkout/how-it-works.md) in Reference.

***

## 6. Gate content on what the user bought

After a successful purchase the user's `productAccess` array contains the product they just bought. It's the canonical source of truth for what they can access — see [Product access](/reference/checkout/product-access.md) in Reference.

Derive the current tier in one place:

```tsx
import { useTiun } from '@tiun/react-native-sdk';
import { TIUN_PRODUCTS } from './tiun';

type Tier = 'free' | 'light' | 'pro';

export function useTier(): Tier {
  const { user } = useTiun();
  const access = user?.productAccess ?? [];

  if (access.includes(TIUN_PRODUCTS.pro)) return 'pro';
  if (access.includes(TIUN_PRODUCTS.light)) return 'light';
  return 'free';
}
```

Then gate your screens on it:

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

function PremiumScreen() {
  const tier = useTier();
  const { checkout } = useTiun();

  if (tier !== 'pro') {
    return (
      <Button
        title="Upgrade to Pro"
        onPress={() => checkout({ productId: TIUN_PRODUCTS.pro })}
      />
    );
  }

  return <ProContent />;
}
```

`useTiun()` re-renders your component whenever the user changes, so the same code covers checkout success, login, logout, and the session restore at launch. If you need to *react* to a change rather than render from it — refetching data, resetting a screen — subscribe with `useTiunEvent('userChange', ...)`.

{% hint style="info" %}
**The `userChange` payload has no `event` field in React Native.** If you're porting from the web SDK, replace `data.event === 'login'` checks with the separate `login` and `logout` events. See [Hooks and events](https://app.gitbook.com/s/NH7Oo7FWeLjynlddH6r8/react-native-sdk/hooks).
{% endhint %}

***

## 7. Add login and logout

Returning subscribers sign in without buying again — their existing `productAccess` comes back with the session, and your gating picks it up unchanged.

```tsx
import { Button } from 'react-native';
import { useTiun } from '@tiun/react-native-sdk';

function AuthButton() {
  const { isAuthenticated, login, logout } = useTiun();

  return (
    <Button
      title={isAuthenticated ? 'Log out' : 'Log in'}
      onPress={() => (isAuthenticated ? logout() : login())}
    />
  );
}
```

***

## 8. Verify on your server

Gating in the app controls what it renders. If your backend serves the premium payload itself, verify the user there before responding — a client can be modified.

Get a signed token from the SDK and send it with the request:

```tsx
const { getUserVerificationToken } = useTiun();

async function fetchPremium() {
  const token = await getUserVerificationToken();
  if (!token) return null;

  const response = await fetch('https://api.example.com/premium', {
    headers: { Authorization: `Bearer ${token}` },
  });

  return response.ok ? response.json() : null;
}
```

The token is the same signed JWT the web SDK issues, so the backend half is unchanged — see [verify authentication server-side](/guides/authentication/verify-server-side.md) for the exchange, and [verify subscriptions server-side](/guides/subscriptions/verify-server-side.md) for checking entitlements.

***

## 9. Test on a device

The user's session is bound to a key in the device's secure hardware, which limits where you can test:

* **iOS Simulator can't do login or checkout** — there's no Secure Enclave. Use a physical iPhone.
* **Android emulators and devices work** normally.
* On iOS, checkout shows a one-time system prompt — *"…wants to use…to sign in"*. That's expected; it's how the payment redirect gets back into your app.
* Set `debug: true` in your config to see `[tiun]` bridge logs in the Xcode or Android console.
* **Check that Metro can reach your iPhone.** Office and guest Wi-Fi often isolate clients, and the failure is silent — the app keeps running its last cached bundle, so your changes look like they did nothing. Personal Hotspot is the quickest way to rule it out.

Use [simulated payments](/guides/testing/simulate-payments.md) in sandbox so you can run the full purchase flow without real cards.

***

## 10. Go live

When the sandbox integration works:

1. Set up **live** in the dashboard, if you haven't — platform, products, and API keys are separate from sandbox.
2. Remove `host` from your config (or set it to `https://api.tiun.live`) so the app targets live.
3. Swap in your **live** snippet ID and live product IDs (`p-test-…` → `p-live-…`).
4. Turn off `debug`.
5. If you verify server-side, switch to the live API base URL and a live API key.

```tsx
export const TIUN_CONFIG: TiunConfig = {
  snippetId: 'YOUR_LIVE_SNIPPET_ID',
  returnUrl: 'myapp://tiun/return',
  language: 'en',
};
```

The SDK API is identical across environments — only these IDs and credentials change. See [setting up your environment](/guides/getting-started/set-up-environment.md) for the full sandbox-to-live workflow.

***

For the full hook and event reference, see [Hooks and events](https://app.gitbook.com/s/NH7Oo7FWeLjynlddH6r8/react-native-sdk/hooks) in the SDK docs, and [React Native examples](https://app.gitbook.com/s/NH7Oo7FWeLjynlddH6r8/react-native-sdk/examples) for more patterns.


---

# 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/guides/react-native/monetize-in-react-native.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.
