iOS SDK reference
Use the iOS SDK settings, events, and actions to customize the behavior of your AI Agent. This page covers the public API of AdaWebHost in the AdaMessaging framework.
Settings
Configure AdaWebHost with input parameters at initialization. The SDK builds the WebView and its URL inside init, so all settings must be set at initialization. To change values later, use the actions.
appScheme
appScheme: String = ""
Use this setting to pass the scheme name of the host app. This allows for more robust handling of universal links.
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 a 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 exception is the local asset-server environment (.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 such as http://localhost:5173 needs no entry.
The value is delivered to the web runtime through an injected configuration object, not through the WebView URL. It applies only when webSdk is .messaging. The legacy runtime ignores it.
cluster
cluster: String = ""
Specifies the cluster your AI Agent runs on.
Set this only if your Agent is hosted on a non-default cluster (for example, us2, maple, eu).
If the Agent is on the default cluster, leave this unset.
deviceToken
deviceToken: String = ""
The APNs device token for push notifications. 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. To set or rotate the token after initialization, use setDeviceToken.
domain
domain: String = ""
The Ada domain your AI Agent is served from.
embedVersion
embedVersion: String = ""
Pins the legacy runtime’s host page to a specific embed build. Used for pre-release verification with your Ada team. Leave blank for the stable rollout. Ignored when webSdk is not .legacy.
enableProgrammaticControl
enableProgrammaticControl: Bool = false
Opts this host into the Messaging runtime’s programmatic-control API. When set to true, your app can:
- Call
sendMessage. - Receive the
ada:message:sentandada:message:receivedevents ineventCallbacks.
While the flag is false (the default), sendMessage is rejected with ProgrammaticControlNotEnabled and those events are not delivered.
With this flag on, full message bodies flow into your app code through eventCallbacks, including any PII your end users type. Do not write message bodies to logs, analytics, or crash reports. Have your product and security teams accept that exposure explicitly before turning this on.
This setting applies only when webSdk is .messaging. The legacy runtime ignores it.
environment
environment: AdaEnvironment? = nil
The deployment environment that hosts the WebView entry page and SDK assets. See AdaEnvironment. Most production apps set .production.
The Messaging runtime requires an explicit environment. If you set webSdk: .messaging but leave environment unset, the host falls back to the legacy path.
eventCallbacks
eventCallbacks: [String: (_ event: [String: Any]) -> Void]? = nil
A dictionary of callbacks keyed by event name. See Events for the delivery contract and the list of event keys.
greeting
greeting: String = ""
Use this setting to customize the greeting messages that new end users see. This is useful for setting view-specific greetings across your app. The greeting should correspond to the ID of the Answer you would like to use, which you can find in the URL of the corresponding Answer in the dashboard.
Example

This setting is only applicable if you’re using a scripted AI Agent.
handle
handle: String
The handle for your AI Agent. This is a required field.
headless
headless: Bool = false
When set to true, the Messaging runtime connects to your AI Agent without rendering its default chat UI. Use this when your app renders its own conversation UI with native components and drives the conversation through sendMessage and eventCallbacks.
Headless hosts are typically paired with enableProgrammaticControl: true. Without it, the methods and events needed to drive a custom UI are rejected at runtime.
headless suppresses only the runtime’s UI. To run the WebView without presenting it, launch with launchHeadlessWebSupport. That action forces this setting to true, and rebuilds the WebView when the host was created without it, so set headless: true at initialization to avoid the extra load. See Headless session lifecycle for the constraints.
Headless sessions run with no visual indicator. The runtime creates and persists session state inside the WebView the same way as a visible session. Treat enabling headless as a meaningful trust decision.
This setting applies only when webSdk is .messaging. The legacy runtime ignores it.
identityToken
identityToken: String = ""
A short-lived identity token that authenticates the end user before the session starts. Your backend mints the token with the Ada Platform API, then your app passes it here. See Authenticate end users for the setup flow.
Token handling rules:
- Tokens are single use and expire after 15 minutes. Mint a fresh token for each new
AdaWebHost. - The SDK delivers the token to the web runtime through a one-time injected configuration object at document start. The token never appears in a URL, so it stays out of request logs.
- The SDK holds the token in memory only. It is never persisted to disk.
- The SDK remembers when the runtime has consumed the token. If the host rebuilds or reloads its WebView, the spent token is not delivered again. Create a new host with a newly minted token to re-authenticate.
- Exchange failures surface as the
ada:identity_token:errorandada:identity_token:expiredevents.
Never log the identity token. Never store it in UserDefaults, files, or analytics payloads.
This setting applies only when webSdk is .messaging. The legacy runtime ignores it.
language
language: String = ""
Sets the initial display language. To use the same language for AI Agent replies, first turn languages on in your Ada dashboard. Go to Customization > Languages. See Support multiple languages in the same AI Agent for more information.
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.
metafields
metafields: [String: Any] = [:]
Use metafields to pass information about a user to Ada at initialization. This can be useful for tracking information about your customers, as well as personalizing their experience.
To change these values after initialization, use the setMetaFields action.
navigationBarOpaqueBackground
navigationBarOpaqueBackground: Bool = false
When set to true, the modal presentation uses a full-screen style with an opaque, light-gray navigation bar and status bar. Applies to launchModalWebSupport only.
openWebLinksInSafari
openWebLinksInSafari: Bool = false
External web links open by default in-app, via SFSafariViewController. To open external links in the Safari browser, pass openWebLinksInSafari: true.
sensitiveMetafields
sensitiveMetafields: [String: Any] = [:]
Use this parameter to pass sensitive meta information about an end user. This works like metafields but provides an added layer of security.
The SDK forwards these fields at initialization, so an identified session carries them from the first message. 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.
To change these values after initialization, use the setSensitiveMetaFields action.
styles
styles: String = ""
Passes style overrides to the web runtime. The value’s meaning depends on webSdk:
.legacy: a CSS style override string..messaging: no effect. The runtime ignores the value and logs a warning.
version
version: String = ""
Pins the legacy runtime’s chat bundle to a specific build. Used for pre-release verification with your Ada team. Leave blank for the stable rollout. Ignored when webSdk is not .legacy.
webSdk
webSdk: AdaWebSdk = .legacy
Selects which web runtime the WebView mounts. See AdaWebSdk.
.legacy(the default) keeps the runtime the previousAdaEmbedFrameworkSDK loaded, so migrating apps see no behavior change..messagingmounts the Messaging runtime.headless,identityToken,enableProgrammaticControl, andsendMessagerequire it.
Set an explicit environment when you select .messaging.
webViewLoadingErrorCallback
webViewLoadingErrorCallback: ((Error) -> Void)? = nil
Called when the WebView fails to load. Receives an AdaWebHostError: .webViewTimeout when loading exceeds webViewTimeout, or .webViewFailedToLoad for navigation failures.
webViewTimeout
webViewTimeout: Double = 30.0
The number of seconds the SDK waits for the WebView to load before it stops loading and calls webViewLoadingErrorCallback with .webViewTimeout.
zdChatterAuthCallback
zdChatterAuthCallback: ((@escaping (_ token: String) -> Void) -> Void)? = nil
Use zdChatterAuthCallback to authenticate Zendesk Chat and Zendesk Messaging Handoffs.
For Zendesk Messaging, select the Messaging runtime. Request a JWT from your server and pass it to the callback.
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 adaWebHost.reset() so the next user starts a new conversation and a new Zendesk user.
See Authenticate end users for signing key setup.
Session persistence
The web runtime keeps the working copy of session state inside the WebView’s web storage. From version 1.3.0, the SDK also stores a session mirror in the Keychain. If the end user force-quits the app, the SDK restores the session from the session mirror on the next launch. The restored session includes active live agent handoff context. The native side also caches a small allowlist of cosmetic state, with a 10 minute expiry, to smooth the next launch.
Session persistence has these properties:
- The session mirror follows your AI Agent’s persistence setting. The
normalpersistence mode writes the session mirror. Thesessionandprivatepersistence modes clear the session mirror, so the SDK writes no session mirror in these modes. - The session mirror is this-device-only. The Keychain entry does not sync to iCloud and does not transfer to another device.
- The session does not survive an app uninstall. This behavior is deliberate. After a reinstall, a first-run check wipes old Keychain entries, and the SDK starts a fresh session.
- An
identityTokenalways takes precedence. If you supply a token at start or atreset, the SDK performs the identity exchange first. The resolved session replaces any previously persisted session.
Session persistence shows no end-user prompts, permission dialogs, or biometric sheets. It requires no new host-app permissions. The SDK never persists identity tokens to disk.
Clear the session when an end user signs out of your app. Sessions now survive an app restart. If your sign-out flow does not clear the session, the next user of the device can resume the previous user’s conversation. Call reset, deleteHistory, or clearPersistedState when the end user signs out.
Events
Pass an eventCallbacks dictionary at initialization to receive runtime events.
The delivery contract:
- Each callback receives one
[String: Any]dictionary. event["event_name"]is the event key as aString.event["data"]carries the event payload when the runtime sends one.- The callback registered under the exact event key fires first, then the callback registered under
"*"fires with the same event. - The
"*"callback receives every event the runtime emits, including keys not listed below.
The dictionary holds one closure per key. To register several subscribers for the same key, or to add and remove subscribers after initialization, use addEventCallback and addSdkEventCallback instead. Subscribers registered that way also receive the ada.bridge.error and ada.webview.* events under their own keys, not only under "*".
The ada:message:sent and ada:message:received events are delivered only when the host was created with enableProgrammaticControl: true.
Common event keys, in alphabetical order:
Headless session lifecycle
A headless host is an offscreen integration, not a background service. The following constraints are firm:
- No background execution. iOS suspends the WebView’s content process when the app is suspended. Events do not arrive while the app is not running. Use push notifications through
setDeviceTokenfor delivery outside the app lifecycle. - App termination ends the runtime. When the app terminates, the WebView and its in-memory state are gone. On the next launch, the session rehydrates from the runtime’s own web persistence, or from the session mirror.
- Tokens are never persisted natively.
identityTokenis held in memory and consumed once by the runtime. Mint a fresh token for each new host. - One WebView per host. Each
AdaWebHostowns one WebView. Retain the host for as long as you need the session. Releasing it stops event delivery. - Keep the container out of user interaction. A hidden or zero-sized container is fine. WebKit can throttle rendering for offscreen views; command dispatch and event delivery still work.
To show the Ada UI later, create a new AdaWebHost without headless and present it with one of the launch actions. The conversation continues because the runtime persists session state in web storage.
Actions
Use the actions below in conjunction with settings to customize the behavior of your AI Agent in an iOS app. On the Messaging runtime, actions called before the runtime is ready are queued and dispatched when sdk.ready fires.
addEventCallback
addEventCallback(_ eventName: String = "*", callback: @escaping (_ event: [String: Any]) -> Void) -> AdaEventSubscription
Registers a callback for one event key, or for every event with the default "*" key. Unlike the eventCallbacks dictionary, which holds one closure per key, any number of callbacks can subscribe to the same event, and you can subscribe after initialization. Returns an AdaEventSubscription token. Pass the token to removeEventCallback to unsubscribe.
Subscribers registered this way also receive the ada.bridge.error and ada.webview.* events under their own keys.
addSdkEventCallback
addSdkEventCallback(_ callback: @escaping (_ key: String, _ data: String?) -> Void) -> AdaEventSubscription
Registers a raw sink that receives every event as its key plus its JSON-encoded data. Use it to forward events without knowing the keys in advance. Returns an AdaEventSubscription token for removeSdkEventCallback.
clearPersistedState
clearPersistedState()
Removes the natively persisted state. This includes the allowlisted, non-sensitive startup and branding state in UserDefaults. From version 1.3.0, it also includes the persisted session mirror in the Keychain. Call it when an end user signs out. The next WebView session starts without rehydrated state. See Session persistence.
The method returns no result. To confirm the wipe, use clearPersistedStateDurably.
The call does not touch the web runtime’s own storage. To clear the conversation itself, use deleteHistory or reset.
clearPersistedStateDurably
clearPersistedStateDurably() -> Bool
Removes the same natively persisted state as clearPersistedState, and returns the result. The method returns false when the SDK could not confirm the session-mirror wipe in the Keychain. If the method returns false, call it again.
This method blocks the calling thread. AdaWebHost runs on the main actor, so the blocked thread is the main thread. The block lasts until the wipe completes or a timeout of about 3 seconds elapses. Use clearPersistedStateDurably(completion:) instead, unless your sign-out flow needs the result inline. The method does not touch the web runtime’s own storage.
clearPersistedStateDurably(completion:)
clearPersistedStateDurably(completion: @escaping @MainActor @Sendable (Bool) -> Void)
Removes the same natively persisted state as clearPersistedState. The SDK calls completion on the main actor with the result. The method does not block. The result is false when the SDK could not confirm the session-mirror wipe in the Keychain. If the result is false, call the method again. Prefer this form for a sign-out on the main actor.
deleteHistory
deleteHistory()
Deletes the record used to fetch conversation logs for an end user from local storage. When the user opens a new chat window, a new user record will be created.
launchHeadlessWebSupport
launchHeadlessWebSupport(in hostView: UIView? = nil)
Runs the web runtime without presenting any Ada UI. Attaches the WebView to hostView when one is supplied (keep it hidden or zero-sized), or to an internal hidden zero-sized container otherwise.
Requirements and behavior:
- Requires
webSdk: .messaging. Calling it on a legacy host stops the program with a precondition failure, matching the Android SDK’s headless factory. - Forces
headlesstotrue. When the host was created withheadless: false, the SDK rebuilds the WebView so the runtime loads in headless mode. Setheadless: trueat initialization to avoid the extra load.
Drive the conversation natively through eventCallbacks and sendMessage. See Headless session lifecycle.
launchInjectingWebSupport
launchInjectingWebSupport(into view: UIView)
Launches Ada chat into a specified subview.
launchModalWebSupport
launchModalWebSupport(from viewController: UIViewController)
Launches Ada chat in a modal view over top of your current view.
launchNavWebSupport
launchNavWebSupport(from navController: UINavigationController)
Pushes a view containing Ada chat to the top of your navigation stack.
removeEventCallback
removeEventCallback(_ subscription: AdaEventSubscription)
Removes exactly the callback that addEventCallback returned the subscription for. Unknown subscriptions are a no-op.
removeEventCallbacks
removeEventCallbacks(_ eventName: String = "*")
Removes every callback registered through addEventCallback for one event key, or for "*" by default.
removeSdkEventCallback
removeSdkEventCallback(_ subscription: AdaEventSubscription)
Removes the raw sink that addSdkEventCallback returned the subscription for.
reset
Creates a new end user and refreshes the chat, optionally with a new language, greeting, and metadata. Overloads exist with only metaFields, only sensitiveMetaFields, or neither.
resetChatHistory is tri-state: true and false are sent to the runtime explicitly, while nil omits the value so the runtime’s own default applies. The parameter defaults to true.
A reset overload that takes plain dictionaries still exists for backward compatibility but is deprecated. Use the MetaFields.Builder overloads for all new code.
sendMessage
sendMessage(_ body: String)
Sends a message from the end user into the conversation. Use this to drive the conversation from your own native UI.
Requirements and behavior:
- Requires
webSdk: .messaging. On the legacy runtime the call is dropped with a debug log. - Requires
enableProgrammaticControl: true. Without it, the runtime rejects the command withProgrammaticControlNotEnabled. - Calls made before the runtime is ready are queued and dispatched when
sdk.readyfires.
setDeviceToken
setDeviceToken(deviceToken: String)
Sets or rotates the APNs device token used for push notifications. Safe to call before the runtime is ready; the SDK delivers the latest token once the runtime signals sdk.ready.
setLanguage
setLanguage(language: String)
Changes the language in chat programmatically. Use this action, rather than the language setting, to change the chat language without clearing the chat history. Language codes must use a lowercase, two-letter code, in ISO 639-1 language format.
Before using setLanguage, you must turn languages on in your Ada dashboard. Go to Customization > Languages. See Support multiple languages in the same AI Agent for more information.
setMetaFields
setMetaFields(builder: MetaFields.Builder)
Sets metadata for an end user after initialization. This is useful if you need to update user data after Ada has already launched. See also metafields.
A setMetaFields(_:) overload that takes a plain dictionary still exists for backward compatibility but is deprecated. Use MetaFields.Builder for all new code.
setSensitiveMetaFields
setSensitiveMetaFields(builder: MetaFields.Builder)
Sets sensitive metadata for an end user after initialization. This works like setMetaFields and is useful for passing more private and sensitive information. See also sensitiveMetafields.
A setSensitiveMetaFields(_:) overload that takes a plain dictionary still exists for backward compatibility but is deprecated. Use MetaFields.Builder for all new code.
Curated bridge requests
AdaWebHost exposes a fixed set of methods that ask the running chat for state or drive it. Each method takes a completion closure. The closure receives one AdaBridgeRequestResult. That result is .success(Any?), .unsupported, or .failure(String).
A method reports .unsupported when the running runtime build does not implement it. A method reports .failure in any of three cases:
- 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.
Reads return public models only. No read returns sensitive meta fields, the internal stores, or persisted session data. Writes and triggers succeed with a nil value.
Calls made before the runtime is ready are queued and dispatched when the runtime becomes ready. Reads take a required completion closure. Writes and triggers take an optional completion closure. Only the message reads getConversation and getMessages require enableProgrammaticControl. That setting defaults to false. The other reads, writes, and triggers do not. The default differs per platform. React Native defaults it to true. There the same two reads resolve without the flag.
Types
AdaEnvironment
AdaEnvironment selects the deployment environment that hosts the WebView entry page and SDK assets.
AdaEventSubscription
An opaque token returned by addEventCallback and addSdkEventCallback. Keep it to remove the subscription later with removeEventCallback or removeSdkEventCallback.
AdaWebHostError
AdaWebHost.AdaWebHostError is the error type passed to webViewLoadingErrorCallback.
AdaWebSdk
AdaWebSdk selects which web runtime the WebView mounts. See webSdk.
MetaFields.Builder
MetaFields.Builder builds the metadata payload for setMetaFields, setSensitiveMetaFields, and reset. setField(key:value:) accepts String, Bool, Int, Float, and Double values and returns the builder for chaining.