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 Ada dashboard, go to Channels > Chat and 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.

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

deviceToken

deviceToken: String = ""

The APNs device token for push notifications. The SDK sends it to the runtime when the runtime becomes ready. To set or rotate the token after initialization, use setDeviceToken.

domain

domain: String = ""

The Ada domain your AI Agent is served from.

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

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:sent and ada:message:received events in eventCallbacks.

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.

Swift
1let adaWebHost = AdaWebHost(
2 handle: "my-agent",
3 eventCallbacks: [
4 "ada:message:received": { event in
5 // A message arrived from the AI Agent or a human agent.
6 },
7 "*": { event in
8 // Every event, keyed by event["event_name"].
9 }
10 ],
11 environment: .production,
12 webSdk: .messaging,
13 enableProgrammaticControl: true
14)

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:error and ada:identity_token:expired events.

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 = ""

Takes in a language code to programmatically set the AI Agent language. You must first turn languages on in your Ada dashboard. Go to Customization > Languages. See Support multiple languages in the same AI Agent for more information.

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.

Swift
1lazy var adaWebHost = AdaWebHost(handle: "my-agent", metafields: ["tier": "pro"])

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.

preprodDemoToken

preprodDemoToken: String = ""

A time-bound access token for Messaging pre-production assets. Applied only when environment is .preprod and webSdk is .messaging. Used for pre-release testing with your Ada team; leave blank otherwise.

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. 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: a JSON object of string style tokens, for example "{\"tintColor\": \"#520497\"}". The runtime honors tintColor only today, and ignores unsupported keys. A value that is not a JSON object of string values is dropped with a debug log.

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.

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 the zdChatterAuthCallback to request a JWT token from your API, then pass it to Ada. This creates shared trust between Ada and Zendesk, and in turn allows for verifiable end user identity.

Swift
1lazy var adaWebHost = AdaWebHost(handle: "my-agent", zdChatterAuthCallback: { callback in
2 // Request JWT from your API
3 // Then...
4 callback("your.JWT")
5})

zdChatterAuthCallback is available only for Zendesk Chat. It is not available for Zendesk Messaging.

Session persistence

The SDK stores session state inside the WebView’s web storage. The native side caches only a small allowlist of cosmetic state, with a 10 minute expiry, to smooth the next launch.

On iOS, WebView storage persistence across app restarts is not guaranteed. Session state may or may not survive depending on OS storage management, and should not be relied upon for maintaining live agent handoff state.

The SDK never persists tokens or credentials to platform-native storage such as Keychain or UserDefaults. If your app requires guaranteed session continuity across app restarts, you need to implement your own native storage management. See the Apple developer documentation on Keychain Services.

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 a String.
  • 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:

Event keyFires when
ada.bridge.errorThe native bridge hits an error, such as an SDK load failure. Delivered to the "*" callback only, with the message in event["error"].
ada.webview.loadedThe WebView finishes loading its page, with the loaded url. Delivered to the "*" callback only.
ada.webview.loadFailedThe WebView navigation fails, with the reason in event["error"]. webViewLoadingErrorCallback also fires. Delivered to the "*" callback only.
ada.webview.subresourceLoadFailedA resource inside the Messaging runtime page fails to load, with url, error, and the lowercase tag name in element. Reported once per URL per document. The main frame is intact, so webViewLoadingErrorCallback does not fire. Delivered to the "*" callback only.
ada:agent:joinedA human agent joins the conversation.
ada:agent:leftA human agent leaves the conversation.
ada:chatter_tokenThe runtime issues or adopts an end user token.
ada:connection:changeThe runtime’s connection state changes.
ada:conversation:changeThe active conversation changes.
ada:csat_submittedThe end user submits a satisfaction survey.
ada:end_conversationThe conversation ends.
ada:identity_token:errorThe identityToken exchange fails.
ada:identity_token:expiredThe identityToken is expired or already used.
ada:message:receivedA message arrives from the AI Agent or a human agent. Requires enableProgrammaticControl.
ada:message:sentThe end user sends a message. Requires enableProgrammaticControl.
ada:typing:startThe other party starts typing.
ada:typing:stopThe other party stops typing.
sdk.readyThe runtime is ready to accept commands. The event also carries event["web_sdk"] with the active runtime name.

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 setDeviceToken for 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 inside the new WebView.
  • Tokens are never persisted natively. identityToken is held in memory and consumed once by the runtime. Mint a fresh token for each new host.
  • One WebView per host. Each AdaWebHost owns 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.

Swift
1let subscription = adaWebHost.addEventCallback("ada:message:received") { event in
2 // A message arrived from the AI Agent or a human agent.
3}

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.

Swift
1let subscription = adaWebHost.addSdkEventCallback { key, data in
2 analytics.track(key, payload: data)
3}

clearPersistedState

clearPersistedState()

Removes the natively persisted state cache: the allowlisted, non-sensitive startup and branding state in UserDefaults. Call it when an end user signs out. The next WebView session starts without rehydrated state. See Session persistence.

The call does not touch the web runtime’s own storage. To clear the conversation itself, use deleteHistory or reset.

Swift
1adaWebHost.clearPersistedState()

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.

Swift
1adaWebHost.deleteHistory()

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 headless to true. When the host was created with headless: false, the SDK rebuilds the WebView so the runtime loads in headless mode. Set headless: true at initialization to avoid the extra load.

Drive the conversation natively through eventCallbacks and sendMessage. See Headless session lifecycle.

Swift
1// Offscreen: the SDK creates and retains a hidden container.
2adaWebHost.launchHeadlessWebSupport()
3
4// Or attach to your own container. Keep it hidden or zero-sized.
5adaWebHost.launchHeadlessWebSupport(in: myHiddenContainerView)

launchInjectingWebSupport

launchInjectingWebSupport(into view: UIView)

Launches Ada chat into a specified subview.

Swift
1adaWebHost.launchInjectingWebSupport(into: injectingView)

launchModalWebSupport

launchModalWebSupport(from viewController: UIViewController)

Launches Ada chat in a modal view over top of your current view.

Swift
1adaWebHost.launchModalWebSupport(from: self)

launchNavWebSupport

launchNavWebSupport(from navController: UINavigationController)

Pushes a view containing Ada chat to the top of your navigation stack.

Swift
1adaWebHost.launchNavWebSupport(from: navigationController)

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

Swift
1reset(
2 language: String? = nil,
3 greeting: String? = nil,
4 metaFields: MetaFields.Builder,
5 sensitiveMetaFields: MetaFields.Builder,
6 resetChatHistory: Bool? = true
7)

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.

Swift
1adaWebHost.reset(
2 language: "en",
3 metaFields: publicFields,
4 sensitiveMetaFields: sensitiveFields,
5 resetChatHistory: true
6)

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.

Swift
1adaWebHost.sendMessage("Where is my order?")

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 with ProgrammaticControlNotEnabled.
  • Calls made before the runtime is ready are queued and dispatched when sdk.ready fires.

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.

Swift
1adaWebHost.setDeviceToken(deviceToken: "apns-device-token")

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.

Swift
1adaWebHost.setLanguage(language: "fr")

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.

Swift
1let publicFields = MetaFields.Builder()
2 .setField(key: "firstName", value: "Jane")
3 .setField(key: "tier", value: "pro")
4
5adaWebHost.setMetaFields(builder: publicFields)

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.

Swift
1let sensitiveFields = MetaFields.Builder()
2 .setField(key: "authToken", value: "secure-session-token")
3
4adaWebHost.setSensitiveMetaFields(builder: sensitiveFields)

A setSensitiveMetaFields(_:) overload that takes a plain dictionary still exists for backward compatibility but is deprecated. Use MetaFields.Builder for all new code.

Types

AdaEnvironment

AdaEnvironment selects the deployment environment that hosts the WebView entry page and SDK assets.

CaseDescription
.productionProduction assets. Use this for production apps.
.preprod(branch: String = "main")Pre-production assets, for pre-release testing with your Ada team.
.local(port: Int = 4900)Local development against a local assets server.
.custom(assetsOrigin: URL)A custom CDN origin that serves the 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.

CaseDescription
.webViewFailedToLoadThe WebView navigation failed.
.webViewTimeoutThe WebView did not finish loading within webViewTimeout seconds.

AdaWebSdk

AdaWebSdk selects which web runtime the WebView mounts. See webSdk.

CaseDescription
.legacyThe runtime the previous AdaEmbedFramework SDK loaded. The default.
.messagingThe Messaging runtime. Required for headless, identityToken, and sendMessage.

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.

Swift
1let fields = MetaFields.Builder()
2 .setField(key: "plan", value: "pro")
3 .setField(key: "signedIn", value: true)
4 .setField(key: "seats", value: 5)