> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ada.cx/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ada.cx/_mcp/server.

# Getting started

The Ada React Native SDK embeds your Ada AI Agent in a React Native app through `react-native-webview`. This guide takes you from installation to a working integration, including identity tokens and headless mode.

> **Note**
>
> You need an active Ada handle to use the SDK. To gain access, reach out to an Ada Account Manager.

> **Note**
>
> This guide covers the new Ada React Native SDK ([`@ada-cx/messaging-react-native`](https://www.npmjs.com/package/@ada-cx/messaging-react-native)). If you are migrating from the existing SDK (`@ada-support/react-native-sdk`), see [Upgrade from the existing React Native SDK](#upgrade-from-the-existing-react-native-sdk) below.

## Compatibility

| Requirement          | Minimum version |
| -------------------- | --------------- |
| react                | 18.0.0          |
| react-native         | 0.73.0          |
| react-native-webview | 13.0.0          |

To open chat links in the system browser on iOS, use `react-native-webview` 13.16.1 or later.

The SDK does not ship a native module of its own. It builds on `react-native-webview`, so complete that package's standard native installation for your app first. Your minimum iOS and Android OS versions follow the versions your app and `react-native-webview` support.

The Messaging runtime inside the WebView requires iOS 15.4 or later and Android System WebView 99 or later. The `react`, `react-native`, and `react-native-webview` minimum versions are unchanged.

## Install the React Native SDK

Install the package and its peer dependency:

**`npm`**

```bash npm
npm install @ada-cx/messaging-react-native react-native-webview
```

**`yarn`**

```bash yarn
yarn add @ada-cx/messaging-react-native react-native-webview
```

If your app does not already include compatible `react` and `react-native` versions, upgrade those first. No Podfile changes are required for the Ada package. Run `pod install` only if adding `react-native-webview` for the first time.

## Launch Ada

Import the `AdaMessagingView` component and render it. You must pass a valid `handle` for the Agent to load.

**`TSX`**

```tsx TSX
import { useRef } from "react";
import {
  AdaMessagingView,
  type AdaMessagingViewHandle,
} from "@ada-cx/messaging-react-native";

export function SupportScreen() {
  const adaRef = useRef<AdaMessagingViewHandle>(null);

  return (
    <AdaMessagingView
      ref={adaRef}
      handle="my-company"
      webSdk="messaging"
      language="en"
      metaFields={{ plan: "pro", signedIn: true }}
      onReady={() => {
        adaRef.current?.setSensitiveMetaFields({
          authToken: "secure-session-token",
        });
      }}
      onEvent={(key, data) => {
        console.log("[Ada]", key, data);
      }}
      style={{ flex: 1 }}
    />
  );
}
```

> **Note**
>
> The `webSdk` prop defaults to `"legacy"` so that package upgrades do not change end-user behavior before you intentionally cut over. Set `webSdk="messaging"` explicitly to run the Messaging runtime. The identity token and headless features below require the Messaging runtime.

The quickstart above does not persist session state. Without the `sessionStorageAdapter` prop, the SDK behaves as in earlier versions. To keep a session across an app force-quit, add the prop. It is available from version 1.2.0. It persists session state in storage that your app owns. See [Session persistence](/messaging/react-native/sdk-api-reference#session-persistence).

> **Warning**
>
> The session state contains session tokens, so it must stay on the device that wrote it. On Android, Auto Backup and device transfer copy the adapter's storage onto a different device. Exclude the adapter's storage from Auto Backup and device transfer.
>
> On iOS, AsyncStorage marks its own directory `NSURLIsExcludedFromBackupKey`, so it stays out of iCloud and encrypted backups. AsyncStorage still holds the session token in plaintext in the app container. Use a Keychain-backed adapter with a `ThisDeviceOnly` accessibility class to protect the token at rest. Keychain items survive an app uninstall, so a reinstall can restore the previous session. See [Session persistence](/messaging/react-native/sdk-api-reference#session-persistence) for how to wipe them on first run.

> **Warning**
>
> If you pass `sessionStorageAdapter` and an end user signs out of your app, call `reset()`. Otherwise the next user of the device can resume the previous user's conversation.

Most apps only need `handle`. Leave `cluster` unset unless Ada tells you your AI Agent is hosted on a non-default production region. If it is, pass the exact cluster value that Ada gives you:

**`TSX`**

```tsx TSX
<AdaMessagingView handle="my-company" webSdk="messaging" cluster="maple" />
```

## Control the Agent at runtime

Call actions on the component ref. Commands sent before the runtime is ready are queued, then flushed automatically.

**`TSX`**

```tsx TSX
adaRef.current?.sendMessage("Where is my order?");
adaRef.current?.setLanguage("fr");
adaRef.current?.setMetaFields({ tier: "gold" });
adaRef.current?.reset();
```

The [SDK reference](/messaging/react-native/sdk-api-reference#actions) covers every action, setting, and event.

## Secure identity tokens

Use `identityToken` to start the session as a known user.

1. Mint a token from your backend with `POST /v2/auth/tokens/`. The token is short-lived and single-use.
2. Fetch the token in your app, then pass it to the view before you mount it.

**`TSX`**

```tsx TSX
const token = await fetchAdaIdentityToken(); // your backend call

<AdaMessagingView handle="my-company" webSdk="messaging" identityToken={token} />
```

The SDK injects the token into the WebView document before content loads. The token never appears in a URL. The runtime reads it once per document load and then deletes it. A token set after mount only applies when the WebView reloads.

> **Note**
>
> Fetch a fresh token before each mount. Because tokens are single-use, a remount needs a newly minted token.

## Headless mode

Set `headless` to run the Ada runtime without its chat UI. The WebView stays mounted, but it is hidden and non-interactive. `onEvent`, `onStateCache`, and every imperative handle method keep working. Use them to build a fully native experience, such as an unread badge driven by message events:

**`TSX`**

```tsx TSX
const adaRef = useRef<AdaMessagingViewHandle>(null);
const [unread, setUnread] = useState(0);

<AdaMessagingView
  ref={adaRef}
  handle="my-company"
  webSdk="messaging"
  headless
  onEvent={(key) => {
    if (key === "ada:message:received") {
      setUnread((count) => count + 1); // drive your own red-dot badge
    }
  }}
/>

// Later, from your own composer UI:
adaRef.current?.sendMessage("Where is my order?");
```

> **Warning**
>
> The `ada:message:sent` and `ada:message:received` events include full message bodies, including any personal information end users type. Do not forward these payloads to analytics or logging tools unless your product and security teams have accepted that exposure.

> **Note**
>
> Headless sessions run with no visual indicator, and a session starts as soon as the view mounts. Mount a headless view only when you intend to start or resume a session.

Headless requires the Messaging runtime (`webSdk="messaging"`). The remote legacy host page ignores it.

> **Note**
>
> The React Native SDK exposes an [`enableProgrammaticControl`](/messaging/react-native/sdk-api-reference#enableprogrammaticcontrol) prop that defaults to `true`. The iOS and Android SDKs default it to `false`. At the default, `getConversation`, `getMessages`, `selectQuickReply`, `sendMessage`, and the `ada:message:sent` / `ada:message:received` events all work. Set it to `false` to disable them.

## Session lifecycle and state restoration

Keep the component mounted while you need the live session. Unmounting the component ends the session.

State restoration removes the loading state only. To persist the session itself across a force-quit, pass the `sessionStorageAdapter` prop. See [Session persistence](/messaging/react-native/sdk-api-reference#session-persistence).

To restore the UI instantly after process recreation:

1. Use `onStateCache` to persist the latest state snapshot.
2. Pass that snapshot as `initialState` the next time the view mounts.

This removes the loading spinner on WebView restart flows.

Your app owns this persistence, and the SDK writes nothing to disk itself. Before `onStateCache` runs, the SDK reduces every snapshot to an allowlist of non-sensitive keys and stamps it with `__ada_cached_at__`. Session credentials and conversation content never reach your callback, so the delivered snapshot is safe to persist as is. On the next mount, the SDK filters `initialState` again and discards snapshots whose `__ada_cached_at__` stamp is older than 10 minutes.

The package exports the pieces of this contract: `PERSISTABLE_STATE_KEYS` (the allowlist), `STATE_CACHE_TTL_MS` (the expiry), and `toPersistableStateSnapshot()` (the filter itself). See [State persistence exports](/messaging/react-native/sdk-api-reference#state-persistence-exports).

> **Warning**
>
> Snapshots persisted by earlier package versions were unfiltered, and can contain session credentials. Run stored snapshots through `toPersistableStateSnapshot()` once before you pass them as `initialState`, and overwrite the stored copy with the filtered result.

## Upload and media permissions

If your Agent flow lets end users upload files or capture media, include the platform permissions that `react-native-webview` and the device features require.

For iOS, add usage descriptions to `ios/[project]/Info.plist`:

| Key                              | When required            |
| -------------------------------- | ------------------------ |
| `NSCameraUsageDescription`       | Camera capture uploads   |
| `NSPhotoLibraryUsageDescription` | Photo library uploads    |
| `NSMicrophoneUsageDescription`   | Video capture with audio |

For Android, add any permissions your upload or capture flow requires in `AndroidManifest.xml`.

## Upgrade from the existing React Native SDK

If you are migrating from `@ada-support/react-native-sdk`, the new package is designed as a low-friction replacement. The recommended path is:

1. Replace the npm package.
2. Keep the runtime on legacy first (`webSdk` defaults to `"legacy"`).
3. Use the deprecated `AdaEmbedView` alias as a temporary bridge if that reduces churn.
4. Move to `AdaMessagingView` and the new prop patterns once the package upgrade is stable.
5. Set `webSdk="messaging"` when you are ready to cut over to the Messaging runtime.

### Side-by-side mapping

| Existing                                                                                          | Messaging SDK                                                           |
| ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `@ada-support/react-native-sdk`                                                                   | `@ada-cx/messaging-react-native`                                        |
| `AdaEmbedView`                                                                                    | `AdaMessagingView` (a deprecated `AdaEmbedView` alias is also exported) |
| `require_relative '../node_modules/@ada-support/react-native-sdk/react_native_pods'` in `Podfile` | Remove it                                                               |
| `use_ada!()` in `Podfile`                                                                         | Remove it                                                               |

The new package relies on the standard React Native and `react-native-webview` native setup only. Remove any Ada-specific Podfile helpers from the old package.

### Before / after: package

```bash
# Before
npm install @ada-support/react-native-sdk

# After
npm install @ada-cx/messaging-react-native
```

### Before / after: imports

Smallest possible migration:

**`TSX`**

```tsx TSX
import { AdaEmbedView } from "@ada-cx/messaging-react-native";
```

Recommended end state:

**`TSX`**

```tsx TSX
import { AdaMessagingView } from "@ada-cx/messaging-react-native";
```

### Prop differences to watch for

Some legacy patterns still work for compatibility, but they are no longer the preferred integration pattern.

| Legacy prop / pattern      | Status in the new package              | Recommended approach                                                                                                                                                                                |
| -------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `deviceToken` prop         | Supported                              | Set the prop before mounting so the token forwards at initialization on the legacy runtime; call `ref.setDeviceToken()` to rotate it later                                                          |
| `endConversationCallback`  | Supported but deprecated               | Use `onEvent` and check for the `ada:end_conversation` key                                                                                                                                          |
| `eventCallbacks`           | Supported but deprecated               | Use `onEvent`                                                                                                                                                                                       |
| `sensitiveMetaFields` prop | Supported                              | Set the prop before mounting so the fields forward at initialization and reach the first message; call `ref.setSensitiveMetaFields()` in `onReady` only to change them mid-session                  |
| `styles`                   | Legacy runtime only                    | Pass a CSS string on the legacy runtime. The Messaging runtime ignores it. See [styles](/messaging/react-native/sdk-api-reference#styles)                                                           |
| `thirdPartyCookiesEnabled` | Supported but deprecated; Android only | Normally omit it                                                                                                                                                                                    |
| `zdChatterAuthCallback`    | Supported                              | Authenticate Zendesk Chat or Zendesk Messaging end users. See [callback requirements](/messaging/react-native/sdk-api-reference#zdchatterauthcallback) for the JWT and anonymous fallback behavior. |

## Release checklist

Before shipping your integration or migration to production:

* Verify your real production handle launches successfully on both iOS and Android
* Confirm `onReady` fires
* Confirm your event logging still receives SDK events
* Call `setDeviceToken()` in `onReady`. Verify device token storage in the end user's sensitive metadata. See [Push notifications](/docs/channels/messaging/push-notifications) for webhook delivery.
* Test `reset()` and `deleteHistory()` if your app exposes those actions
* If you pass `sessionStorageAdapter`, verify that your sign-out flow calls `reset()`, `deleteHistory()`, or `clearPersistedState()`
* Test background / foreground transitions and process restart behavior