Mobile Widget SDKs

# React Native

Embed Returning.AI custom widgets in a React Native CLI application or an Expo development build.

Package: [@returningai/react-native-widget-sdk](https://www.npmjs.com/package/@returningai/react-native-widget-sdk)

## Requirements

- React 19.2 or later within the supported major version.
- React Native 0.86, React Native WebView 16, and Node.js 22.13+.
- Expo SDK 57 with a development build when using Expo.
- An HTTPS client origin and a trusted embed-token backend.

> Expo Go is not supported
>
> Use `expo run:ios` or `expo run:android` to create a development build. The Old Architecture and hosts below the listed peer versions are not certified.

## Install the packages

`terminal`

```bash
npm install @returningai/react-native-widget-sdk react-native-webview
```

## Mount a custom widget

Import the component and configuration from the published package. The token provider calls your backend and returns only a fresh embed token.

`RewardsScreen.tsx`

```tsx
import {
  ReturningAIWidget,
  ReturningAIWidgetConfiguration,
  ReturningAIWidgetController,
} from "@returningai/react-native-widget-sdk";

const controller = new ReturningAIWidgetController();
const configuration = ReturningAIWidgetConfiguration.customBundle({
  widgetId: "YOUR_SUPPLIED_WIDGET_ID",
  bundleUrl: "YOUR_SUPPLIED_BUNDLE_URL",
  clientOrigin: "https://mobile-client.example",
  runtimeUrl:
    "https://unpkg.com/@returningai/widget-sdk/dist/rai-widget.iife.js",
});

export function RewardsScreen() {
  return (
    <ReturningAIWidget
      configuration={configuration}
      controller={controller}
      embedTokenProvider={async () => {
        return backend.fetchReturningAIEmbedToken();
      }}
      onExternalNavigation={(uri) => {
        appRouter.openExternal(uri);
      }}
    />
  );
}
```

## Configure Web Crypto for Expo

Install `expo-crypto` and load this polyfill before the first widget mount when `crypto.getRandomValues` is unavailable.

`polyfill-crypto.ts`

```typescript
import * as ExpoCrypto from "expo-crypto";

const webCrypto = globalThis.crypto;
if (
  webCrypto === undefined ||
  typeof webCrypto.getRandomValues !== "function"
) {
  Object.defineProperty(globalThis, "crypto", {
    configurable: true,
    value: {
      getRandomValues(array) {
        const bytes = ExpoCrypto.getRandomBytes(array.byteLength);
        new Uint8Array(
          array.buffer,
          array.byteOffset,
          array.byteLength,
        ).set(bytes);
        return array;
      },
    },
  });
}
```

## Session lifecycle

- Keep one `ReturningAIWidgetController` attached to one mounted widget.
- The controller supports `reload()`, `retry()`, `updateTheme()`, `logout()`, and `invalidate()`.
- Unmount the widget on host logout. On account change, mount a new component with a stable, non-secret session key.
- Do not cache a stale embed token after a session-expired event.

Return to the [Mobile Widget SDK overview](https://docs.returning.ai/mobile-widget-sdk.md).
