SDK API Reference

Use the React Native SDK settings, actions, and events to customize the behavior of your AI Agent.

Settings

AdaMessagingView takes the following props. Only handle is required.

appScheme

appScheme?: string;

The custom URL scheme for your app. A link whose scheme equals this value is a deep link into your app. The SDK hands it to the operating system instead of loading it in the WebView.

On iOS the SDK hands only a user-initiated top-level link to the operating system. It refuses a script-driven or subframe link, so a subframe cannot start a deep link on its own. On Android the SDK hands any matching link to the operating system, because Android reports no user-initiation signal.

appUrl

appUrl?: string;

Overrides the app frame URL that the Messaging runtime mounts.

Your handle’s Allowed websites list controls custom apps. In your dashboard, go to Channels > Messaging. Before your transition, use Channels > Chat. Add your app’s origin. If the list does not allow the origin, the runtime drops the URL with a logged warning and mounts the default app.

The value must be an absolute https: URL. The runtime drops invalid values with a logged warning and mounts the default app instead. If the custom app fails to load or complete its handshake, the runtime falls back to the default app.

For local development against an emulator or simulator, expose your development server through an https: tunnel, and add the tunnel origin to Allowed websites. The dashboard accepts only https:// entries. On the production and pre-production environments, the WebView’s host page is an Ada asset origin, not a loopback page. The web SDK’s implicit loopback allowance therefore does not apply there. The emulator or simulator reaches the tunnel origin directly, so no port forwarding is needed.

The exception is the local asset-server environment (environment: { type: "local" }), used for SDK development. Its WebView host page is https://localhost:4900, a loopback origin, so the implicit loopback allowance applies and a loopback appUrl needs no entry. On Android, the emulator’s 10.0.2.2 host alias is not a loopback host, so the runtime rejects it as an appUrl. A host page served from that alias also loses the implicit allowance, for the same reason. Instead, forward the port so the emulator reaches your development server at http://localhost:5173:

adb reverse tcp:5173 tcp:5173

The SDK injects the value into the WebView document through an injected configuration object, never through a URL. Unlike identityToken, which the runtime reads once, the value is delivered again on every document load. Changing the value reloads the WebView. See Custom apps. Requires the Messaging runtime (webSdk="messaging").

cluster

cluster?: string;

Specifies the region your AI Agent runs on. Pass either a short region name (for example, maple or us2) or a full cluster domain. Short names resolve to <name>.ada.support. Defaults to ada.support.

Do not set this value unless instructed by your Ada team.

deviceToken

deviceToken?: string;

Push notification device token.

On the legacy runtime, the SDK forwards the token at initialization, so it is present from the first message the end user sends. On the Messaging runtime, the SDK registers the token once the runtime is ready. It is not folded into the initialization payload on the Messaging runtime, unlike the Android SDK. The token never appears in a URL.

Set the prop once before mounting. Call setDeviceToken on the ref for explicit control after the runtime is ready, or to rotate the token later.

domain

domain?: string;

The Ada domain your AI Agent is served from. Applies to the legacy runtime only. The Messaging runtime resolves its host from environment and cluster.

Do not set this value unless instructed by your Ada team.

embedVersion

embedVersion?: string;

Pins the remote legacy host page to a specific legacy web build for pre-release verification. Rendered as the ?__ada-embed-version=<sha> query parameter. Leave unset for the stable rollout. Ignored when webSdk is not "legacy".

enableProgrammaticControl

enableProgrammaticControl?: boolean;

Runs the Messaging runtime with programmatic control enabled. Defaults to true on React Native for backward compatibility, because the pre-prop React Native behavior was unconditional. This is not parity with the native SDKs.

Programmatic control is required for sendMessage, the two curated bridge requests that read messages, and the gated ada:message:sent / ada:message:received events. The two message reads are getConversation() and getMessages(). The other curated bridge requests do not require it. Set false to opt out: those programmatic calls then reject and the gated events are not delivered. iOS and Android default it to false. It applies to the Messaging runtime only and is never sent on the legacy runtime.

endConversationCallback

endConversationCallback?: (event: unknown) => void;

Called when a conversation ends.

This prop is deprecated. Use onEvent and check for the ada:end_conversation key instead.

environment

environment?:
| { type: "production" }
| { type: "preprod"; branch?: string }
| { type: "local"; port?: number; host?: string }
| { type: "custom"; assetsOrigin: string };

Selects which Ada web-hosting environment the WebView loads and the matching origin allowlists. When provided, environment takes precedence over cluster for asset resolution. Leave unset for production.

eventCallbacks

eventCallbacks?: Record<string, (event: unknown) => void>;

Dictionary of event callbacks keyed by event name. Supports "*" as a wildcard to receive all events.

This prop is deprecated. Use onEvent instead for a unified event callback.

greeting

greeting?: string;

Specifies a greeting response ID to trigger on load. This is useful for setting view-specific greetings across your app.

handle

handle: string;

The handle for your AI Agent. This is a required field.

headless

headless?: boolean;

When set to true, the SDK runs the Ada runtime without rendering its chat UI. The WebView stays mounted but hidden and non-interactive: it renders as an absolute-positioned, transparent 1×1 view with pointer events and accessibility disabled. onEvent, onStateCache, and every action keep working, so you can drive a fully native UI, such as an unread badge fed by message events.

Unmounting the component ends the live session. Pass the last onStateCache snapshot back as initialState to rehydrate on the next mount.

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. See Headless mode for a complete example.

identityToken

identityToken?: string;

Short-lived, single-use identity token minted by your backend via POST /v2/auth/tokens/. Use it to start the session as a known user.

The SDK injects the token into the WebView document before content loads. The token is never placed in a URL. The runtime reads the injected value once per document load and deletes it immediately. Blank or whitespace-only values are treated as absent.

Provide the token before mounting the view. A value set after mount only applies when the WebView reloads, and a reload needs a freshly minted token because tokens are single-use. After the runtime becomes ready, the SDK never delivers a consumed token again on later reloads. Set a newly minted token to authenticate again. Requires the Messaging runtime (webSdk="messaging").

initialState

initialState?: Record<string, unknown> | null;

Previously cached state snapshot to inject before the page loads. When provided, the chat UI renders immediately without a loading state. Capture snapshots with onStateCache.

The SDK filters the value to the allowlisted keys in PERSISTABLE_STATE_KEYS before injection, and discards the whole snapshot when its __ada_cached_at__ timestamp is older than 10 minutes. See State persistence exports.

Snapshots persisted by earlier package versions were unfiltered, and can contain session credentials. Run stored snapshots through toPersistableStateSnapshot() before you pass them here, and overwrite the stored copy with the filtered result. See Session lifecycle and state restoration.

language

language?: string;

Sets the initial display language. To use the same language for AI Agent replies, first turn on languages in your Ada dashboard.

With the Messaging runtime, this setting applies on every WebView launch and takes precedence over a saved language choice. A language picker or setLanguage change during that launch is still saved when session persistence is enabled. This setting takes precedence again on the next launch. Omit this setting to allow a saved choice to restore.

Later language updates from the Agent or another widget sharing the session can change the display language. With session persistence enabled, the widget saves its current display language.

When activation restores an existing session, it synchronizes the configured language if the Agent supports it. If the reply language changes, other open widgets using the same session apply the update live, even during a conversation.

If the Agent does not support the display language, or the language update fails, the display language can differ from the Agent’s reply language. An unsupported configured value can still replace a supported saved choice when session persistence is enabled.

Language codes use the ISO 639-1 language format.

loadTimeoutMs

loadTimeoutMs?: number;

The maximum time in milliseconds the initial WebView load may take. Defaults to 30000, matching the iOS webViewTimeout and Android loadTimeoutMillis defaults. When the timeout elapses first, the component emits the ada.webview.loadFailed event and calls onError. Pass 0 or a negative value to disable the timeout.

Earlier package versions had no load timeout. A silently stalled load now fails after 30 seconds by default.

metaFields

metaFields?: Record<string, string | number | boolean | null>;

Use metaFields to pass information about an end user to Ada on initialization. This can be useful for tracking information about your end users, as well as personalizing their experience.

TSX
metaFields={{
name: "Some name",
age: 30
}}

To change these values after setup, use the setMetaFields action.

onError

onError?: (error: string) => void;

Called when an error occurs inside the WebView, including load failures and runtime errors reported by the SDK.

onEvent

onEvent?: (key: string, data: unknown) => void;

Called whenever the SDK publishes an event, and for WebView lifecycle events. Subscribe to specific keys for analytics or routing. See Events for the available keys.

TSX
onEvent={(key, data) => {
if (key === "ada:end_conversation") {
console.log("Conversation ended", data);
}
}}

onReady

onReady?: () => void;

Called when the SDK has finished initializing and is ready to accept commands. Use it to send sensitive metadata and device tokens through the ref.

onStateCache

onStateCache?: (state: Record<string, unknown>) => void;

Called when the runtime sends a state cache snapshot. Store the snapshot and pass it back as initialState on the next mount to remove the reload spinner after the WebView restarts.

Before your callback runs, the SDK reduces the snapshot to the allowlisted keys in PERSISTABLE_STATE_KEYS and stamps it with __ada_cached_at__. Session credentials and conversation content never reach your code, and the delivered snapshot is safe to persist as is. It matches what the iOS and Android SDKs cache natively. See State persistence exports.

onWebViewError

onWebViewError?: (error: AdaWebViewError) => void;

The typed variant of onError. It runs alongside onError for WebView load and bridge failures. It carries an AdaWebViewError so you can tell one failure from another. This matches the Android and iOS typed error callbacks.

AdaWebViewError is a discriminated union with four kind values:

  • loadFailed: the main document failed to load. It carries url, code, and description.
  • httpError: the main document returned an HTTP error status. It carries url, statusCode, and description.
  • timeout: the page did not load within the configured load timeout. It carries timeoutMs and description.
  • bridgeError: the runtime bridge reported an error. It carries description.

openWebLinksInSafari

openWebLinksInSafari?: boolean;

Whether the SDK hands a user-initiated top-level web link to the system browser. This applies to an http or https link to a non-Ada origin. It defaults to true, which preserves the established React Native behavior.

Such a link cannot become the WebView main document without destroying the runtime bridge, so the SDK opens it externally. Set false to suppress the handoff. The SDK then blocks the link instead of opening it. Ada runtime documents and customer-hosted subframes always stay in place.

On Android the SDK always ejects a foreign top-level document and stops its load. This prop still controls whether the SDK then hands the link to the system browser. On iOS this prop controls the same handoff. iOS gates it additionally on navigationType.

sensitiveMetaFields

sensitiveMetaFields?: Record<string, string | number | boolean | null>;

Sensitive metadata to pass to the AI Agent. This works like metaFields, but the values are not stored in the database, and are deleted after 24 hours.

The SDK forwards these fields at initialization, so an identified session carries them from the first message, matching iOS and Android. On the legacy runtime they ride the start config. On the Messaging runtime they ride a document-start injection. The values never appear in a URL.

Set the prop once before mounting for the init-time path. Call setSensitiveMetaFields on the ref for explicit control after the runtime is ready, or to change the fields later.

sessionStorageAdapter

sessionStorageAdapter?: {
getItem(key: string): Promise<string | null>;
setItem(key: string, value: string): Promise<void>;
removeItem(key: string): Promise<void>;
};

Available from version 1.2.0. Durable key-value storage that your app owns. When you set this prop, the SDK persists session state to the storage. On the next mount, the SDK reads the storage again when the chat runtime asks for the session state. Session state, including active live agent handoff context, then survives an app force-quit. See Session persistence.

Without the prop, the SDK behaves as in earlier versions: session state does not survive a force-quit. Development builds log a one-time warning when the runtime sends session state and no adapter is set.

The package exports the interface as AdaSessionMirrorStorage and adds no storage dependency. The session state contains session tokens. Use a store that stays 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, use a Keychain-backed adapter with a ThisDeviceOnly accessibility class. The Keychain protects the session token at rest. See Session persistence.

react-native-keychain stores values on the device only. Set the ThisDeviceOnly accessibility class so the values stay off backups.

Keychain items survive an app uninstall on iOS. A reinstall can therefore restore the previous install’s session. If your app must not do that, wipe the adapter’s ada-session-mirror:-prefixed keys on first run, or use a backup-excluded file store instead.

TSX
import * as Keychain from "react-native-keychain";
const adapter = {
getItem: async (key: string) => {
const result = await Keychain.getGenericPassword({ service: key });
return result ? result.password : null;
},
setItem: async (key: string, value: string) => {
await Keychain.setGenericPassword("ada", value, {
service: key,
accessible: Keychain.ACCESSIBLE.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY,
});
},
removeItem: async (key: string) => {
await Keychain.resetGenericPassword({ service: key });
},
};
<AdaMessagingView handle="my-company" sessionStorageAdapter={adapter} />

react-native-mmkv is another option. Its API is synchronous, so wrap it in a thin async adapter. On iOS, exclude the store file from backup.

TSX
import { MMKV } from "react-native-mmkv";
const storage = new MMKV({ id: "ada-session" });
const adapter = {
getItem: async (key: string) => storage.getString(key) ?? null,
setItem: async (key: string, value: string) => storage.set(key, value),
removeItem: async (key: string) => storage.delete(key),
};

@react-native-async-storage/async-storage also satisfies the interface. Protect the adapter’s storage on each platform.

On Android, exclude the adapter’s storage from Auto Backup and device transfer. Set fullBackupContent and dataExtractionRules in your app manifest. Otherwise, use a store that Android excludes from backup by default. Without an exclusion, a backup or a device transfer copies the session tokens to another device.

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.

The SDK catches adapter errors. A throwing adapter degrades to no persistence and never breaks chat. The SDK stores values under keys with the ada-session-mirror: prefix. Do not write to those keys yourself. The prop applies to both the Messaging runtime and the legacy runtime.

If an end user signs out of your app, call reset, deleteHistory, or clearPersistedState. See Session persistence.

style

style?: StyleProp<ViewStyle>;

Additional style overrides for the container view. When headless is set, the hidden styling is applied after style and always wins.

styles

styles?: string | Record<string, string>;

Style overrides for the web runtime. The accepted shape depends on the runtime:

  • Messaging runtime: no effect. The runtime ignores the value and logs a warning.
  • Legacy runtime: pass a CSS style override string.

Empty values are omitted.

thirdPartyCookiesEnabled

thirdPartyCookiesEnabled?: boolean;

Enables third-party cookies in the WebView. Android only.

This prop is deprecated. Cookies are managed by the shared cookie jar, and the SDK sets sensible defaults. Normally omit it.

version

version?: string;

Pins the remote legacy host page to a specific legacy chat build for pre-release verification. Rendered as the ?__ada-chat-version=<sha> query parameter. Leave unset for the stable rollout. Ignored when webSdk is not "legacy".

webSdk

webSdk?: "messaging" | "legacy";

Selects which web runtime boots inside the WebView. Defaults to "legacy" so package upgrades do not change end-user behavior before you intentionally cut over. Set "messaging" to run the Messaging runtime.

The headless and identityToken settings and the sendMessage action require the Messaging runtime.

zdChatterAuthCallback

zdChatterAuthCallback?: (callback: (token: string) => void) => void;

Use zdChatterAuthCallback to authenticate Zendesk Chat and Zendesk Messaging Handoffs. For Zendesk Messaging, select webSdk="messaging". Request a JWT from your server and pass it to the callback.

TSX
zdChatterAuthCallback={(callback) => {
const token = getTokenFromAPI(); // Get a fresh JWT token from your API
callback(token);
}}

For Zendesk Messaging, return your Zendesk Messaging authentication JWT. Sign it with a Zendesk Messaging signing key using HS256. Include the signing key ID in the kid header. Include the scope: "user", external_id, and exp claims. Set exp to an expiry time in Unix seconds. Keep the signing secret on your server.

The external_id must be a non-empty string of at most 255 characters. It must not contain /, ?, #, %, whitespace, or control characters. The JWT can include name and email, but Ada does not store these claims for Messaging authentication.

The SDK requests one token at startup, including when both Zendesk platforms are configured. Zendesk Messaging authentication does not require the Zendesk Chat feature. Existing Zendesk Chat callbacks need no changes.

Ada finds or creates the Sunshine user under that external_id when the Handoff starts.

After successful verification, the server stores the identity and its validity window on the end user record. Each successful startup check renews the window for 24 hours. Browser metadata cannot supply or change these values.

If no valid token or signing secret is available, the Handoff uses an anonymous Sunshine user unless another identity mapping applies. When a user signs out, call adaRef.current?.reset() so the next user starts a new conversation and a new Zendesk user. See Authenticate end users for signing key setup.

Actions

Call actions on the AdaMessagingView ref. This lets you control the AI Agent without re-rendering the component. Commands sent before the runtime is ready are queued, then flushed automatically when it becomes ready.

TSX
import { useRef } from "react";
import {
AdaMessagingView,
type AdaMessagingViewHandle,
} from "@ada-cx/messaging-react-native";
function MyComponent() {
const adaRef = useRef<AdaMessagingViewHandle>(null);
return <AdaMessagingView ref={adaRef} handle="my-company" webSdk="messaging" />;
}

clearPersistedState

clearPersistedState(): Promise<void>;

Available from version 1.2.0. Removes every key that sessionStorageAdapter recorded, across all handles and all scopes. The call is not limited to the mounted handle. The live WebView session continues unchanged. Call it when an end user signs out of your app. See Session persistence.

TSX
await adaRef.current?.clearPersistedState();

The returned promise rejects in three cases. It rejects when an adapter delete throws. It rejects when a removed key still reads back a value. It rejects when you supplied an adapter earlier in the component’s lifetime and no adapter is set now. In that third case the call never resolves silently, because it cannot reach the data it must remove. Await the call and handle the rejection so your sign-out flow can retry.

The promise resolves with no effect only when the component never received an adapter.

The SDK tracks the keys it writes, because the adapter interface cannot list keys. An earlier app run that used a different adapter leaves keys the SDK cannot track. To remove those, delete every key in your store that starts with ada-session-mirror:.

deleteHistory

deleteHistory(): void;

Deletes the conversation history and resets the session. If sessionStorageAdapter is set, the SDK also removes the persisted session state.

TSX
adaRef.current?.deleteHistory();

reset

reset(opts?): void;

Starts a new session and refreshes the chat. reset can take an optional object that changes greeting, language, metaFields, and sensitiveMetaFields for the new session. Pass resetChatHistory: false to keep the existing history. If sessionStorageAdapter is set, the SDK also removes the persisted session state.

TSX
adaRef.current?.reset();
// With options
adaRef.current?.reset({
language: "fr",
metaFields: { plan: "pro" },
resetChatHistory: true,
});

sendMessage

sendMessage(body: string): void;

Sends a message into the conversation on behalf of the end user. Pair it with headless and onEvent to drive a fully native chat UI.

TSX
adaRef.current?.sendMessage("Where is my order?");

sendMessage requires the Messaging runtime (webSdk="messaging"). The legacy runtime does not support this action.

setDeviceToken

setDeviceToken(token: string): void;

Registers a push notification device token with Ada. Call it in onReady.

TSX
adaRef.current?.setDeviceToken("push-token");

setLanguage

setLanguage(language: string): void;

Changes the display language at runtime without resetting the session. Language codes use the lowercase, two-letter ISO 639-1 language format.

TSX
adaRef.current?.setLanguage("fr");

setMetaFields

setMetaFields(fields: Record<string, string | number | boolean | null>): void;

Updates metaFields without resetting the session. This is useful if you need to update end-user data after the Agent has already launched.

TSX
adaRef.current?.setMetaFields({
name: "Some name",
age: 30,
});

setSensitiveMetaFields

setSensitiveMetaFields(fields: Record<string, string | number | boolean | null>): void;

Updates sensitive metadata without resetting the session. This works like setMetaFields, but provides an added layer of security. Call it in onReady.

TSX
adaRef.current?.setSensitiveMetaFields({
token: "your_jwt_token",
});

Curated bridge requests

The ref exposes a fixed set of methods that ask the running chat for state or drive it. Each returns a Promise that resolves with the requested value, or rejects. A method rejects in any of four cases:

  • The running runtime build does not implement it.
  • The runtime returns an error, such as a bad argument.
  • No answer arrives before the request times out.
  • The runtime sends a malformed response that carries none of a result, an error, or an unsupported outcome.

A method never silently does nothing: one that only some runtimes support rejects with an explicit unsupported signal.

Reads return public models only. No read returns sensitive meta fields, the internal stores, or persisted session data. Writes and triggers resolve with no value.

Call these after the runtime is ready. Call them in onReady. Only the message reads getConversation() and getMessages() require enableProgrammaticControl, which defaults to true. The other reads, writes, and triggers do not. The default differs per platform. iOS and Android default it to false. On those platforms the same two reads reject until the host enables the flag.

MethodReturnsDescription
close()Promise (rejects as unsupported)The SDK cannot close a parent-hosted webview.
closeCampaign()Promise<void>Dismisses the active campaign.
getConversation()Promise<unknown>The public conversation model.
getInfo()Promise<unknown>The public AI Agent and session info.
getMessages()Promise<unknown>The public message list.
getMetaFields()Promise<Record<string, unknown>>The non-sensitive meta fields set on the session.
isOpen()Promise<boolean>Whether the chat window is open.
open()Promise (rejects as unsupported)The SDK cannot open a parent-hosted webview.
setTheme(theme)Promise<void>Sets the runtime theme to "light", "dark", or "auto".
toggle()Promise (rejects as unsupported)The SDK cannot toggle a parent-hosted webview.
triggerAnswer(answerId)Promise<void>Triggers a specific answer by id.
triggerGreeting(handle?)Promise<void>Triggers the greeting, optionally for a specific handle.
triggerProactive(messageKey, params?)Promise<void>Shows a proactive message by key, with optional variable substitutions.
TSX
const conversation = await adaRef.current?.getConversation();
await adaRef.current?.setTheme("dark");

Events

Subscribe to events through the onEvent prop. The callback receives the event key and an event-specific data payload.

SDK events

With the Messaging runtime, onEvent receives every event the SDK publishes. Common keys include:

KeyDescription
ada:agent:joinedA human agent joined the conversation.
ada:agent:leftA human agent left the conversation.
ada:campaigns:engagedThe end user engaged with a proactive campaign.
ada:close_chatThe end user explicitly closed the chat with the close control, or confirmed ending the conversation. It is not a signal that the chat UI is gone: after an End Chat confirm the UI stays on screen for any survey, and the event fires even when the chat could not end.
ada:connection:changeThe realtime connection state changed.
ada:conversation:changeThe active conversation changed.
ada:conversation:messageA message was added to the conversation. The payload does not include the message body.
ada:csat_submittedThe end user submitted a satisfaction survey.
ada:end_conversationThe conversation ended.
ada:message:receivedThe AI Agent or a human agent sent a message. The payload includes the message body.
ada:message:sentThe end user sent a message. The payload includes the message body.
ada:typing:startA typing indicator started.
ada:typing:stopA typing indicator stopped.

ada:message:sent and ada:message:received carry 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.

ada:message:sent and ada:message:received are delivered only when enableProgrammaticControl is on. The React Native SDK defaults this prop to true. The native app is the programmatic driver. The iOS and Android SDKs default it to false. Set it to false to opt the app out of these gated events on React Native.

WebView lifecycle events

The component also reports its own lifecycle and the session mirror through onEvent:

KeyDescription
ada.webview.loadedThe WebView finished its initial load. The payload includes the loaded url.
ada.webview.loadFailedThe initial load failed, including when loadTimeoutMs elapsed first. The payload includes url, code, statusCode, and error. Also reported through onError.
ada.webview.subresourceLoadFailedA runtime subresource failed to load after the initial load. Also reported through onError.
ada.webview.mainDocumentLostThe main frame left the trusted Ada document, so the chat bridge stopped working. The payload includes url and recovering. recovering is true when the SDK reloads the trusted document. Also reported through onError.
ada.sessionMirror.diagnosticThe SDK could not complete a session mirror operation. The payload includes one reason string and no session data. The SDK reports each reason once per loaded document, except adapter-removeItem-failed, which it reports every time. Reasons: adapter-getItem-failed, adapter-quarantined, adapter-removeItem-failed, adapter-setItem-failed, adapter-unavailable, entries-not-allowlisted, guard-origin-unavailable, legacy-rollout-unresolved, nonce-mismatch, origin-mismatch, scope-mismatch.

Session persistence

The SDK stores session state inside the WebView’s storage. On Android, that storage does not survive a force-quit. On iOS, the OS can also discard it.

From version 1.2.0, pass sessionStorageAdapter to persist session state in storage that your app owns. On the next launch, the chat runtime asks the SDK for the persisted session state, and the SDK reads your adapter to answer. Session state, including active live agent handoff context, then survives an app force-quit. Without the adapter, the SDK does not persist session state, and it behaves as in earlier versions.

Session persistence follows these rules:

  • Session state persists only under the normal persistence mode. The session and private persistence modes clear the session state, so the SDK writes no session state to the adapter in these modes.
  • If you supply an identityToken when a session starts or resets, the identity exchange runs first. The resolved session replaces any persisted session state.
  • The SDK never persists identity tokens to disk.
  • reset and deleteHistory remove the persisted session state. clearPersistedState removes it without a session reset.
  • The SDK shows no prompts or permission dialogs to end users, and it needs no new app permissions.
  • The persisted session state contains session tokens, so it must stay on the device that wrote it. On Android, exclude the adapter’s storage from Auto Backup and device transfer. Otherwise a backup can copy a session to another device.
  • On iOS, AsyncStorage keeps its own directory out of iCloud and encrypted backups, so a backup does not copy the session. AsyncStorage still stores the token in plaintext in the app container. See sessionStorageAdapter for the Keychain-backed alternative.

The onStateCache snapshot is a separate mechanism. It carries branding state only, and it removes the loading state after a restart. It never contains session state.

Call reset() when an end user signs out of your app. Because session state survives app restarts, the next user of the device can otherwise resume the previous user’s conversation. Call reset, deleteHistory, or clearPersistedState in your sign-out flow.

State persistence exports

The package exports the pieces of the state persistence contract described in Session lifecycle and state restoration.

PERSISTABLE_STATE_KEYS

PERSISTABLE_STATE_KEYS: readonly string[]

The allowlist of snapshot keys the SDK keeps: advancedColorsEnabled, allowedProtocols, button, chatEnabled, fallbackUi, features, intro, proactiveConversations, textOverAccentColor, tintColor, and __ada_cached_at__. It matches the allowlist the iOS and Android SDKs persist natively.

STATE_CACHE_TTL_MS

STATE_CACHE_TTL_MS = 600000

The snapshot expiry in milliseconds (10 minutes). An initialState snapshot with an older __ada_cached_at__ stamp is discarded instead of injected.

toPersistableStateSnapshot

toPersistableStateSnapshot(state: Record<string, unknown>): Record<string, unknown>

Reduces a snapshot to the allowlisted keys, and stamps __ada_cached_at__ when the stamp is missing. onStateCache already applies this filter. Use it to sanitize snapshots that earlier package versions persisted unfiltered, before you pass them as initialState.