SDK reference
@askdialog/dialog-sdk is the core SDK for embedding Dialog in custom stacks. It handles communication with the Dialog API, the assistant lifecycle, tracking, and exposes everything you need to build a UI around it.
Install
Section titled “Install”From npm:
npm install @askdialog/dialog-sdk# orpnpm add @askdialog/dialog-sdk# oryarn add @askdialog/dialog-sdkFrom CDN (no bundler):
<script src="https://d2m6yt8rnm4dos.cloudfront.net/dialog-sdk.X.Y.Z.min.js"></script>When loaded via CDN the SDK is exposed as window.DialogSDK.
Instantiate
Section titled “Instantiate”import { Dialog, type SimplifiedProduct } from '@askdialog/dialog-sdk'
const client = new Dialog({ apiKey: 'YOUR_PUBLIC_API_KEY', locale: 'en', currency: 'USD', callbacks: { addToCart: async ({ productId, quantity, variantId, currency }) => { // Add the product to your cart and update your UI }, changeCartQuantity: async ({ productId, variantId, quantity }) => { // Optional: set that cart line to `quantity` and update your UI }, getProduct: async (productId, variantId): Promise<SimplifiedProduct> => { // Fetch the product from your backend and return it in SimplifiedProduct shape }, },})Constructor options
Section titled “Constructor options”| Option | Type | Required | Description |
|---|---|---|---|
apiKey |
string |
Yes | Your Dialog public API key. |
locale |
string |
Yes | Active locale (e.g. 'en', 'fr', 'es'). |
callbacks.addToCart |
(params) => Promise<void> |
Yes | Called when a user clicks add-to-cart inside the assistant. You handle the actual cart mutation and UI refresh. |
callbacks.getProduct |
(productId, variantId?) => Promise<SimplifiedProduct> |
Yes | Called to render product cards inside the assistant. Return your product in SimplifiedProduct shape. |
callbacks.changeCartQuantity |
(params) => Promise<void> |
No | Called when the shopper steps the quantity of a line the assistant just added. quantity is the line’s new absolute quantity. Omit it and the assistant hides its quantity stepper. |
currency |
string |
Yes | Store currency, ISO 4217 (e.g. 'USD', 'EUR'), independent of the locale. Read back as client.currency; Search uses it to pick the index. |
callbacks.addToCart |
(params) => Promise<void> |
No | Called when a user clicks add-to-cart inside the assistant. You handle the actual cart mutation and UI refresh. |
callbacks.getProduct |
(productId, variantId?) => Promise<SimplifiedProduct> |
No | Called to render product cards inside the assistant. Return your product in SimplifiedProduct shape. |
theme |
Theme |
No | Override visual theme (colors, fonts, CTA shape). |
userId |
string |
No | Stable user ID for your visitor. If omitted, Dialog auto-generates one and persists it. |
product |
{ id: string; variantId?: string } |
No | The product of the current page. Grounds questions that carry no product of their own (floating bookmark, resume surface, free text) on the product being viewed. See Declaring the current product. |
disableAddToCart |
boolean |
No | Hides Dialog add-to-cart for this widget instance/session (default false). See “Disabling add-to-cart” below. |
analyticsConsent |
'granted' |
No | Declares the analytics consent as granted, for sites with no cookie banner. Omitted by default. See Declaring the analytics consent. |
callbacks can be omitted in a search-only integration (see Search): only the assistant needs them, and the client’s getProduct() and addToCart() throw a configuration error when their callback is missing.
Disabling add-to-cart
Section titled “Disabling add-to-cart”Set disableAddToCart: true to suppress Dialog add-to-cart for a specific session, for example a B2B storefront that hides purchasing actions when a B2B customer is logged in. Evaluate your own condition at initialization:
const client = new Dialog({ apiKey: 'YOUR_PUBLIC_API_KEY', locale: 'en', currency: 'USD', disableAddToCart: isB2BCustomerLoggedIn, // per session callbacks: { /* ... */ },})When enabled:
- the assistant hides the add-to-cart CTA on recommendation and conversational product cards;
callbacks.addToCartis never called and no add-to-cart event is tracked;- product links and recommendation browsing stay available.
Omit it (or set false) to keep the current behavior. The flag is read at initialization, so it applies for the lifetime of that widget instance (a login-state change takes effect on the next page load).
Declaring the analytics consent
Section titled “Declaring the analytics consent”By default the assistant sends analytics events (add-to-cart, checkout, assistant usage) only once it detects a consent signal on the page: Google Consent Mode, TCF v2 or OneTrust. A site with no cookie banner emits no such signal, so no event is sent for any of its visitors and the dashboard stays empty.
On those sites, set analyticsConsent: 'granted':
const client = new Dialog({ apiKey: 'YOUR_PUBLIC_API_KEY', locale: 'en', currency: 'USD', analyticsConsent: 'granted', // no cookie banner on this site callbacks: { /* ... */ },})The option works like a Google Consent Mode default state:
- analytics is on from the first page view, for every visitor;
- a refusal coming from a consent platform present on the page still wins: a Google Consent Mode
updateset todenied, or OneTrust loaded without the performance group (C0002), turns analytics off for that visitor; window.dialog.audit.consentreportsdetectedCmp: 'declared'when the option is what enabled analytics.
Whether consent can be assumed for your visitors is your compliance decision. Omit the option to keep the default detection.
Declaring the current product
Section titled “Declaring the current product”Pass product on product pages so the assistant always knows which product the visitor is looking at. Questions asked without an explicit product (from the floating bookmark, the resume surface or the free-text input) are then answered in the context of that product, including after the visitor navigates from one product page to another:
const client = new Dialog({ apiKey: 'YOUR_PUBLIC_API_KEY', locale: 'en', currency: 'USD', product: { id: 'product-123', variantId: 'variant-456' }, // variantId optional callbacks: { /* ... */ },})On single-page storefronts, update the declaration on client-side navigation:
client.setCurrentProduct('product-456', 'variant-789') // variantId optionalclient.clearCurrentProduct() // left for a non-product pageThe id must match the product ID of your Dialog catalog feed. Without a declared product, questions asked outside a product click are answered without product context.
Load Dialog on every page
Section titled “Load Dialog on every page”Because your code initializes Dialog, it must run on every route of your store, not only product, listing, and home pages. Two things depend on Dialog being present on the page:
- Proactive surfaces (Smart Discovery’s modal and AI bar) only appear where Dialog is loaded, so a configuration targeting content pages never fires if the SDK isn’t initialized there, even when its URL pattern matches.
- Tracking (sessions, add-to-cart, checkout) is captured only on pages where Dialog runs: routes without it silently drop analytics.
A common mistake is wiring initialization only into product, listing, and home page flows. Initialize Dialog globally instead (e.g. in a shared layout or root template), so it runs on every page type.
Sending messages
Section titled “Sending messages”With product context
Section titled “With product context”client.sendProductMessage({ question: 'Is this top runs small?', productId: 'product-123', productTitle: 'Linen V-neck top', selectedVariantId: 'variant-456', // optional})Without product context
Section titled “Without product context”client.sendGenericMessage({ question: 'What is your return policy?',})Fetching suggestions
Section titled “Fetching suggestions”Get the AI-generated suggestion list for a given product. Useful if you build a custom suggestions UI on your PDP rather than using our DialogProductBlock component.
const suggestions = await client.getSuggestions('product-123')// {// questions: [{ question: '...' }, ...],// assistantName: 'Your expert',// inputPlaceholder: 'Ask any question...',// description: 'Ask any question about this product'// }Locale information
Section titled “Locale information”const info = client.getLocalizationInformations()// { countryCode: 'US', formatted: 'en-US', language: 'English', locale: 'en' }Search
Section titled “Search”The SDK runs Dialog Search, the keyword search over your catalog. The React and Vue components and the REST endpoint are covered in the Search integration guide.
Index names
Section titled “Index names”Search reads one index per language and currency. Build the names with searchIndexName(index, language, currency):
import { searchIndexName } from '@askdialog/dialog-sdk'
searchIndexName('products', 'fr', 'EUR') // 'products_fr_eur'index:'products','collections','articles'or'pages'.language: lowercase ISO 639-1 code ('fr'). A regional locale such as'fr-FR'throws.currency: ISO 4217 code ('EUR'), lowercased in the name.
client.search()
Section titled “client.search()”client.search(request, options?) sends one request to the search API, as is: no debounce, no cancellation of outdated requests, no analytics. Use it for one-off searches; for a search field, use createSearchController.
const response = await client.search({ requests: [ { indexName: searchIndexName('products', 'en', client.currency), query: 'running shoes', page: 0, // optional, zero-based (default 0) hitsPerPage: 20, // optional, 1 to 100 (default 20) }, ],})// response.results[0].hits: [{ objectID, title?, url?, handle?, imageUrl?, priceRange? }]options.signal (an AbortSignal) cancels the request, which then rejects with the native AbortError. An HTTP error rejects with DialogSearchError (status and message). The request and response fields are detailed in the REST endpoint reference.
createSearchController
Section titled “createSearchController”createSearchController(options) runs an interactive search: it debounces keystrokes, cancels outdated requests and ignores their late responses, paginates, retries, and records search analytics (result impressions and clicks). It renders nothing: you subscribe to its state and render the results.
import { createSearchController, Dialog, SearchStatus } from '@askdialog/dialog-sdk'
const client = new Dialog({ apiKey: 'YOUR_PUBLIC_API_KEY', locale: 'en-US', currency: 'USD' })
const controller = createSearchController({ search: (request, options) => client.search(request, options), language: 'en', currency: client.currency, analytics: { surface: 'search_page', trackViewSearchResults: (params) => client.trackViewSearchResults(params), trackSelectSearchResult: (params) => client.trackSelectSearchResult(params), }, navigate: (url) => router.push(url), // optional sections: [{ index: 'collections', hitsPerPage: 5 }], // optional})
const unsubscribe = controller.subscribe((state) => { if (state.status === SearchStatus.SUCCESS) { renderCards(state.response.hits).forEach((card, index) => { controller.observeResult(card, index) card.onclick = (event) => { if (controller.selectResult(index)) event.preventDefault() } }) }})
input.oninput = () => controller.setQuery(input.value)form.onsubmit = (event) => { event.preventDefault() controller.submit(input.value)}nextButton.onclick = () => controller.setPage(controller.getState().page + 1)
// On unmountcontroller.dispose()language is the ISO 639-1 part of the client’s locale ('en' for 'en-US'): pass it explicitly, a regional locale is rejected.
Options
Section titled “Options”Options are fixed when the controller is created: create a new controller to change the language or the currency.
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
search |
(request, options?) => Promise<SearchResponse> |
Yes | - | Sends a request. Pass client.search, bound to the client, or your own transport. |
language |
string |
Yes | - | Lowercase ISO 639-1 code, e.g. 'en'. |
currency |
string |
Yes | - | ISO 4217 code, e.g. client.currency. |
analytics |
SearchControllerAnalytics |
Yes | - | { surface, trackViewSearchResults, trackSelectSearchResult }. surface is where results are displayed: 'search_page', 'autocomplete', 'smart_discovery' or 'ai_bar'. Pass the client’s trackViewSearchResults and trackSelectSearchResult. |
navigate |
(url, hit) => void |
No | - | Router adapter, called after a selection is recorded. Omit it to let your result links navigate natively. |
debounceMs |
number |
No | 250 |
Keystroke debounce, in milliseconds. |
hitsPerPage |
number |
No | 12 |
Products per page. |
sections |
SearchSection[] or () => SearchSection[] |
No | [] |
Extra indices searched alongside the products, e.g. [{ index: 'collections', hitsPerPage: 5 }]. Only request an index your catalog has: a missing one fails the whole search. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
setQuery(query) |
Searches after the debounce delay. A query under 2 characters (after trimming) resets the state to idle. |
submit(query) |
Searches immediately. |
setPage(page) |
Loads a zero-based page of the current query. A new query always starts at page 0. |
retry() |
Replays the last request, when the state is error. |
observeResult(element, index) |
Records the impression of state.response.hits[index] once element is visible. |
selectResult(index, options?) |
Records the click on state.response.hits[index], then calls navigate. Returns true when navigate ran: call preventDefault() on the click then. Pass { navigate: false } for middle-clicks and modified clicks. |
subscribe(listener) |
Calls listener(state) on every state change. Returns the unsubscribe function. |
getState() |
Returns the current state. |
dispose() |
Cancels pending requests and removes listeners and observers. |
| Field | Type | Description |
|---|---|---|
status |
'idle' | 'loading' | 'success' | 'empty' | 'error' |
empty is a successful search with no result. Compare with the SearchStatus constants. |
query |
string |
Last query searched. |
page |
number |
Zero-based page of the last request. |
response |
SearchResult |
Optional. Products result: hits, nbHits, page, nbPages, hitsPerPage, query, queryID. Kept while loading, cleared on error. |
sections |
object |
Optional. Results of the extra indices, keyed by index (state.sections?.collections). |
error |
unknown |
Optional. The error of the last request, when status is error. |
Tracking
Section titled “Tracking”The SDK auto-tracks assistant interactions (open / close / message / add-to-cart from assistant). Use the methods below for events that happen outside the assistant.
Manual add-to-cart and checkout
Section titled “Manual add-to-cart and checkout”client.registerAddToCartEvent({ productId: 'product-123', quantity: 1, currency: 'EUR', variantId: 'variant-456', price: 29.99,})
client.registerSubmitCheckoutEvent({ productId: 'product-123', quantity: 1, currency: 'EUR', variantId: 'variant-456',})Call these whenever the customer adds to cart or completes checkout without going through the Dialog assistant, so the dashboard can attribute conversion correctly. See Tracking: SDK custom for full guidance.
Listening to assistant events
Section titled “Listening to assistant events”const unsubscribe = client.onAssistantEvent((event) => { // event.type, event.payload})
// Laterunsubscribe()Available event types (full guidance in Tracking: SDK custom):
userOpenedAssistantuserClosedAssistantuserSentMessageuserClickedOnProductCarduserOpenedRecommendationuserAddedToCartuserSendPositiveFeedbackuserSendNegativeFeedback
Pass a theme object on construction:
const client = new Dialog({ apiKey: 'YOUR_PUBLIC_API_KEY', locale: 'en', currency: 'USD', theme: { backgroundColor: '#ffffff', primaryColor: '#000000', ctaTextColor: '#ffffff', ctaBorderType: 'rounded', // 'straight' | 'rounded' capitalizeCtas: false, fontFamily: 'Inter, sans-serif', highlightProductName: true, }, callbacks: { /* ... */ },})The title, description, and content keys on theme only apply to the Vue / React components. The vanilla SDK doesn’t render those (you do).
SimplifiedProduct shape
Section titled “SimplifiedProduct shape”Your getProduct callback must return this shape:
interface SimplifiedProduct { id: string title: string handle: string descriptionHtml?: string url?: string totalInventory: number featuredImage?: { url?: string } | null variants: SimplifiedProductVariant[] options?: SimplifiedProductOption[]}
interface SimplifiedProductVariant { id: string displayName?: string inventoryQuantity?: number price: string // string, e.g. '29.99' currencyCode: string // ISO code, e.g. 'USD' compareAtPrice?: string | null url?: string selectedOptions?: { name: string; value: string }[] image?: { url?: string } | null}
interface SimplifiedProductOption { id: string name: string position: number values: string[]}Next steps
Section titled “Next steps”- React components: drop-in UI with the SDK.
- Vue components: same, for Vue 3.
- Install Search on a headless storefront: Search with the SDK, the components or the REST endpoint.
- Tracking SDK custom: full tracking guidance for the SDK path.
- Add-to-cart issues: common UI-sync patterns.
