SDK API Reference

The Messaging Web SDK exposes an adaEmbed interface with corresponding settings and actions. Get the interface from loadAdaMessaging in the npm package, from createAdaEmbedInterface in the module script, or from the window.adaEmbed global that the Chat SDK script tag continues to provide.

All three paths return the same interface. The window.adaEmbed global remains fully supported for existing installs, but is deprecated for new installations, which should hold the interface in a private scope instead. See Security best practices. The examples on this page call window.adaEmbed for brevity; substitute your own scoped reference.

Settings

Configure the SDK by passing a settings object to start or to loadAdaMessaging:

JavaScript
1await window.adaEmbed.start({
2 handle: "<your-handle>",
3 language: "fr",
4});

Pages that load the SDK through the legacy script tag can keep defining a window.adaSettings object before the script loads. Both forms accept the same settings, and window.adaSettings remains fully supported for existing installs. For new installations it is deprecated: pass settings to start() or loadAdaMessaging instead. See Security best practices.

Settings merge in priority order: values passed to start(settings) override window.adaSettings. A few newer settings are read only from start(settings) and not from window.adaSettings; each one is marked below.

The following are all of the available settings for the Messaging Web SDK.

adaReadyCallback

adaReadyCallback?(params: { isRolledOut: boolean }): void;

Specifies a callback function that the SDK calls when it has finished setting up. isRolledOut is false when the browser session falls outside the configured rollout percentage; in that case the widget does not render.

HTML
1<script type="text/javascript">
2 window.adaSettings = {
3 adaReadyCallback: ({ isRolledOut }) => {
4 console.log("Ada is ready. Rolled out:", isRolledOut);
5 }
6 }
7</script>

The equivalent event is ada:start, which delivers the same { isRolledOut } payload to subscribers.

align

align?: "right" | "left" | "auto";

Sets the side of the page that the launcher button and the chat drawer anchor to. Defaults to "right". With "auto", the SDK anchors left when the configured language is Arabic (ar) or Hebrew (he), and right otherwise.

allowMetaFieldsInReset

allowMetaFieldsInReset?: boolean;

When set to true, a full reset({ metaFields }) may apply caller-supplied meta fields to the new session. Defaults to false, so a script running in your page (for example, from the browser console) cannot inject or override meta fields by calling reset(). The value is locked on the first configuration and cannot be changed at runtime.

History-preserving resets (resetChatHistory: false) apply reset meta fields regardless of this setting, because the current end user session survives the reset.

appUrl

appUrl?: string;

URL of a customer-hosted conversation app that the SDK mounts in place of Ada’s default conversation UI.

Your handle’s Allowed websites list controls custom apps. In your Ada dashboard, go to Channels > Chat and add your app’s origin. A URL on an origin that the list does not allow is dropped with a console warning, and the default app mounts instead. An empty list disables custom apps for the handle. For local development, a loopback appUrl is allowed implicitly when the page that embeds the widget also runs on a loopback host, so pure local development needs no entry. A deployed page gets no implicit loopback allowance: expose your development server through an https: tunnel and add the tunnel origin to Allowed websites, because the dashboard accepts only https:// entries. Chromium 142 and later, and Firefox 149 and later, also gate the loopback navigation behind a Local Network Access permission prompt. The SDK delegates that permission down its frame chain for a loopback appUrl, and never for other values. Set appUrl in the settings that the page starts with. Click Allow when the browser asks. A missing or denied permission surfaces as a handshake_timeout fallback. The https: tunnel path needs no permission and works in every browser. See Local development.

The value must be an absolute https: URL without embedded credentials, on an origin you control. For local development, http: is accepted on loopback hosts such as localhost and 127.0.0.1. Any other value (non-loopback http:, javascript:, data:, relative, credentialed, or on an Ada-hosted origin such as *.ada.support) is dropped with a console warning, and the default app mounts instead. The SDK validates the URL again inside its core frame, so the check cannot be bypassed from the page. The core-frame check also rejects a URL on the Messaging frame’s own origin, and enforces the Allowed websites check after the handle’s configuration loads.

The custom app frame:

  • Runs in a sandboxed iframe with allow-same-origin, so the document keeps its own origin. Cookies and storage work inside the frame, partitioned by the embedding site. See Sandbox, origin, and storage.
  • Receives all conversation state through @ada-cx/messaging-bridge. The SDK never appends query parameters or tokens to a custom app URL.
  • Must complete the bridge app.initialize handshake within 15 seconds of the iframe loading. The handshake requires document.referrer: the SDK mounts the frame with referrerpolicy="origin", so your app document always receives the Messaging frame’s origin, and never its full URL. This includes apps served over http: on a loopback host during local development. A browser extension or proxy that strips the Referer header entirely breaks the handshake, and the SDK falls back to the default app.
  • Stays pinned to its first document. A navigation or reload, even to the same origin, disconnects the bridge permanently.

When the custom frame fails to load or complete its handshake, or when its origin is not allowed by your handle’s Allowed websites list, the SDK publishes the ada.customApp.fallback event with { appUrl, reason, code, retryable } and logs a console warning with the reason. It destroys the failed frame and mounts the default app in its place. After one of these fallbacks, the SDK stays on the default app for the rest of the page’s lifetime. Set appUrlFallback to false to fail closed instead.

One fallback reason is transient: the handle’s configuration did not load in time to verify the Allowed websites list. That fallback applies only to the one mount attempt. The next mount after a reset() checks the loaded list again.

appUrl and appUrlFallback are locked on the first configuration. A runtime re-configuration or reset() cannot redirect the app frame to a different URL.

JavaScript
1await window.adaEmbed.start({
2 handle: "<your-handle>",
3 appUrl: "https://chat-app.example.com/ada-frame/",
4});
5
6window.adaEmbed.subscribeEvent("ada.customApp.fallback", ({ appUrl, code, reason }) => {
7 console.log("Custom app fell back to default:", appUrl, code, reason);
8});

This setting is read only from start(settings) or the loadAdaMessaging settings object. It is not read from window.adaSettings.

appUrlFallback

appUrlFallback?: boolean;

Controls what happens when a custom appUrl frame fails to load, fails its bridge handshake, or fails the Allowed websites check. It also applies when your handle’s configuration does not load in time to verify the Allowed websites list. Defaults to true, which mounts Ada’s default app in place of the failed custom frame.

When set to false, the SDK does not fall back. The activation fails through the normal activation error path, and later activation attempts retry the custom URL until three consecutive default-app failures latch the activation. The ada.activation.error event’s data then carries a code field with the same values as the ada.customApp.fallback event. In fail-closed mode, the next activation retries every cause, including origin_not_allowlisted. The retryable flag exists only on the fallback event.

Only meaningful together with appUrl. Like appUrl, this setting is read only from start(settings), not from window.adaSettings, and is locked on the first configuration.

chatterTokenCallback

chatterTokenCallback?(chatterToken: string): void;

Specifies a callback for when the end user token has been set. The equivalent event is ada:chatter_token.

cluster

cluster?: string | null;

Specifies the regional cluster your AI Agent runs on. Accepts either a regional segment (for example, "eu") that the SDK combines with domain, or a full base domain (for example, "eu.ada.support") used as-is.

Set this only if your Agent is hosted on a non-default cluster. If the Agent is on the default cluster, leave this unset.

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

conversationEndCallback

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

Specifies a callback function that the SDK calls when the end user ends the conversation. The callback receives the same payload as the ada:end_conversation event.

HTML
1<script type="text/javascript">
2window.adaSettings = {
3 conversationEndCallback: (event) => {
4 // perform an action after the end user has ended the conversation
5 }
6};
7</script>

crossWindowPersistence

crossWindowPersistence?: boolean;

Persists the chat drawer open state across page refreshes and tabs while a live agent conversation is active, using the Window.sessionStorage API. When the browser is closed, the state is forgotten. Has no effect in headless or parentElement mode.

Defaults to true. Set to false to disable.

On the legacy Chat SDK this behavior was opt-in. On the Messaging SDK it is on by default.

domain

domain?: string;

Overrides the Ada base-domain segment (for example, "ada"). The SDK combines it with handle and any regional cluster into the API host https://<handle>.[<cluster>.]<domain>.support. For a full URL override, use endpoint instead.

Unless directed by an Ada team member, you do not need to change this value.

enableProgrammaticControl

enableProgrammaticControl?: boolean;

Opt-in to the transcript-bearing programmatic surface. When set to true, your page can:

While the flag is false (the default), those methods reject with ProgrammaticControlNotEnabled and the events are not delivered to host subscribers. The value is locked on the first configuration and cannot be changed at runtime.

Every script that lives in your host page (analytics tags, GTM, ad pixels, session replay tools, and any third-party SaaS pixel) inherits your page’s trust and can subscribe to these events or call these methods. They will see full message bodies, including any PII your end users type. Have your product and security teams accept that exposure risk explicitly before turning this on.

JavaScript
1await window.adaEmbed.start({
2 handle: "<your-handle>",
3 enableProgrammaticControl: true,
4});

endpoint

endpoint?: string;

Full base URL for the Ada API. Overrides all default host derivation from handle, cluster, and domain.

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

eventCallbacks

eventCallbacks?: Record<string, AdaSdkEventCallback>;

A map of event key to callback, registered eagerly before the first startup event fires. Two kinds of keys are supported:

  • Public ada:* event keys, registered exactly like subscribeEvent subscriptions.
  • Custom JavaScript event names configured in your Ada dashboard, keyed by the event’s event_name. The key "*" receives every custom JavaScript event.
JavaScript
1await window.adaEmbed.start({
2 handle: "<your-handle>",
3 eventCallbacks: {
4 "ada:end_conversation": (data) => console.log("Conversation ended", data),
5 my_custom_event: (data) => console.log("Custom JS event", data),
6 },
7});

greeting

greeting?: string;

Customizes the greeting that new end users see. The value is the response id of the Answer to trigger, which you can find in the URL of the corresponding Answer in the dashboard. This is useful for setting page-specific greetings across your app.

handle

handle?: string;

Your AI Agent’s handle. Required: pass it in start(settings), in the loadAdaMessaging settings, or in window.adaSettings. Pages migrating from the Chat SDK script tag can keep the data-handle attribute on that script.

headless

headless?: boolean;

When set to true, the SDK connects to the AI Agent in the background without rendering the default launcher button, intro popup, or chat drawer. Use this when your page renders its own chat UI and drives the conversation through sendMessage, getMessages, getConversation, and subscribeEvent.

Headless sessions are typically paired with enableProgrammaticControl: true. Without it, the methods needed to drive a custom UI reject at runtime.

Methods that act on the built-in UI are not available in headless mode:

  • setComposerText rejects with HeadlessModeError. There is no built-in composer to write to.
  • toggle, open, and close are no-ops. There is no drawer to open or close.
  • isOpen always resolves false.

In headless mode, call start to activate the session, or let the first sendMessage activate it for you.

Headless sessions run with no visual indicator. The end user token is created and persisted to local storage the same way as a visible session. If your page is compromised, an attacker can run conversation activity under the visiting user’s token without any user-facing signal. Host pages should treat enabling headless as a meaningful trust decision.

JavaScript
1await window.adaEmbed.start({
2 handle: "<your-handle>",
3 headless: true,
4 enableProgrammaticControl: true,
5});

hideMask

hideMask?: boolean;

Controls the page mask behind the open drawer on desktop. By default, no mask appears, and users can interact with your page while the chat window is open.

Set hideMask to false to show the mask. The mask dims your page, and a click on it minimizes the drawer instead of reaching the page.

Leave hideMask unset, or set it to true, when users need to navigate the page while the chat window is open.

identityToken

identityToken?: string;

A short-lived, single-use identity token that your backend mints through Ada’s Platform API for a known end user. Pass it here to start an identified session instead of an anonymous one. See the identity guide for the full flow.

How the exchange works:

  • The SDK exchanges the token once with the AI Agent backend, before it restores any persisted session state. The exchange request carries the token in the JSON body as identity_token. The token never appears in a URL.
  • The token is one-shot. After a successful exchange, the SDK clears its cached copy and the server will not accept the same token again. A later reset() without a new token starts an anonymous session.
  • To identify a new user (for example, after a login change), pass a fresh token to reset({ identityToken }). A reset that carries an identity token is always a full reset.

On exchange failure, the SDK clears identity-sensitive storage and continues with an anonymous session. It publishes ada:identity_token:error with a reason such as identity_token_expired, invalid_identity_token, identity_token_already_used, or identity_token_exchange_failed. An expired token additionally publishes ada:identity_token:expired.

JavaScript
1const { token } = await fetchIdentityTokenFromYourBackend();
2
3await window.adaEmbed.start({
4 handle: "<your-handle>",
5 identityToken: token,
6});
7
8window.adaEmbed.subscribeEvent("ada:identity_token:error", (data) => {
9 console.warn("Identity exchange failed:", data.reason);
10});

language

language?: string;

Sets the language for your AI Agent. Takes a language code in ISO 639-1 format, for example "fr".

You must first turn languages on in your dashboard, under Customization > Languages. See Support multiple languages in the same AI Agent.

Alternatively, you can use the setLanguage action, which changes the language without clearing the chat history.

lazy

lazy?: boolean;

When set to true, prevents the AI Agent from loading until the adaEmbed.start(...) method is called.

metaFields

metaFields?: Record<string, MetaFieldValue>;

Use metaFields to pass information about an end user to Ada. This can be useful for tracking information about your users, as well as personalizing their experience. For example, you may wish to track the phone_number and name for conversation attribution. (See Variables for more information.)

Values must be a string, number, boolean, or null. The SDK accepts up to 50 entries, keys up to 256 characters, and string values up to 1024 characters. Entries beyond those limits are dropped or truncated with a console notice.

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

JavaScript
1await window.adaEmbed.start({
2 handle: "<your-handle>",
3 metaFields: {
4 phone_number: "(123) 456-7890",
5 name: "Ada Lovelace",
6 },
7});

Meta field keys should not include whitespace, emojis, special characters, or periods.

onAdaEmbedLoaded

onAdaEmbedLoaded?(): void;

Called when the embed interface is ready to be used, before startup events fire. This is useful for subscribing to events. Subscribing here ensures that subscriptions are in place before events are triggered.

HTML
1<script type="text/javascript">
2window.adaSettings = {
3 onAdaEmbedLoaded: () => {
4 window.adaEmbed.subscribeEvent("ada:ready", (data) => {
5 console.log("Chat is ready in mode:", data.mode);
6 });
7 }
8};
9</script>

The equivalent event is ada:embed_loaded.

parentElement

parentElement?: string | HTMLElement;

Specifies where to mount the conversation frame if the default side drawer is not desired. Accepts the HTMLElement or element id of the desired parent element.

HTML
1<head>
2 <!-- ... -->
3 <script type="text/javascript">
4 window.adaSettings = {
5 parentElement: "custom-iframe"
6 }
7 </script>
8</head>
9<body>
10 <!-- ... -->
11 <div id="custom-iframe"></div>
12</body>

In parentElement mode, toggle throws, and open and close do not show or hide a drawer. The WindowInfo field isDrawerOpen is always false.

Chat renders immediately inside the parentElement provided. This means that the conversation also gets initialized. Avoid initializing the SDK with the parentElement setting automatically on every page, since it could lead to low engagement rates.

privateMode

privateMode?: boolean;

Puts the SDK into private mode when set to true. In private mode, the SDK forgets conversation history on refresh. This is effectively the same as setting customer persistence to Forget After Reload.

rolloutOverride

rolloutOverride?: number;

Overrides the rollout value set in the dashboard for this session. Useful if you need page-specific rollout values, or together with testMode to always show the widget. For testing and QA purposes only.

Accepts a fraction between 0 and 1. For backward compatibility, a window.adaSettings value above 1 is treated as a legacy percentage (for example, 50 becomes 0.5).

sensitiveMetaFields

sensitiveMetaFields?: Record<string, MetaFieldValue>;

Like metaFields, you can use sensitiveMetaFields to pass information about an end user to Ada. With sensitiveMetaFields, however, values are:

  • encrypted immediately upon entering the Ada system
  • temporarily stored in a cache on the Ada side, that is cleared after 24 hours
  • not stored in the database
  • redacted on the dashboard

Sensitive values are delivered over the SDK’s secure storage transport and are never readable back through getMetaFields.

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

JavaScript
1await window.adaEmbed.start({
2 handle: "<your-handle>",
3 sensitiveMetaFields: {
4 jwt_token: "xxxxx.yyyyy.zzzzz",
5 },
6});

Meta field keys should not include whitespace, emojis, special characters, or periods.

showFallbackOnTimeout

showFallbackOnTimeout?: boolean;

When true (the default), the SDK shows a self-contained fallback document in the chat frame if chat activation exceeds the timeout budget and no ada:chat_frame_timeout subscriber has taken over handling. Set to false to suppress the built-in fallback and handle timeouts yourself.

styles

styles?: Record<string, string>;

Named style overrides for the widget. The supported key is tintColor, which accepts a 3- or 6-digit hex color and overrides the dashboard tint.

JavaScript
1await window.adaEmbed.start({
2 handle: "<your-handle>",
3 styles: { tintColor: "#1a73e8" },
4});

Values that are not valid hex colors are ignored with a console notice. Style overrides require the UI Customization feature; without it, applied keys are ignored with a console notice.

The legacy CSS-string form of styles is not supported on the Messaging SDK. Only the named-override object form applies.

testMode

testMode?: boolean;

Marks the end user as a test user. The session keeps the real transport and backend; the SDK stamps the test_user: 1 meta variable on the session so analytics can exclude it. Rollout percentage still applies; set rolloutOverride to 1 to always show the widget.

theme

theme?: "light" | "dark" | "auto";

Color scheme for the chat widget. When set to "auto" (the default), the widget follows the user’s OS preference via prefers-color-scheme. This overrides the server-configured theme. Change it at runtime with setTheme.

This setting is read only from start(settings) or the loadAdaMessaging settings object. It is not read from window.adaSettings.

toggleCallback

toggleCallback?(isDrawerOpen: boolean): void;

Use this setting to trigger side effects when the chat drawer is opened or closed. The equivalent event is ada:toggle.

zdChatterAuthCallback

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

Use zdChatterAuthCallback for Zendesk end user authentication. This setting allows you 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 within the context of a chat session.

JavaScript
1window.adaSettings = {
2 handle: "<your-handle>",
3 zdChatterAuthCallback: (callback) => {
4 // Request a fresh JWT token, then pass it to Ada
5 const token = "token goes here";
6 callback(token);
7 }
8};

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

Actions

You can call all of the following actions on the adaEmbed interface. Every action returns a Promise. Except for start, subscribeEvent, subscribeAll, unsubscribeEvent, and setDelegate, actions reject until start() has run, with the message Actions cannot be called until Embed has been instantiated. Try running adaEmbed.start({...}).

The Messaging SDK supports generative AI Agents only. The scripted-campaign actions createProactive, triggerCampaign, and evaluateCampaignConditions are deprecated: calling them still resolves, but has no effect and logs a console warning. To start a proactive conversation, use triggerProactive.

close

close(): Promise<void>;

Closes the chat drawer and restores the launcher button. A no-op when the chat is already closed, in headless mode, and in parentElement mode.

Closing through this action reports the ada:minimize_chat event, matching the drawer’s minimize control. The ada:close_chat event is reserved for the end user explicitly ending the chat.

closeCampaign

closeCampaign(): Promise<void>;

Closes the currently displayed proactive message bubble. Does nothing if no proactive bubble is currently displayed.

createProactive

createProactive(body: string, duration?: number, responseId?: string): Promise<void>;

This action is deprecated on the Messaging SDK. Calling it resolves, but has no effect, and logs the console warning createProactive() is deprecated and not supported. Messaging supports only generative features; scripted/declarative campaigns and Answers are ignored. Use triggerProactive instead.

deleteHistory

deleteHistory(): Promise<void>;

Permanently deletes the end user’s conversation history and persisted state, and resets the session. When the end user opens a new chat window, a new end user token is generated. The promise resolves once the SDK confirms the persisted clear is durable.

destroy

destroy(): Promise<void>;

Tears down all SDK frames, channels, and listeners, and clears every event subscription and the delegate. Use stop instead when you plan to start again and want subscriptions to survive.

evaluateCampaignConditions

evaluateCampaignConditions(options?: Record<string, unknown>): Promise<void>;

This action is deprecated on the Messaging SDK. Calling it resolves, but has no effect, and logs the console warning evaluateCampaignConditions() is deprecated and not supported. Messaging supports only generative features; scripted/declarative campaigns and Answers are ignored. Use triggerProactive instead.

getConversation

getConversation(): Promise<ConversationInfo>;

Returns information about the active conversation: its id (or null if the end user has not sent or received any messages yet) and the live agent handoff state. See ConversationInfo for the full shape.

Requires enableProgrammaticControl: true. Otherwise rejects with ProgrammaticControlNotEnabled. Rejects with a timeout error when the chat frame does not respond in time.

JavaScript
1const conversation = await window.adaEmbed.getConversation();
2console.log("Conversation id:", conversation.id);
3if (conversation.handoff.inLiveChat) {
4 console.log("Talking to agent:", conversation.handoff.agent?.name);
5}

getInfo

getInfo(): Promise<WindowInfo>;

Returns a WindowInfo object containing information about the current client state.

JavaScript
1const windowInfo = await window.adaEmbed.getInfo();
2console.log("Is the drawer open?", windowInfo.isDrawerOpen ? "Yes" : "No");

getMessages

getMessages(): Promise<PublicMessage[]>;

Returns the messages currently held in the chat session, in the order they were sent. See PublicMessage for the field shape.

Requires enableProgrammaticControl: true. Otherwise rejects with ProgrammaticControlNotEnabled.

Important behaviors:

  • In-memory only. This is the transcript the SDK holds for the current end user. There is no server-side history endpoint or pagination. Refreshing the page resets the list to whatever the SDK rehydrates from the persisted session.
  • Filtered to conversational messages. Presence notifications (typing, conversation-ended), system events, and other non-conversational entries are excluded. Every returned message has one of the role values documented in PublicMessage.
JavaScript
1const messages = await window.adaEmbed.getMessages();
2messages.forEach((m) => console.log(`[${m.role}] ${m.body ?? "<no body>"}`));

getMetaFields

getMetaFields(): Promise<Record<string, MetaFieldValue>>;

Returns the non-sensitive meta fields currently set on the active session: the values passed in settings plus any subsequent setMetaFields updates. Sensitive meta fields are never returned.

JavaScript
1const meta = await window.adaEmbed.getMetaFields();

handleNotification

handleNotification(): Promise<void>;

Opens the chat drawer in response to a notification the host page handled itself, for example a push notification tap. A no-op in headless mode.

On the legacy Chat SDK, this action toggled the drawer only when the chat was closed. On the Messaging SDK it calls open unconditionally, which is a no-op when the drawer is already open. The end state is the same.

isOpen

isOpen(): Promise<boolean>;

Resolves to true when the chat is currently visible to the end user, and false otherwise. Always resolves false in headless mode.

JavaScript
1if (!(await window.adaEmbed.isOpen())) {
2 window.adaEmbed.toggle();
3}

open

open(): Promise<void>;

Opens the chat drawer. A no-op when the chat is already open and in headless mode. When lazy is set and the client has not initialized yet, calling open() triggers initialization first.

JavaScript
1await window.adaEmbed.open();

requestNotifications

requestNotifications(): Promise<NotificationPermission | null>;

Requests browser web-notification permission. Call it from a user gesture, such as a button click, per browser policy. Resolves the resulting permission ("granted", "denied", or "default"), or null when the browser does not support the Notification API.

Once granted, the widget shows a browser notification for new live agent messages while the page is hidden or the chat is closed. Clicking the notification focuses the window, opens the chat, and publishes the ada:web_notification:click event.

JavaScript
1enableNotificationsButton.onclick = async () => {
2 const permission = await window.adaEmbed.requestNotifications();
3 console.log("Notification permission:", permission);
4};

reset

reset(resetParams?: ResetParams): Promise<void>;

Resets the session. By default this clears the history and creates a new end user; pass resetChatHistory: false to update configuration while keeping the history and the current end user. See ResetParams for all options.

JavaScript
1await window.adaEmbed.reset({
2 language: "fr",
3});

Behaviors to know:

  • Caller-supplied metaFields apply on a full reset only when the host opted in with allowMetaFieldsInReset. History-preserving resets always apply them.
  • Passing identityToken starts a new identified session and always forces a full reset. See identityToken.
  • The promise resolves on the SDK’s confirmation. Full resets wait for the persisted conversation clear to be durable.

sendMessage

sendMessage(text: string): Promise<SendMessageResult>;

Sends a message to the AI Agent on behalf of the end user. Resolves with the new message’s id, which matches the id on the same message in getMessages and in the ada:message:sent event payload.

Requires enableProgrammaticControl: true. Otherwise rejects with ProgrammaticControlNotEnabled.

Sending opens the chat drawer if it is not already visible. In headless mode, sending activates the session in the background instead. If the conversation has not started, the auto-greeting is skipped and the message starts the conversation.

Possible rejections:

  • sendMessage requires non-empty text: text is empty, whitespace-only, or not a string.
  • DelegateRejected: a registered beforeSend hook returned false.
  • DelegateTimeout: the beforeSend hook did not resolve within 5 seconds.
  • sendMessage rejected by chat: <CODE>: chat-side validation rejected the message. Codes include TOO_LONG (exceeds the 500-character message cap), RATE_LIMITED (a previous send was less than 200 ms ago), EMPTY_TEXT, and DISPATCH_FAILED.
  • sendMessage cancelled: the session changed before it could be sent: a reset() or identity change superseded the send.
  • A timeout error when the chat frame does not respond in time.

To attach metadata to the conversation, use setMetaFields before calling sendMessage.

JavaScript
1const { id } = await window.adaEmbed.sendMessage("What is your refund policy?");
2console.log("Sent message id:", id);

setComposerText

setComposerText(text: string): Promise<void>;

Pre-fills the chat composer with text without sending it. The end user can still edit or clear the text before sending.

Requires enableProgrammaticControl: true. Otherwise rejects with ProgrammaticControlNotEnabled. Not available in headless mode (rejects with HeadlessModeError). Rejects with setComposerText rejected by chat: TOO_LONG if text exceeds the composer’s 500-character cap.

JavaScript
1window.adaEmbed.setComposerText("Hello, I'd like to ask about ");

setDelegate

setDelegate(delegate: Delegate | null | undefined): void;

Registers a beforeSend hook that runs on outgoing messages sent via sendMessage. Use it to transform, cancel, or pass the message through.

Requires enableProgrammaticControl: true. Called after start(), it throws synchronously with ProgrammaticControlNotEnabled when the gate is off. Called before start(), the delegate is queued; if the gate turns out to be off at start time, the SDK logs a warning and does not apply it.

The hook fires only for programmatic sendMessage() calls. Messages typed into the chat composer are sent through a separate path and do not flow through beforeSend. Do not rely on this hook as a moderation or PII-redaction gate for composer input.

The hook receives { text: string } (not a full PublicMessage) and returns one of:

  • A modified { text: string } to change what is sent.
  • false (or a Promise resolving to false) to cancel. sendMessage rejects with DelegateRejected.
  • The input unchanged to pass through.

The hook can be synchronous or asynchronous. It is bounded by a 5-second timeout; a slow or never-resolving delegate causes sendMessage to reject with DelegateTimeout. The transformed text is re-validated: returning { text: "" } or { text: " " } causes sendMessage to reject, and the message is not sent.

Pass null or undefined to clear the delegate.

JavaScript
1window.adaEmbed.setDelegate({
2 beforeSend: ({ text }) => {
3 if (text.toLowerCase().includes("secret")) return false;
4 return { text: text.trim() };
5 },
6});

See Delegate for the type shape.

setDeviceToken

setDeviceToken(token: string): Promise<void>;

Registers a device push-notification token (from APNs or FCM) for the active end user. An empty or whitespace-only token is ignored. Primarily used by the mobile SDK wrappers.

JavaScript
1await window.adaEmbed.setDeviceToken("fcm-device-token-here");

setLanguage

setLanguage(language: string): Promise<void>;

Changes the conversation language programmatically. Use this action, rather than the language setting, to change the language without clearing the chat history. Language codes use ISO 639-1 format, for example en, fr, ar.

JavaScript
1await window.adaEmbed.setLanguage("fr");

You must first turn languages on in your Ada dashboard, under Customization > Languages. See Support multiple languages in the same AI Agent.

On the legacy Chat SDK, setLanguage threw when the chat frame was not ready yet. On the Messaging SDK, the call is queued and applied when the frame is ready; it does not throw. A host that relied on catching the “not ready” error should stop doing so.

setMetaFields

setMetaFields(fields: Record<string, MetaFieldValue>): Promise<void>;

Updates metaFields after setup. In most situations, the metaFields setting is enough for user attribution. However, in cases where the chat remains open while page changes occur (like in single-page applications), this method may be useful.

The same value rules and limits as the metaFields setting apply.

JavaScript
1await window.adaEmbed.setMetaFields({
2 phone_number: "(123) 456-7890",
3 name: "Ada Lovelace",
4});

Meta field keys should not include whitespace, emojis, special characters, or periods.

setSensitiveMetaFields

setSensitiveMetaFields(fields: Record<string, MetaFieldValue>): Promise<void>;

Updates sensitiveMetaFields after setup. The values are not stored in the database and are deleted after 24 hours.

JavaScript
1await window.adaEmbed.setSensitiveMetaFields({
2 jwt_token: "xxxxx.yyyyy.zzzzz",
3});

Meta field keys should not include whitespace, emojis, special characters, or periods.

setTestModeBanner

setTestModeBanner(label: string | null): Promise<void>;

Shows a test-mode banner with the given label, or removes it with null. This action exists for the Ada dashboard’s test surface; host pages do not normally call it.

setTheme

setTheme(theme: "light" | "dark" | "auto"): Promise<void>;

Changes the chat widget’s color scheme at runtime. Takes effect immediately, without a reset or reload. "auto" follows the user’s OS preference.

JavaScript
1await window.adaEmbed.setTheme("dark");

start

start(settings?: AdaMessagingStartOptions): Promise<void>;

Initializes the SDK on your page with the merged settings: window.adaSettings first, then any settings passed to createAdaEmbedInterface or loadAdaMessaging, then this call’s settings on top. handle is required unless it was already provided.

AdaMessagingStartOptions accepts everything listed in the Settings section.

JavaScript
1await window.adaEmbed.start({
2 handle: "<your-handle>",
3 language: "fr",
4});

Rejections:

  • AdaEmbedError with code start_already_active when the SDK has already been started. Call stop first to restart.
  • AdaEmbedError with code start_interrupted when a callback stops the SDK while the start is still in progress.
  • AdaEmbedError with code start_owner_conflict when a different adaEmbed interface already runs on the page. Only one interface can own a page. Stop the other interface first. loadAdaMessaging is memoized and reuses one interface, so repeated calls never trigger this. See One interface per page.
  • An error asking for a handle when none was provided anywhere.

In headless and parentElement modes, start() also activates the conversation session, because those modes have no launcher gesture.

stop

stop(): Promise<void>;

Removes the SDK from your page and tears down its frames. A later start can run again. Event subscriptions made through subscribeEvent and subscribeAll survive a stop and replay onto the next started client; a delegate set with setDelegate does not.

subscribeAll

subscribeAll(callback: (eventKey: string, data: unknown) => void): Promise<number>;

Subscribes to every broadcast event with a single callback. The callback receives the event key and the event data. Resolves a subscription id for unsubscribeEvent.

This action is designed for bridge adapters, such as native wrappers, that forward SDK events wholesale.

The transcript-bearing events ada:message:sent and ada:message:received are never delivered to subscribeAll subscribers. They require exact subscribeEvent subscriptions, so transcript data is not exposed to generic host-page listeners.

JavaScript
1const id = await window.adaEmbed.subscribeAll((eventKey, data) => {
2 console.log("Ada event:", eventKey, data);
3});

subscribeEvent

subscribeEvent(eventKey: string, callback: (data: unknown, context: { eventKey: string }) => void): Promise<number>;

Certain things in Ada trigger events. Each event consists of an event key and a data payload. Using subscribeEvent, you can define callbacks that are called when a specific event is triggered.

JavaScript
1window.adaEmbed.subscribeEvent("ada:end_conversation", (data) => {
2 console.log("The conversation has ended.");
3});

Callbacks are triggered whenever an event starts with the eventKey provided to subscribeEvent. This means you can subscribe to all events of a certain category. For example, the callback in a subscription to ada:campaigns is called on ada:campaigns:shown, ada:campaigns:engaged, and any other event beginning with ada:campaigns.

Transcript-bearing events are the exception: ada:message:sent and ada:message:received require exact subscriptions to those event keys. They are not delivered through prefix subscriptions such as ada:message or broad listeners such as subscribeAll, so transcript data is not exposed to generic host-page subscribers.

Two arguments are provided to each callback when it is called: data and context.

  • data is specific to each event.
  • context is an object with a single property, the eventKey of the event that triggered the callback.

subscribeEvent resolves a numeric subscriptionId that you can use to unsubscribe later (see unsubscribeEvent). Subscriptions made before start() are queued and replay onto each started client.

It is strongly recommended that you place initial subscriptions in the onAdaEmbedLoaded setting. This ensures that subscriptions are in place before any events are triggered, so that no events are missed.

The following are the events that you can currently subscribe to:

Event keyDataDescription
ada.activation.error{ "error": string, "attempt": number }, plus { "code": string } when a fail-closed custom app mount caused the failureTriggered when a chat activation attempt fails. error is a human-readable message. attempt counts consecutive failures within its own class. The SDK counts a payload that carries code on the separate fail-closed custom-mount budget. The default-app class stops emitting after three consecutive failures. The fail-closed class has no limit of its own, until three consecutive default-app failures latch the activation and stop all attempts. With appUrlFallback set to false, a failed custom appUrl mount surfaces here, and code carries the same stable values as ada.customApp.fallback. A fail-closed custom mount failure during a session resume also triggers this event. A resume-driven event arrives without a preceding ada.activation.started. Branch on code, because both timeout causes share one error message.
ada.customApp.fallback{ "appUrl": string, "reason": string, "code": string, "retryable": boolean }Triggered when the SDK mounts the default app in place of a custom appUrl frame. code names the cause with a stable value: origin_not_allowlisted, allowlist_unavailable, frame_load_failed, or handshake_timeout. retryable is true only for allowlist_unavailable. reason is a human-readable sentence, which the SDK also logs as a console warning. See Watch for fallbacks.
ada:agent:joined{ "conversation_id": string }Triggered whenever a live agent joins the conversation.
ada:agent:left{ "conversation_id": string }Triggered whenever a live agent leaves the conversation.
ada:analytics{ "event": string, "data": object }Triggered for conversation analytics events, including events recorded through trackEvent.
ada:campaigns:dismissed{ "campaignKey": string }Triggered when the end user dismisses a proactive message bubble.
ada:campaigns:engaged{ "campaignKey": string }Triggered when the end user engages the conversation (that is, sends a message) after being shown a proactive message in the same session.
ada:campaigns:opened{ "campaignKey": string }Triggered when chat is opened after a proactive message has been shown.
ada:campaigns:shown{ "campaignKey": string }Triggered when a proactive message bubble is displayed to the end user.
ada:chat_frame_timeout{ "message": string } plus { "frame": string } for a frame-load timeout or { "phase": "activation", "timeoutMs": number } for an activation timeoutTriggered when a chat frame fails to load, or when chat activation exceeds its timeout budget. Use it to build a fallback when chat fails to load. See also showFallbackOnTimeout. On the legacy Chat SDK the payload was null; on the Messaging SDK it carries diagnostic fields.
ada:chatter_tokenThe end user token as a stringTriggered when the end user token becomes available. Also drives chatterTokenCallback.
ada:close_chat{ "conversation_id": string, "is_engaged": boolean }Triggered when the end user explicitly ends or closes the chat with the drawer’s close (X) control, or confirms ending the conversation. is_engaged reports whether the end user sent at least one message.
ada:connection:change{ "state": "connected" | "reconnecting" | "disconnected" }Triggered when the chat connection state changes.
ada:conversation:change{ "id": string }Triggered when the end user moves to a new conversation. Does not fire for the end user’s first conversation; it only fires on transitions between two already-known conversations. To detect every new conversation including the first, listen for both ada:ready and the first ada:message:sent (where role === "user").
ada:conversation:message{ "author": string, "conversation_id": string, "message_id": string }Triggered whenever the end user receives a new message. author reports whether the AI Agent or a live agent sent it, using the inbound role values from PublicMessage. Carries metadata only, never the message body. For full message payloads, use the gated ada:message:received event.
ada:csat_submitted{ "conversation_id": string, "csat_score": number }Triggered when a CSAT survey is submitted. csat_score is omitted when the survey carries no score.
ada:embed_loadedundefinedTriggered once, when the embed interface is ready to be used. A subscriber that registers after the event already fired receives an immediate replay. Also drives onAdaEmbedLoaded.
ada:end_conversation{ "chatter_id": string, "event_data": object }Triggered when the end user ends the conversation. event_data contains conversation information, including chatter_transcript when available.
ada:identity_token:error{ "reason": string }Triggered when an identityToken exchange fails. Reasons include identity_token_expired, invalid_identity_token, identity_token_already_used, and identity_token_exchange_failed. The session continues anonymously.
ada:identity_token:expired{}Triggered, in addition to ada:identity_token:error, when the supplied identity token had already expired.
ada:message:received{ "message": PublicMessage }Triggered for every inbound AI Agent or live agent message. Presence and system notifications are excluded, so the payload’s role is never "user". Requires enableProgrammaticControl: true and an exact subscription to ada:message:received. Privacy: the payload includes the full message body and reaches every host-page subscriber to this exact event key, including third-party scripts.
ada:message:sent{ "message": PublicMessage }Triggered after successful dispatch of an outgoing end user message: composer text, sendMessage, quick replies, and uploads. The payload’s role is always "user"; programmatic sends carry origin: "programmatic". Requires enableProgrammaticControl: true and an exact subscription to ada:message:sent. Privacy: same caveat as ada:message:received.
ada:minimize_chat{ "conversation_id": string, "is_engaged": boolean }Triggered when the end user minimizes the chat drawer, or when the page calls close.
ada:ready{ "mode": "headless" | "visible" }Triggered once, when chat has finished initializing and is ready to accept programmatic calls. Fires before any conversation exists. Register this subscription inside onAdaEmbedLoaded so it is in place before the event fires.
ada:start{ "isRolledOut": boolean }Triggered when the SDK finishes setting up. isRolledOut is false when the session falls outside the configured rollout. Also drives adaReadyCallback.
ada:toggletrue when the drawer opened, false when it closedTriggered when the chat drawer opens or closes. Also drives toggleCallback.
ada:typing:start{ "agentId": string }Triggered during a live agent handoff when the agent starts typing.
ada:typing:stop{ "agentId": string }Triggered during a live agent handoff when the agent stops typing.
ada:web_notification:click{ "conversation_id": string, "message_id": string }Triggered when the end user clicks a browser web notification created after requestNotifications was granted.

toggle

toggle(): Promise<void>;

Opens the chat drawer if it is closed, and closes it if it is open. A no-op in headless mode. Rejects when the parentElement setting is in use.

JavaScript
1await window.adaEmbed.toggle();

trackEvent

trackEvent(eventKey: string, value?: number, meta?: Record<string, unknown>): Promise<void>;

Tracks a business Event for conversation analytics. The arguments of this function are:

  • eventKey: string: the key of the Event to track (required).
  • value?: number: an optional value to assign to the Event. Defaults to 0.
  • meta?: Record<string, unknown>: an optional object containing metadata corresponding to the Event, such as currency, product group, or customer segment. The SDK always stamps the current page URL onto the metadata.
JavaScript
1await window.adaEmbed.trackEvent("Example_Event", 2, {
2 productId: "a1b2c3",
3 customerSegment: "premium",
4});

Tracked events are also re-published to subscribers as ada:analytics events.

On the legacy Chat SDK, value was required. On the Messaging SDK, both value and meta are optional.

triggerAnswer

triggerAnswer(answerId: string): Promise<void>;

Triggers a specific Answer in the conversation. Include the Answer’s response id, which you can find in the URL of the corresponding Answer in the dashboard.

JavaScript
1await window.adaEmbed.triggerAnswer("627d28a9bd9ca9e5337b9763");

triggerCampaign

triggerCampaign(campaignKey: string, options?: Record<string, unknown>): Promise<void>;

This action is deprecated on the Messaging SDK. Calling it resolves, but has no effect, and logs the console warning triggerCampaign() is deprecated and not supported. Messaging supports only generative features; scripted/declarative campaigns and Answers are ignored. Use triggerProactive instead.

triggerGreeting

triggerGreeting(handle?: string): Promise<void>;

Triggers the AI Agent’s configured greeting in the active conversation. handle optionally overrides the configured handle for the greeting.

JavaScript
1await window.adaEmbed.triggerGreeting();

triggerProactive

triggerProactive(messageKeyOrOptions: string | { messageKey: string; params?: Record<string, string> }, params?: Record<string, string>): Promise<void>;

Triggers a proactive conversation using a specified key. This displays a predefined static or template message, where template messages can include dynamic parameters.

Parameters:

NameTypeRequiredDescription
messageKeystringYesThe key identifying the proactive conversation. Must match a predefined static or template message.
paramsRecord<string, string>No (static)
Yes (template)
Key-value pairs for replacing placeholders in template messages. Ignored for static messages.

The Messaging SDK accepts both the object form and a plain string key. The legacy Chat SDK accepted only the object form, so existing calls keep working.

The trigger is ignored while the chat drawer is open. With lazy set, calling triggerProactive initializes the SDK first.

Examples

  1. Triggering a static proactive conversation:
JavaScript
1window.adaEmbed.triggerProactive({
2 messageKey: "static_message_key"
3});
  1. Triggering a template proactive conversation, for example “Hello {{name}}, how can I help you today?”:
JavaScript
1window.adaEmbed.triggerProactive({
2 messageKey: "template_message_key",
3 params: { name: "Ada" }
4});
5
6// -> "Hello Ada, how can I help you today?"

unsubscribeEvent

unsubscribeEvent(subscriptionId: number): Promise<void>;

Removes a subscription created with subscribeEvent or subscribeAll. It takes a single parameter, subscriptionId, which is the id of the subscription to be removed.

JavaScript
1const subscriptionId = await window.adaEmbed.subscribeEvent("ada:ready", (data) => {
2 console.log("Chat is ready in mode:", data.mode);
3});
4
5await window.adaEmbed.unsubscribeEvent(subscriptionId);

Type signatures

Messaging SDK actions commonly use the following type signatures. When you use the @ada-cx/messaging-sdk npm package, import them by these names.

AdaMessagingStartOptions

JavaScript
1{
2 handle?: string;
3 // ...every setting from the Settings section
4}

The object accepted by start and loadAdaMessaging. It extends the settings object with handle, which is required unless it was already provided elsewhere.

AdaSdkEventCallback

JavaScript
1(data: unknown, context: { eventKey: string }) => void

The callback shape for subscribeEvent subscriptions and eventCallbacks entries.

ConversationInfo

JavaScript
1{
2 id: string | null;
3 handoff: {
4 inLiveChat: boolean;
5 agent?: PublicAgentInfo;
6 };
7}

The shape returned by getConversation. id is the id of the active conversation, or null if the end user has not sent or received any messages yet. handoff.agent is populated only during an active live agent handoff.

Delegate

JavaScript
1{
2 beforeSend?: (message: { text: string }) =>
3 { text: string } | false | Promise<{ text: string } | false>;
4}

The object accepted by setDelegate. beforeSend is called for messages sent via sendMessage only (not composer-typed messages). Return { text } to change the message, false to cancel it (causing sendMessage to reject with DelegateRejected), or pass the input through unchanged. Bounded by a 5-second timeout.

MetaFieldValue

JavaScript
1string | number | boolean | null

The value type accepted by metaFields, sensitiveMetaFields, setMetaFields, and setSensitiveMetaFields.

PublicAgentInfo

JavaScript
1{
2 id: string;
3 name: string;
4 avatarUrl?: string;
5}

Basic live agent identity, carried on ConversationInfo and on agent messages in PublicMessage.

PublicMessage

JavaScript
1{
2 id: string;
3 role: "user" | "bot" | "agent";
4 type: string; // "text", "picture", "quick_replies", etc.
5 body?: string; // omitted for non-text messages
6 createdAt: number; // Unix epoch seconds
7 agent?: PublicAgentInfo; // present on agent messages during a live agent handoff
8 data?: Record<string, unknown>; // type-specific extras
9 origin?: "programmatic"; // present on messages sent through sendMessage()
10}

The message shape returned by getMessages and carried in the ada:message:sent and ada:message:received event payloads.

ResetParams

JavaScript
1{
2 greeting?: string | null;
3 greetingResponseId?: string | null;
4 language?: string;
5 metaFields?: Record<string, MetaFieldValue>;
6 sensitiveMetaFields?: Record<string, MetaFieldValue>;
7 identityToken?: string;
8 resetChatHistory?: boolean;
9}

The options accepted by reset. greeting and greetingResponseId both name an Answer response id to trigger after the reset; greeting matches the legacy Chat SDK field. identityToken starts a new identified session and forces a full reset. resetChatHistory: false keeps the conversation history and the current end user.

SendMessageResult

JavaScript
1{
2 id: string;
3}

The result resolved by sendMessage once Messaging accepts the end user message.

WindowInfo

JavaScript
1{
2 hasActiveChatter: boolean;
3 hasClosedChat: boolean;
4 isChatOpen: boolean;
5 isDrawerOpen: boolean;
6}

The shape returned by getInfo. isChatOpen reports whether the chat is visible to the end user. isDrawerOpen reports the floating drawer specifically and is always false in parentElement mode. hasActiveChatter reports whether an end user session exists. hasClosedChat reports whether the end user has previously closed a chat.