iAdvizeDocs

Embed the assistant on your storefront

Paste one script tag to load the assistant. Open it from a floating chat bubble, your own button, or both. No login, works from the site key.

The web tag puts the assistant on your own storefront. You paste one <script> snippet once; it loads a small loader that opens the assistant in a full-height side panel when a shopper triggers it. The panel docks to one edge of the screen and slides in horizontally from that edge. The conversation runs inside a cross-origin iframe served by iAdvize, so no chat content ever touches your page's DOM.

You decide what opens the panel: a floating chat bubble or a centered question bar the loader renders for you (below), a button, a link, or a menu item you already have on the page, or any combination of these. Both built-in surfaces are off by default.

If a technical or SEO review has to clear the tag first, Web tag performance has the weight, the request count, and the layout-shift guarantees.

Install the snippet

Open the site in the dashboard and go to Site settings → Installation. The Install the tag on your site card holds the snippet, already filled in with this site's public key.

Copy the snippet and paste it once into your storefront, ideally just before </body> on every page:

<script>
  ;(function (w, d) {
    w.iadvize =
      w.iadvize ||
      function () {
        ;(w.iadvize.q = w.iadvize.q || []).push(arguments)
      }
    w.iadvize.k = 'pk_site_YOUR_PUBLIC_KEY'
    function l() {
      var s = d.createElement('script')
      s.async = true
      s.src = 'https://tag.iadvize.ai/tag/loader.js'
      d.head.appendChild(s)
    }
    if (d.readyState === 'complete') l()
    else w.addEventListener('load', l)
  })(window, document)
</script>

The snippet defines the window.iadvize command queue, stores your public key, and injects the loader after the page has loaded, so it never competes with your page's first render. Everything heavier (the panel, the iframe) loads later, only when a shopper opens the assistant.

The snippet carries no display option. The side the panel docks to and how it opens are site settings on the Appearance page, which the card links to: change them there, with nothing to recopy.

Copy the dashboard snippet, not this one

The block above shows the shape of the snippet. Copy the real one from the Install the tag card: it carries your site's actual public key. The key (pk_site_…) is a public, non-secret identifier; it's safe to ship in page source.

You don't need to publish your AI Storefront

The web tag works from a key that's minted when the site is created, so the Publish your AI Storefront switch (on the site's Site settings → AI Storefront tab) does not gate it. That switch only controls your AI Storefront, the /s/<key> page we host for your site. You can embed the tag whether or not your AI Storefront is published.

Check that the tag is detected

The Tag detection card on Site settings → Installation shows what AISA last saw on your homepage. Every hour, AISA loads the site's URL and looks for the site key. How the check works lists the requests it makes.

The card shows the page checked, when the tag was last seen on the page, the time of the last check, and one status:

StatusMeans
DetectedThe last check found the key.
Not detected yetThe tag was never found, or no check has run. Install the snippet. AISA starts watching once it has seen the tag once, so a site that never had it opens no alert.
MissingThe tag was seen before, and the last check found a readable page without it. This opens an alert.
Cannot verifyThe last check could not read the page: your site refused or did not answer, or it served a password page or a bot check. No alert is opened or closed. See how to allow the check.
Monitoring offMonitor the tag is off for this site.

Monitor the tag is on by default. Switch it off and AISA stops checking the site, opens no alert and sends no email. If an alert is open for the site, it closes. Like the other switches of the settings tabs, it takes effect when you click Save. It needs the Sites: Edit permission. Without it, the card shows the switch as text and has no Check now button. The same switch is tagMonitoringEnabled on the REST API and the MCP tool set_site_tag_monitoring.

Check now runs the same check as the hourly one, on request, and shows its result in the card. If the first load misses the tag, it loads the page a second time before it says Missing. A site can be checked once a minute: this counts the hourly run too, so a click right after any check shows "Wait N seconds before checking again". The button is disabled when monitoring is off or the site has no URL. The same check is available as POST /api/v1/sites/{siteId}/tag-check and the MCP tool check_site_tag, with the same one-a-minute limit.

Allow the origins that will embed it

The panel only starts a conversation on a page whose origin is on this site's authorized domains list. This is a separate control from your storefront's own Content Security Policy: the panel checks the origin itself, before it will show anything.

Your storefront's own address is covered automatically: a site's URL is required when you create or edit it, and its origin is added to the allowed list for you, marked From site URL and not removable; it stays allowed for as long as it's the site's URL. If you change the URL later, the old origin stays on the list as a regular entry; it's not removed automatically.

To allow additional origins (a staging domain, a second brand site, a subdomain pattern), open Site settings → Installation and use the Authorized domains card:

Type the origin in the field: either an exact one (https://shop.example.com) or a wildcard subdomain pattern (https://*.example.com, which matches any subdomain of example.com at any depth, such as shop.example.com or eu.shop.example.com, but never example.com itself).

Click Add. The origin shows up in the list marked Not saved yet. An entry that isn't a valid origin is refused on the spot, with a message saying what's expected.

Remove an origin you no longer need with the trash icon next to it. Removing a saved origin asks you to confirm first. The one marked From site URL can't be removed this way. Update the site's URL instead if it needs to change.

Click Save at the top right of the page. Nothing on the list changes what the panel accepts until you do: additions are written first, then removals.

If a shopper opens your page on an origin that isn't on the list, the panel doesn't stay blank: it shows an inert box naming the refused origin and pointing back to this setting, so you (or your web team) know exactly what to add.

No authorized domain, no install snippet

The Install the tag on your site card hides its snippet until the site has at least one saved authorized domain, and asks you to add one instead, so you can't paste a snippet that would only ever show that refusal message. A brand-new site already has one, from its required URL.

Open the assistant

Nothing opens the panel on its own. Wire it to one of your own elements, either way:

A data-iadvize-open attribute on any element. The tag listens for clicks anywhere on the page and opens the panel when the click lands on (or inside) an element carrying the attribute:

<button data-iadvize-open>Ask our assistant</button>

A JavaScript call, from your own click handler or component:

iadvize('open')

Opening needs a real click

Both paths require a genuine user gesture. iadvize('open') only opens the panel when it runs inside an active user activation (a click, a tap), so a script can't silently open conversations on page load. A data-iadvize-open click is a gesture by nature, so it always works.

While the panel is loading, it shows an opaque, branded background and a small loading indicator in your text colour instead of a see-through gap. The conversation fades in once it's ready.

Auto-send a first message

A data-iadvize-open element can also send a first message in the same click, opt-in only. A plain data-iadvize-open with neither attribute below keeps working exactly as it does today: opens the panel, sends nothing. Adding this to an existing button changes nothing until you also add one of these two attributes.

<button data-iadvize-open data-iadvize-message="Where's my order?">
  Track my order
</button>

<button data-iadvize-open data-iadvize-auto-send>Track my order</button>
  • data-iadvize-message="…" sends that exact text, whatever the element itself displays. Setting this attribute is itself the opt-in: no second attribute needed.
  • data-iadvize-auto-send (a boolean attribute; its presence is what matters, it needs no value) sends the element's own visible text (textContent, trimmed). Use it when the button or link's label already reads like something a shopper would say.

If an element carries both, data-iadvize-message wins whenever it's non-blank.

Only opt in where the text makes sense as a message

Auto-send sends whatever text resolves: the element's own label, or your override. Tagging a large block of unrelated content with data-iadvize-auto-send sends all of its text (truncated, see below), not just "open."

A few behaviors worth knowing before you wire this up:

  • No resolvable text → open only, plus a console warning. If you opted in (either attribute) but the resolved text is empty (an empty data-iadvize-message="" and no text content, for instance), the panel still opens, nothing is sent, and the loader logs a console.warn so the misconfiguration doesn't pass silently.
  • Long text is truncated. A resolved message longer than roughly 200 characters is cut at the last word boundary before that mark, never mid-word. If there's no word break before the mark (a single very long token, or a script that doesn't use whitespace between words), it falls back to a hard cut at the same length.
  • Every click sends, including a click into a conversation that's already open: there's no "first click only" restriction.
  • A click that lands mid-reply waits its turn. If the assistant is still streaming a response when an opted-in click comes in, the message is held and sent once that response finishes, never at the same time as another message. If the shopper tapped something in the panel during that same response (an Add to cart button, say), that goes first, and the clicked message follows once the assistant has answered it. Only the latest click is held: a second click before the first one's message has gone out replaces it. Stopping the response doesn't cancel the held message.
  • An open question changes the timing. A message held during a response that then ends on a clarifying question keeps waiting, so it doesn't cancel the question. It goes once the shopper answers, skips or closes the question, or types a message of their own, and the assistant has replied. A click made while the question is already on screen goes at once (after any message still waiting) and sets the question aside, as typing would.

Add a floating launcher bubble or a question bar

If you don't want to build your own trigger, turn on one of the loader's own built-in surfaces instead: a floating chat bubble docked to a corner of the screen, or a centered, bottom-docked question bar a shopper can type into directly: sending their first message opens the panel in the same action, no separate click to open it first.

There is a third format, the inline button, which renders inside your own content flow at a point you declare rather than against the viewport. Everything in this section describes the two floating ones; the button behaves differently on three counts: it stays visible while the panel is open, it needs a declared page type, and it needs a mount point in your markup. See The inline button and Place an inline button on your pages.

The dashboard calls it Chat bubble; the API still says launcher

This page's identifiers are unchanged: the launcher key on iadvize('set', …), and the data-iadvize-launcher-host selector in Style engagement widgets with CSS. Only the dashboard's label for that widget format changed, from "Launcher" to "Chat bubble". Nothing to update in your page code.

Both are managed as engagement widgets, on their own dashboard page, not in Site settings anymore, which no longer has anything pointing back to it. Open the site in the dashboard and go to Engagement → Widgets (/dashboard/sites/{siteId}/engagement-widgets), then Add an engagement widget and pick the format from the catalog; see Engagement widgets for the full walkthrough of going live and taking a widget offline, its offsets, its Stacking order, and its page-type targeting. A newly created widget renders nowhere until you go live with its draft; its dashboard page says as much until you have.

Taking a widget offline or putting it back live doesn't change the install snippet: it's the same snippet whether a widget is online or offline. An already-installed tag picks up a change to its widgets on its next page load, with nothing to re-paste on your storefront.

A few things worth knowing about how these behave:

  • A chat bubble's docked side is its own setting, independent of the panel. Set the widget's Position (Left/Right) on its own configuration page; it no longer has to match the panel side set on the Appearance page. A question bar has no side setting; it's always horizontally centered.
  • Both are restylable from the dashboard. Colours, size, corner radius, and shadow are per-widget fields that inherit your site's branding until you override them; a chat bubble additionally picks an icon from a built-in catalogue and can carry an optional per-language text label. See Appearance. Neither renders a remote image, and neither pops up a greeting. The question bar shows a translatable placeholder text in its input (configured per widget; see Engagement widgets) and a send button.
  • You can go further in your own CSS. Both widgets expose a small, supported set of CSS custom properties and shadow parts, so front-end work on your storefront can restyle them beyond the dashboard's fields, with no extra CSP directive. See Style engagement widgets with CSS.
  • Both hide while the panel is open, and reappear when the shopper closes it. An inline button doesn't: hiding it would collapse its box and move your page's content on every open and close.
  • Both step aside while a conversation is in progress. Once the shopper has written in the last 30 minutes and the panel is closed, the tag shows the Panel reduced state button instead of any chat bubble or question bar.
  • Page-type targeting decides where either can show. A widget with no page types selected never renders at all. See Page-type targeting for exactly how the allow-list works. This only hides the widget; if a conversation is already open on that page, it isn't closed. checkout is not a page type, so there is no way to hide a widget from a payment page by page type. See Keep the assistant off a payment page.
  • Both fail closed. A widget only ever appears once the loader has successfully fetched this site's config. If that request fails or is blocked (a flaky connection, an ad blocker, whatever the cause), the page shows no chat bubble or question bar for that visit, with no retry and no fallback to a previous value. Nothing else about the tag depends on this fetch, so the rest of the panel keeps working either way.
  • You can enable more than one, of either type. Each enabled widget renders as its own independent surface with its own offsets and stacking order. See Multiple widgets on one site.
  • The page-side launcher override only ever targets launcher widgets. The iadvize('set', { launcher: … }) command below (predating the question bar) has no equivalent for it: there's no page-side way to suppress or reconfigure a question bar outside the dashboard.

Override it from your own page

A page-side call always beats the dashboard configuration, whichever arrives first:

iadvize('set', { launcher: true }) // or false
iadvize('set', { launcher: { enabled: false } })
iadvize('set', { launcher: { offsetBottom: 80, offsetSide: 16 } })

Pass true/false to override just whether it shows, or an object to touch enabled/offsetBottom/offsetSide individually; any field you leave out keeps its current value. Those three are the whole list: appearance isn't settable from the page. Colours, size, corner radius, shadow, icon, and label come from the widget's Appearance fields, or from your own CSS. An offset passed here also wins at every screen size, including below the 768px breakpoint where a widget's narrow-screen offsets would otherwise apply. This is a single, blanket override: it applies the same way across every launcher widget on the site, not one widget at a time. Unlike position/backdrop, this can be called again at any time, including after the panel is already open, so you can suppress every launcher bubble on specific routes of a single-page app without touching the dashboard configuration.

Why an admin might see enabled widgets but no bubble

A page-side iadvize('set', { launcher: … }) call always wins over the dashboard configuration, regardless of which one arrives first. If a widget is enabled and targeted at the right page type on the Engagement Widgets page but doesn't show on a given page, check that page's own code for a launcher override before assuming the configuration didn't save.

The AI disclosure only reaches shoppers on hover, not on touch

The bubble carries iAdvize's fixed AI-transparency line ("You're chatting with an AI assistant…") as its accessible name and as a native title tooltip. This text isn't something you write or edit. aria-label is what reaches assistive technology, and it's always there. The title tooltip is different: like every native tooltip, it only appears on mouse hover, and it never appears at all on a touch device: there's no touch equivalent of hovering, so a shopper on a phone or tablet never sees it, no matter how long they press.

Don't rely on the tooltip as your only disclosure

If most of your traffic is mobile, the launcher's title effectively reaches nobody before they tap it. This is a permanent limitation of how browsers handle title, not a bug we plan to fix. Treat the launcher's tooltip as a bonus for desktop/mouse visitors, not your disclosure mechanism. The disclosure every shopper actually sees, on any device, is the one already built into the conversation itself, as the first line once the panel opens.

How the panel takes your brand

The conversation panel is drawn from your site's brand identity and nothing else. There is no extra setting: set your colours once and every part of the panel follows, in the embed, on the public link and in the playground.

  • Buttons (send, Add to cart, Next and Submit on a clarifying question) use your primary colour, with a slightly darker or lighter shade on hover.
  • Your shopper's messages and the highlights (the numbered badge on a clarifying question, the recommended column of a product comparison and its Recommended badge, the badge on a product card) use your secondary colour. A discount percentage keeps its fixed colour.
  • Links in the assistant's answers use your primary colour when it reads as text on your background (at least 4.5:1 contrast), and your text colour otherwise. They are always underlined. See Links in the assistant's answers for how they display.
  • Text, borders, cards and the message field are worked out from your background and text colours. Text that would not read on your background (under 4.5:1) turns black or white, secondary text such as the AI disclosure stays at 4.5:1 or more, and borders get just dark or light enough to show. On a white background the panel looks the same as before.
  • Dialogs and menus opened from the panel (the header menu, the feedback dialog, the confirmations, drop-down lists) take the same colours as the panel.
  • The keyboard focus shows as a ring in your text colour around every control. The message field shows it by turning its border to your text colour whenever it is active, with the mouse as well as the keyboard.

On a dark background, a product photo shot on white shows as a light square inside its card.

A link in an answer opens in a new tab. Two rules keep long links readable, in the panel, on the AI Storefront, in the Playground and in a conversation's transcript:

  • No half-written address while the answer appears. As the answer types out, a link that isn't complete yet stays hidden instead of showing its address character by character. A link with a label shows once it is fully written. A bare address shows once a space or a line break follows it, or when the answer ends. A link inside a code block is left as it is.
  • A long bare address shows its host. When the assistant writes an address as is (https://… or www.…) and it is longer than 60 characters, the answer shows only its host, for example www.example-store.com. The link still opens the full address. A link with a label, an address of 60 characters or fewer, an email address and a phone number show as written.

Close the panel

Shoppers can close the panel three ways, and you don't need to wire any of them yourself:

  • The ✕ in the chat header. Once the conversation has loaded, its header carries a close control.
  • The Escape key, from anywhere: the host page, the conversation, and the message field too. What the shopper typed stays in the field for the next open. Escape doesn't close the panel when something in the conversation uses it first: closing a menu or an inline edit, or, in the message field, stopping an answer that is still being written (a second Escape then closes the panel). Nor does it close the panel while the shopper's keyboard is composing a character (Japanese or Chinese input, for example), where Escape cancels that character.
  • Clicking outside the panel, but only when the panel opens in Focus on the chat mode, where a click on the dimmed page closes it. In Alongside the page mode, clicking the rest of the page never closes the panel: the assistant is a companion to browsing, not a takeover.

You can still close it yourself with iadvize('close').

No close control during the first instant

The ✕ lives in the conversation's own header, so it only appears once the conversation has loaded. For the brief moment between opening and that first paint, there's no visible way to close the panel. Escape still works during that moment.

Scrolling the page behind the panel never closes it, on any device.

Choose which side the panel slides in from

The panel is a full-height drawer, up to 640px wide, docked to one edge of the screen. On a screen 640px wide or narrower it fills the whole width. It slides in horizontally from that edge, from the right by default.

To dock it on the left, open Appearance in the dashboard sidebar (under Agents), choose Left under Panel side in the Position and behaviour card, and click Save. It needs Sites: Edit. The tag reads the side from your site's configuration on each page load, so the change shows on your storefront's next page load, with nothing to change in the snippet. You can also set it over the API (panelPosition on Update a site) or the MCP server (set_site_panel_appearance).

The side is read when the panel is first created on a page, the moment a shopper first opens it. A shopper who opened the panel before your change keeps the old side until the page reloads.

The snippet no longer sets the side

The tag ignores position and backdrop in a set call, without an error. A snippet copied before this change, or your own code, may still carry iadvize('set', { position: 'left' }): the panel now opens on the right anyway. Choose Left on the Appearance page to keep it on the left. You can leave the old line in place or remove it; the rest of the set call (customData, pageSignal, launcher, locale) still works.

Choose how the panel opens

The Display mode setting, on the same Position and behaviour card of the Appearance page, has two modes.

Alongside the page (the default). The panel sits beside your page, and the page stays visible, usable and scrollable while a shopper chats. The panel closes with the ✕ or Escape; a click or a scroll on the page never closes it.

Focus on the chat. A dimmed backdrop covers the rest of the page behind the panel and background scrolling is locked until the panel closes. Clicking the backdrop closes the panel, and that click never reaches your page. Use it when the conversation should feel like a focused step (a guided flow, checkout support).

The mode is read each time the panel opens, so a change applies from the next open after the shopper's next page load. Like the side, it's no longer set from your page: iadvize('set', { backdrop: true }) is ignored. Over the API it's panelBackdrop (true for Focus on the chat).

On a screen 640px wide or narrower, the panel fills the screen, so the page behind it is locked in both modes:

ScreenAlongside the pageFocus on the chat
Desktop / wide (partial-width panel)scrolls normallylocked
Mobile / narrow (panel fills the screen)lockedlocked

Wherever the page is locked, the panel is also modal for keyboard and screen reader users: see Keyboard and screen readers.

Keyboard and screen readers

The panel works with a keyboard and a screen reader without anything to set up on your side.

  • It has a name. Screen readers announce the panel as a dialog called "AI shopping assistant", in the language the panel displays (see Choose the shopper's language). If the shopper opens the panel before your site's configuration has loaded, the name is in English until it arrives.
  • It's modal only when it takes over the page. In Focus on the chat, and on a screen 640px wide or narrower in either mode, the rest of your page is made inert while the panel is open: Tab and a screen reader stay inside the panel, and nothing on the page can be clicked or focused. The page comes back as soon as the panel closes, and the switch follows the window if it's resized while open. In Alongside the page on a wider screen, the panel is a non-modal dialog and the page stays fully usable.
  • Focus goes to the message field once the conversation has loaded. If it's already loaded, that happens as the panel opens. While it's still loading, focus stays on your page and Escape closes the panel; focus then moves to the message field when the conversation is ready, unless the shopper has closed the panel in the meantime. When the panel closes, focus goes to the Panel reduced state button if it shows, otherwise to the chat bubble that opened the panel. When neither applies (the panel was opened from your own button, for example), focus goes back to the element that had it when the panel opened.
  • Escape closes it, even from the message field, and keeps the draft. While an answer is still being written, Escape in the message field first stops the answer, and a second Escape closes the panel. See Close the panel.
  • Answers are read out once they're complete. A screen reader announces each answer when it finishes, not word by word as it streams, and doesn't interrupt what the shopper is doing. A stopped answer is read as far as it got. A conversation that resumes after a page load reads nothing back. The same applies on the public link and in the playground.
  • The chat bubble and the Panel reduced state button say whether the panel is open, so a screen reader announces them as expanded or collapsed.
  • Reduced motion is respected. When the shopper's system asks for reduced motion, the panel appears in place instead of sliding in, and the loading indicator doesn't spin.

If your page uses inert itself

The tag only clears the inert it set. An element your page had already made inert stays inert after the panel closes. The tag applies inert to the direct children of <body>, other than the panel and its backdrop, as they are when the panel becomes modal. That includes overlays already showing on your page, such as a consent banner or an accessibility toolbar: they can't be reached until the panel closes. An overlay that appears after that moment isn't made inert.

Choose the shopper's language

The panel picks the language it displays (the launcher's disclosure, a chat bubble or question bar's label, the composer's placeholder, starter-question chips, and the conversation itself) from the page it's embedded on, before it ever looks at your storefront's own translation setup. Three signals are checked, in order, and the first one that matches one of the site's enabled languages wins:

  1. An explicit iadvize('set', { locale: 'fr' }) call, if one was queued before the loader booted.
  2. The host page's own <html lang="…"> attribute.
  3. The shopper's browser language (navigator.languages).

If none of the three match an enabled language, the site's own default language is used. This runs automatically: most storefronts declare a correct <html lang> per locale already, so there's nothing to wire up.

iadvize('set', { locale: 'fr' })

Force a language when the page's own signals can't be trusted: a theme that hard-codes lang="en" on every locale, or a multi-market page you want to show in a specific language regardless of what the shopper's browser reports. Set it early: locale is read once, from calls queued before the loader script runs, either in the install snippet itself or in a script tag that executes ahead of it. A set({ locale }) call made after the loader has already booted is a no-op; it won't retroactively change anything on the current page.

Resolved once per page load

The language is fixed for the whole page load. A later set({locale}) call, or the page's lang attribute changing without a reload, has no effect until the shopper's next navigation. On a single-page app, that means a route change alone doesn't switch the widget's language.

A resumed conversation keeps its own language

This only decides the language for a new conversation. If a shopper already has one running and navigates to a page in a different language (from your site's French pages to its English ones, say), reopening the panel resumes that conversation in the language it was created with. The page's language never overrides an in-progress conversation.

The AI Storefront has the same default (the shopper's browser), plus its own override for a link you're sharing directly rather than embedding: append ?l= with a language code, for example https://iadvize.ai/s/<public-key>?l=fr. Useful for a link in a French newsletter or on a French QR code, where there's no host page to read a lang attribute from.

Tell the assistant what page the shopper is on

By default the assistant only knows what the shopper types. Declare the current page and it can ground its answers in it instead: "is this in stock?" on a product page, "what's on sale here?" on a category page.

Call iadvize('set', { customData }) with one of five shapes, depending on the page:

// Home page
iadvize('set', { customData: { pageType: 'home' } })

// Category page
iadvize('set', {
  customData: { pageType: 'category', categoryName: 'Chemise homme' },
})

// Product page
iadvize('set', { customData: { pageType: 'product', productId: 'XXX' } })

// Content page (size guide, policy, "about us")
iadvize('set', { customData: { pageType: 'content' } })

// Blog page
iadvize('set', { customData: { pageType: 'blog' } })
  • pageType: 'home': no other field required.
  • pageType: 'category': categoryName is required: a display string (e.g. "Chemise homme"), not a catalog id.
  • pageType: 'product': productId is required: your own catalog/connector id for the product, whatever your product feed already uses. Never an iAdvize id.
  • pageType: 'content' and pageType: 'blog': no other field required.

These five are the whole list: home, product, category, content, blog. Anything else is treated as if you declared nothing.

`checkout` is no longer a page type

Declaring pageType: 'checkout' used to hide a chat bubble or question bar and stop the page signal on that page. It does neither now. The tag treats the call as no declaration at all, so on that page the widgets follow the page type your site's pages hold and the assistant reads the page like any other. Nothing errors. Remove the call, and see Keep the assistant off a payment page.

An inline button needs a page type

A chat bubble or question bar with page types selected still shows on a page that has no page type. An inline button does not: it renders only where the page has a type and that type is one it targets. The type is either the one you declare or, when you declare nothing, the one your site's pages hold. A page with neither gets no inline button, however it's configured.

  • pageUrl: optional on all five. Carried through as-is; never parsed to guess the page type, category, or product.

It also decides which starter questions can show

Declaring a page type has a second, visible effect: a chat bubble or question bar with Show starter questions on carries only the chips whose own page scope admits that page type. Declare product and a Home-scoped question drops out. On a page with no page type (nothing declared and none held for that address), page scope is not applied at all and every enabled question with text in the shopper's language is eligible, the same rule the panel applies there, so the chips on the widget and the chips inside the panel it opens always agree.

When you declare nothing

If you never call customData, or call it with a page type outside the list, the tag falls back to the page type your site's Pages hold for the current address. That type comes from a read of the page, or from a guess made from the address until the page is read. The fallback applies to:

  • the page-type targeting of every widget, floating and inline;
  • which starter questions the widgets show;
  • which questions the panel's welcome screen shows.

Your declaration always wins. The fallback is a stand-in for a page you haven't declared, not a second opinion on one you have.

What the fallback does not do:

  • It is never sent to the assistant. The assistant gets a page type only from your customData. The type your site's pages hold never becomes a product id or a category name either.
  • It does not cover a page the store doesn't hold, or one stored as Unknown. Such a page has no page type, as before.

How it runs: the tag asks our servers for the type of the current path as soon as the page loads, in parallel with loading the site's configuration, and waits up to one second for the answer before it decides which widgets to show. On a slow or failed answer the page simply has no page type. On a single-page storefront it asks again after each client-side navigation, by path, and re-evaluates the widgets when the answer arrives. A shopper who objected to measurement sends nothing: no lookup is made for them. An answer can be cached for a few minutes, so a change to a page's type shows on your storefront after a short delay.

A site that declares nothing therefore behaves differently from before: a widget targeted by page type now follows the type your site's pages hold for that address, where it used to see a page with no type. If a widget shows up on pages where it didn't, check its page types and the Type column in Pages.

Call it again on every route change

customData isn't a one-time setting read only when the panel first opens; it can be set again at any time, including while the conversation is already open. On a single-page-app storefront, call iadvize('set', {customData}) again every time the shopper navigates to a new route, not just once at initial page load. Otherwise the assistant keeps using whichever page context you last set (every message sent while the panel is open carries it) even after the shopper has actually moved to a different page.

It's a reference, not a fact

The assistant treats customData as something to look up, never something to take at face value. Setting productId: 'XXX' doesn't make the assistant state that product's price, stock, or promotion status: it looks the product up in your catalog first, the same way it would if the shopper had just described it, and answers from what it actually finds there. categoryName works the same way: it's a hint the assistant folds into a catalog search, not an exact-match filter, so a category label that's close to but not identical to your catalog's own naming still works.

A shape that doesn't match is silently ignored

customData that doesn't match one of the five shapes above (a missing categoryName on a category page, an unrecognized pageType such as checkout, or a categoryName/productId longer than 200 characters) is dropped: the panel keeps working, the assistant just gets no page context for that turn. There's no error or console warning, so double-check the shape if the assistant doesn't seem to notice the page.

What the assistant reads from the page

The tag also reads the page on its own, with no code on your side. It's the fallback for every page where you don't call customData: a storefront that declares nothing still gets an assistant that knows where the shopper is standing. Unlike customData, which only ever describes the latest page, this travels with each message, so the assistant knows which page every question in the thread was asked from. A shopper who looks at one dress, moves to another, and asks "how does this one compare with the previous one?" is understood.

It's on for every site unless you switch it off, and there are two ways to do that (below). It applies to the tag on your storefront only: the AI Storefront page never carries it.

What is read

Three fields, nothing else:

FieldRead fromTruncated at
Addresslocation.origin + location.pathname500 chars
Titledocument.title200 chars
Description<meta name="description">, falling back to <meta property="og:description"> when that tag is absent300 chars

The address is rebuilt from the origin and the path, so everything after ? or # never leaves the browser: search terms, an order token, an ?email= parameter, your own campaign parameters. The rebuild runs twice, once on your page before anything is sent and once on our servers on arrival, so a value that somehow survives the first pass is still stripped. Whitespace is collapsed and over-long values are cut to the caps above rather than dropped, so a long title still yields a usable signal.

Two more things get dropped on arrival, silently, with the message still going through as normal: an address that isn't http or https, and an address whose origin isn't in the site's authorized domains list.

Nothing is inferred from it

No page type, no product id, no category name is ever derived from the address, the title or the description, and none is sent to the assistant from anywhere but your customData. (Your widgets can fall back to the page type your site's pages hold, see When you declare nothing, but that type stays on the page and only picks widgets and chips.) The structured fields stay exactly what they've always been: values you declare with customData. The three fields above are read as plain text and treated the way customData is treated, as something to look up. The assistant uses them to work out what "this" refers to and to compose a catalog search; it resolves the product through your catalog before stating a price, a stock level, a promotion, or availability.

When it's read, and when it's sent

Reading happens in the shopper's browser, and only there:

  • when the shopper opens the panel,
  • on every client-side route change (pushState, replaceState, popstate),
  • once more about a second after a route change, because a headless storefront often updates its title just after the address changes. Without the second read, the first message after a navigation could pair the new address with the previous page's title,
  • whenever you call iadvize('set', …), so a customData or pageSignal change takes effect on the next message.

All of those happen only once the panel is open. On a page where the shopper never opens the assistant, nothing is read at all: no DOM access, so this feature costs your page load nothing.

Sending only happens with a message. There is no page-view beacon: a shopper who browses ten pages and never types anything sends us nothing at all. Each message carries the page it was asked from, and that page is stored alongside the message, under the same 12-month retention as the rest of the conversation.

When AISA has read the page

The three fields above are all the tag sends. If the agent version has the Site page content tool and AISA holds a read copy of the page the shopper is on (matched on its path, with no query string), the assistant is also told that the content of that page is available, and can read what AISA stored for it. Nothing more leaves the browser. With the page signal switched off, the assistant does not know which page the shopper is on, so it cannot read it this way.

Keep the assistant off a payment page

The tag no longer treats any page as special. Every page it runs on is read, a payment page included, and the page type checkout that used to stop the reading is gone. If you want no assistant on a payment page:

  • Don't load the tag there. This is the reliable way: no tag, no widget, no panel, no reading.
  • Or switch the reading off on that page with iadvize('set', { pageSignal: false }) (see below). That stops the page signal only. A widget can still render there, and the panel still opens.

What you declare still wins

customData and this signal travel side by side and are never merged. Where you declare a pageType, productId or categoryName, that declaration is authoritative for the page it describes, and the assistant is told so.

Two ways to switch it off

Per site, from the dashboard. Open Site settings → Site access and use the Page signal card's Read the current page switch. It's on for every site by default. Like the other switches of that tab, flipping it takes effect when you click the tab's Save at the top right (there's no publish step), and it needs the sites:edit permission: without it the card shows the current state and no switch. Turning it off is enforced on our servers as well as in the tag, so a cached tag, a stale configuration, or a hand-rolled request can't send a page for a site that has it off.

Per page, from your own code. Nothing is read on that page from then on, and anything the panel is already holding is cleared:

iadvize('set', { pageSignal: false })

Call it on account and order pages

Themes routinely put a customer's name or an order number in the page title ("My orders · Jane Doe"), and the title is read as it stands. Call iadvize('set', { pageSignal: false }) on account, order-history and order-detail pages. The query string is already stripped for you, which covers most identifiers, but the title isn't.

On a single-page app, switch it back on

pageSignal: false holds for as long as the loader lives, not just for the current route. On a classic multi-page storefront that's one page, so the call affects only the page that makes it. On a single-page app, where no full reload happens, call iadvize('set', { pageSignal: true }) when the shopper navigates back out of the pages you excluded.

pageSignal: true only lifts a page-side false. It can't switch collection back on for a site whose dashboard switch is off: a call from your page can only reduce what's read, never widen it.

What the shopper sees, and what you see

The shopper-facing data-usage notice at https://iadvize.ai/privacy/assistant/{lang} lists this as its own data category: which three fields are read, that the address stops before the ?, that it's read only when a message is sent and never while browsing, that it's kept with the conversation, and that the store can switch it off.

In the dashboard, a shopper message that carried a page shows an Asked from line under the bubble in the conversation transcript, linking to the page. A message with no page shows nothing.

Command API

Call iadvize(command, …). Calls made before the loader finishes are queued and replayed in order, so you can call it any time after the snippet runs.

Prop

Type

The events you can subscribe to with on:

  • conversation:opened: the panel opened.
  • conversation:closed: the panel closed.
  • message:sent: an auto-send message was handed to the chat panel. The panel may hold it first (see Auto-send a first message), so the event can fire before the message shows in the conversation, and it still fires for a held message that a newer click replaces or that is never sent. No payload: if you need the text, you already have it, it's the same element/attribute your click handler triggered from.
  • resume-button:shown: the Panel reduced state button appeared, on a page load or when the panel closed. It fires each time the button appears, not once per session.
  • resume-button:clicked: the shopper clicked the Panel reduced state button. conversation:opened follows as the panel opens.
  • resume-button:hidden: the shopper hid the Panel reduced state button with its ✕. None of the three resume-button: events carries a payload.
  • config:loaded: the tag fetched the site's display config (branding, locale); the config object is passed to your callback. config.locale is the language actually displayed (the result of Choose the shopper's language above), as a plain site language code (fr, en, …), not a regional dashboard locale. It used to carry a dashboard-style tag like fr-FR; if your own code reads config.locale, update it to expect the shorter code.
iadvize('on', 'conversation:opened', function () {
  // e.g. fire your own analytics event
})

Make sure it can actually answer

The tag loads from the key alone, but the panel only holds a conversation once the site has an agent ready to serve it:

Without one, the panel still opens but the conversation returns not-found: nothing answers, and no engagement widget shows. The Install the tag card warns you when no agent answers on the site, and links to Agents. The panel always serves the answering agent's live version; put another version live and the tag picks it up with no snippet change.

Test the tag from a local page

You can try the tag on a locally-served test page before you touch your real storefront. The conversation iframe accepts being framed on localhost and 127.0.0.1 (over http://, any port), on top of every HTTPS origin.

That's only half of it, though: framing being allowed doesn't mean the panel will boot. Add your local origin to this site's authorized domains first (see above), for example http://localhost:8000, or the panel refuses it exactly like it would refuse any other unlisted origin.

Serve the test page over HTTP from localhost or 127.0.0.1. For a static HTML file, the quickest way is:

python3 -m http.server 8000
# then open http://localhost:8000/your-test-page.html

Your storefront's own dev server works too, as long as you reach it at http://localhost:<port> (or http://127.0.0.1:<port>) and that exact origin is on the authorized domains list.

file:// and LAN addresses won't work

The iframe is framed only from HTTPS origins plus localhost / 127.0.0.1. Two common test setups fall outside that and the panel stays blank:

  • Opening the file directly (file:///…/your-test-page.html). A file:// page has no real origin, so the browser blocks the frame. Serve it over http://localhost instead.
  • A LAN IP or custom local hostname: http://192.168.1.20, http://my-shop.local, http://…​.test, or an HTTP tunnel. These aren't localhost, and they're not HTTPS, so they're not allowed. Serve them over HTTPS to test from them.

This is purely a local-testing convenience. Real storefronts are HTTPS, which is always allowed, so nothing here needs setup on the iAdvize side.

Allow the tag through your Content Security Policy

If your storefront sends a Content-Security-Policy header, add the iAdvize origins so the browser doesn't block the tag. In production:

script-src  https://tag.iadvize.ai
frame-src   https://iadvize.ai
connect-src https://iadvize.ai
  • script-src: the loader and its bundle are served from the tag host (tag.iadvize.ai).
  • frame-src: the conversation runs in an iframe on the app origin (iadvize.ai/embed/<key>).
  • connect-src: the loader fetches the site's display config and posts page telemetry to the app origin.

The iframe accepts being embedded on any HTTPS origin (its frame policy is frame-ancestors https:, plus http://localhost and http://127.0.0.1 for local testing). This is about browser framing, separate from the authorized domains the panel itself checks before it will start a conversation. A production HTTPS storefront needs no CSP changes on the iAdvize side; it does still need its own origin on your authorized domains list. Use the exact origins printed in the snippet the dashboard gives you if your deployment differs from the production hosts above.

Voice dictation in the panel

When the served agent version has the Voice dictation capability turned on, the chat composer's microphone button (speech-to-text, transcribed entirely in the shopper's browser, no audio or transcript reaches iAdvize) works inside the embedded panel out of the box. The iframe our loader creates already requests microphone permission delegation; there's nothing to configure on your side for the common case.

A restrictive Permissions-Policy header can block it

If your storefront sends its own Permissions-Policy HTTP header that restricts microphone for iframed content, that takes precedence over our iframe's own delegation and the mic button won't work inside the embedded panel, even though it works fine on the AI Storefront, which isn't framed. If you hit this, add our origin to that header's microphone allowlist for the app origin used in your Content Security Policy section above. Most storefronts don't send this header at all and need no change.

Shopper privacy: the data-usage notice and the right to object

Every conversation (through the web tag or the AI Storefront) now links to a data-usage notice, shoppers can object to usage measurement from inside the chat panel, and a shopper can delete the conversation they're currently in. This section covers what ships, what it suppresses, and (just as important) what it doesn't do for you.

The data-usage notice

The panel's AI-disclosure line (the "You're chatting with an AI assistant. Responses may contain mistakes." text shown at the top of the conversation) now links to a notice (see the English version) at:

https://iadvize.ai/privacy/assistant/{lang}

{lang} is one of the six languages the assistant can converse in: fr, en, de, it, es, nl. The notice states, in plain language: what's collected (the conversation itself, the ownership cookie that keeps it going, a session-scoped measurement key, standard technical request data, an anonymous performance measurement, and the labels described below) and how long each is kept (conversations for 12 months, session-scoped measurement data for 24 months), that messages are sent to the LLM provider with zero data retention and an instruction not to train on the content, asserted on every request, that what the assistant stores durably is held in the EU while some processing happens elsewhere, and that iAdvize acts as processor on the store's behalf, the store being the controller.

The notice also says that after a conversation an AI model labels it for the store: the kind of request, whether it was answered, whether the replies were accurate, and signals such as an intention to buy. Labels are kept with the conversation, for the same 12 months. Finally, it states that the store relies on its legitimate interest for this processing, unless its own privacy policy says otherwise.

The performance measurement. The chat panel on your storefront (the /embed iframe) sends real-user performance measurements, the Web Vitals of how fast the panel loads and responds, to our hosting provider. It sets no cookie and carries no identifier. The page address is cut down to its route, /embed/[key], so neither your site key nor any query string reaches the provider, and that includes the session-scoped measurement key. The panel sends no audience measurement (page views) to that provider. The AI Storefront page behaves the same way, reduced to /s/[key]. The sub-processor list names the provider and where it processes this.

Page-view counts

The tag on your pages, not the chat panel, reports each page a shopper views, so AISA can rank your pages and find the ones your sitemap misses. Each view adds one to a daily total per page, kept as the site, the page's path (without the part after ?), the UTC day and a number. Nothing in a total identifies the shopper or links it to their conversation or to another store. Totals are kept 90 days. See Counting page views for what is and isn't counted.

The notice has its own line for these counts: "The pages you view as you browse the store, counted as a daily total per page from each page's address without the part after '?'. Nothing in that total identifies you or links it to you, your conversation or another store. It lets the store's assistant prepare the pages people view most first. Kept 90 days, and the store can switch it off." The line is on the notice whatever your site's setting. You can switch counting off for a site under Site settings → Site access.

Shoppers can object to measurement

A second menu item, next to "New conversation" in the chat panel's header menu, lets a shopper object to (or withdraw an objection to) usage measurement, with a one-line explanation and a link to the notice. This is on by default: there's nothing to turn on for it to appear, on both the web tag and the AI Storefront.

Objecting stops, for that browser tab going forward:

  • the session-scoped measurement key (cleared immediately if one was already set for this tab),
  • the "was the assistant shown" beacon sent when the page loads,
  • measurement rows (impression, click, conversation-opened) tied to that session, also checked on our servers for every request that carries the objection (see the timing caveat for an objection coming from your CMP),
  • the panel's performance measurement to our hosting provider (see the timing caveat for an objection coming from your CMP).
  • the page-view counts: the tag stops reporting page views, and our servers count a page view only when the request says the shopper did not object. A request that says nothing either way (an older copy of the tag) counts nothing.
  • conversation labeling: a conversation in which any message was sent with the objection is never labeled, and a label it already has is not refreshed.
  • the Panel reduced state button: it stops showing, and the tag no longer writes its record or its marker (see What the tag stores in the browser). An objection made in the panel, or with a privacy call once the tag has loaded, also deletes both at once.

Objecting does not delete data already recorded (it expires on its own retention schedule) and does not stop the conversation itself: the ownership cookie and the transcript are unaffected, since without them the assistant couldn't keep answering the shopper's own conversation. The objection is stored per store (on your own site's origin), so it doesn't carry over to a different store; there's no shared identifier across stores for it to carry over on.

Call it from your own CMP

The same objection is reachable as a command, so your own cookie-consent tool can drive it without a shopper ever opening the chat panel:

iadvize('privacy', { objected: true }) // shopper objects
iadvize('privacy', { objected: false }) // shopper withdraws the objection

Like every other command, it can be called any time, including before the loader script has finished loading: the call is queued and honored as soon as it boots.

One timing caveat. The panel is loaded the first time a shopper opens it on a page and then stays loaded until they leave that page. An objection your CMP signals after that first open takes effect on your page right away, but it doesn't reach the panel already loaded: that panel keeps the state and the session key it was opened with. Until the shopper's next page load, it can keep recording their interactions inside it (clicks, starter-question picks) under that session key and keep sending its performance measurement, whether it's open or closed at the time. Our servers keep no objection record of their own, so they can't catch this on their side. An objection made from the panel's own menu applies at once.

Shoppers can delete their own conversation

A third menu item, Delete this conversation, sits in the same header menu, on both the web tag and the AI Storefront. Confirming it permanently deletes the conversation and every one of its messages, then starts the shopper fresh on a brand-new one; there's no undo.

It only works while the shopper's browser still holds the small ownership cookie described in Cookies the tag sets below, the same cookie that lets the panel keep answering their conversation at all. Where the browser blocks that cookie in the web tag's panel, the key the panel keeps in its own storage does the same job (see Conversation continuity across page navigation). Once that cookie is gone (a different browser or device, a cleared cache, or it having expired), that past conversation can no longer be singled out and deleted on request: there's no other identifier we can use to find it. It still falls under the retention period that applies to every conversation; see the data-usage notice above for how long that is.

There's no iadvize(...) command for this. Unlike the objection above, deletion isn't something your own CMP would trigger on a shopper's behalf.

This notice and these controls don't make you GDPR/ePrivacy compliant

The notice, the objection mechanism, and the deletion control are evidence you can point to when assessing your own compliance, but they are not a certification that your use of the assistant is compliant. iAdvize acts as a data processor on your instructions; you remain the data controller, responsible for your own privacy policy, your own cookie/consent banner, and whatever assessment your legal counsel or DPO makes about your specific use of the assistant.

Your obligation: informing visitors who never open the chat

The notice and the in-panel objection control only reach a shopper once they open the chat panel. The "was the assistant shown" measurement and the page-view counts start on page load, before that, so a visitor who never opens the chat is measured without ever seeing the notice or getting a way to object from inside the widget.

Covering that visitor is your obligation, not something this widget does for you:

  1. Reference our notice from your own privacy policy. Link https://iadvize.ai/privacy/assistant/{lang} for each language your site serves, so a visitor who reads your policy (rather than opening the chat) is still informed.

  2. Wire the objection command into your own CMP's consent-change callback, so a visitor who withdraws consent through your own cookie banner is honored by the assistant too, even if they never open the chat:

    // in your CMP's callback, whenever the visitor's consent choice changes:
    iadvize('privacy', { objected: true }) // consent withdrawn / refused
    iadvize('privacy', { objected: false }) // consent given / restored

iAdvize cannot enforce either of these for you

We can't edit your privacy policy, and we can't detect your CMP's consent state on our own: the assistant only reacts to the privacy command you choose to call. This is the processor/controller split: if you don't reference our notice and wire this command, visitors who never open the chat aren't informed or given a way to object outside the widget itself, and closing that gap is your responsibility, not something we can do on your behalf.

A paragraph you can paste into your privacy policy

Here is the wording, in English and in French, describing exactly what the assistant does on your site. Paste the version matching the language your policy is published in, fill in your company name, and check it against the rest of your policy before publishing. It describes our side of the processing; it is not legal advice, and using it does not move the obligation above onto us.

[Your company name] uses the AI Shopping Assistant provided by iAdvize SAS (9 rue Nina Simone, 44000 Nantes, France) to answer visitors' questions on this site. iAdvize acts as our processor: it processes this data on our instructions and on our behalf, and we remain responsible for it.

When a page carrying the assistant loads, and before you open anything, a key scoped to your browsing session is stored in your browser and cleared when you close the tab. It is used to measure how the assistant is used on this site: it records that the assistant was available on the page, and, if you then open it, that a conversation started. It does not identify you and is not shared with other sites.

If you converse with the assistant, we also process the conversation itself (the messages you send and the assistant's replies) and a cookie that lets the assistant recognise your own conversation while you browse. That cookie is set when you send your first message, carries no other information about you, and is cleared when you close your browser.

While that conversation is in progress, your browser also keeps, for this site only, the time of your last message and whether you hid the button that brings you back to the conversation, so the next page can offer that button. It is no longer used 30 minutes after your last message. If your conversation cannot be found, a marker turns the button off until you close the tab. Neither value is sent to iAdvize or identifies you.

The pages you view on this site are also counted as a daily total per page, from each page's address without the part after "?". That total does not identify you and is not linked to your conversation or to other sites.

Conversations are kept for 12 months after their last message. Measurement data is kept for 24 months after it is recorded. Daily page totals are kept for 90 days.

iAdvize publishes a notice describing this processing on its own side at https://iadvize.ai/privacy/assistant/{lang}, where {lang} is one of the six languages the assistant converses in: fr, en, de, it, es, nl.

You can object to this measurement at any time from the menu in the assistant's chat window, next to "New conversation". Objecting stops collection going forward. It does not delete data already recorded, which is covered by the retention periods above, and it does not stop the assistant from answering you.

Why this says 'kept for' and not 'deleted automatically'

12 months, 24 months and 90 days are the retention periods the product applies. The job that enforces them by deleting expired conversations, measurement data and page-view counts is built, but its daily schedule is not yet registered in production, so nothing is being purged on a timer today. Don't claim automatic deletion in a published policy until it is. Once the schedule is running, you can strengthen the wording above to say the data is deleted automatically at the end of each period.

Three things to adjust before you publish it:

  • Remove the page-view sentences if you switched page-view counting off for the site under Site settings → Site access. They describe the counting as it runs by default.
  • Add a sentence about your own consent tool only if you wired the privacy command above. Something like "You can also object from our cookie settings, without opening the assistant" / « Vous pouvez également vous opposer depuis nos paramètres de cookies, sans ouvrir l'assistant ». Without that wiring the sentence is false, so leave it out.
  • Link the notice URL for each language your site serves, replacing {lang} with the actual language code. {lang} is a placeholder in the URL, not something the page resolves on its own.

Nothing in this paragraph covers the personal data you collect for your own purposes on the rest of your site. That stays yours to describe.

Rate-limit protection

The tag's chat requests go through the same endpoint as the AI Storefront, protected the same way. See that section for how it works.

Conversation continuity across page navigation

What happens to an open conversation depends on how the shopper moves around your site:

  • In-app navigation (single-page apps). The panel and its iframe are never torn down as the shopper moves between routes, so the conversation just keeps going.
  • A full page reload, a link to another page, or a new tab on the same site. The conversation resumes there too, and not because a cookie merely survived: it resumes because the assistant looks the shopper's own conversation back up and reopens it with its full history, the next time the panel is opened. This works the same way on the web tag and on the AI Storefront, and it's what a classic multi-page storefront (Shopify, PrestaShop, WooCommerce) needs, not just a single-page app.

Resume doesn't reopen the panel by itself: that's still entirely up to your shopper (or your own trigger), same as opening it any other way. What changes is what's waiting inside once it does open: instead of starting empty, it checks whether this same shopper already has a conversation running (same site, same agent, activity within the last 24 hours) and if so, picks it back up exactly where it left off, scrolled to the last message. Nothing announces this: no banner, no "welcome back," no new element. Starting a new conversation, or deleting one, still always starts empty.

When the browser blocks the cookie in the panel

Resume normally rests on the small cookie described in Cookies the tag sets below. Some browsers block that cookie inside the panel, chiefly Safari versions before 26.2. The panel checks this itself when it loads, so it doesn't rely on a list of browsers. Where the cookie is blocked, the assistant keeps the same key in the panel's own browser storage and sends it with each request instead. Sending several messages, rating an answer, deleting the conversation and resuming it on another page all work the same way as with the cookie.

  • Nothing is stored on your site. The key sits in the panel's storage, which belongs to iAdvize's domain and is kept separately for each site the panel runs on. Your page can't read it, and it never shows up in What the tag stores in the browser.
  • It stops working 24 hours after the conversation's last message. Past that, the conversation can no longer be resumed through the key, and the panel discards the key the next time it loads after 24 hours without use, then starts on a new conversation. The assistant doesn't clear the key when the browser closes, but some browsers clear this kind of storage themselves when they quit, in which case the next session starts a new conversation.
  • If the browser blocks that storage too, the key is kept in memory for the page: the conversation works on that page, and a reload or navigation starts a new one.

There's no setting on your side for any of this.

A checkout on a different domain won't resume either

If your checkout runs on a different registrable domain than the rest of your storefront (a separate domain some payment or checkout providers require, not just a subdomain of your own site), the conversation doesn't carry over there. The cookie that makes resume possible is scoped to one top-level site by design (the same scoping that keeps it from following a shopper across unrelated sites), so a domain change resets it exactly like switching browsers would. A checkout on a subdomain of your own site (for example checkout.yourshop.com alongside www.yourshop.com) is unaffected: that's still the same site.

The Panel reduced state button

Once a shopper has a conversation going, the tag shows a small floating button on every page of your site while the panel is closed: the Panel reduced state button. One click opens the panel, and the conversation resumes there exactly as it does from any other entry point. There's nothing to install or switch on, and it doesn't depend on your widgets: it shows on a site with no engagement widget and no trigger of your own. You choose where it sits and how it looks in the site's Brand settings.

When it shows. All of these have to be true:

  • The last message in the conversation, from the shopper or the assistant, is less than 30 minutes old. Each message sent and each answer that finishes starts the 30 minutes again. Opening the panel without writing doesn't. The 30 minutes are fixed: there's no setting for them.
  • The panel is closed.
  • The shopper hasn't hidden the button (see below).
  • The site is offering the assistant to this visitor. A capped organization at its monthly conversation quota stops offering it to new visitors, and then no button shows either.
  • The shopper hasn't objected to measurement.
  • The tag fetched your site's config on this page. Like the floating widgets, the button fails closed: no config, no button.
  • The page isn't a storefront preview of a widget. A preview shows the widget you are testing, and a conversation held in a preview leaves nothing behind for your shoppers' pages.

The tag checks this when a page loads and each time the panel closes, not on a timer. So a tab that's already open picks up a message written in another tab at its next page load or panel close, and a button already on screen stays past the 30-minute mark until the next check. Clicking it then still reopens the conversation, which stays resumable for 24 hours as described above. Once 30 minutes have passed, the button stops showing and the floating widgets come back.

It takes the floating widgets' place. While the button shows, no chat bubble or question bar renders, whatever their page targeting, so the shopper sees one way back to the conversation rather than two. Inline buttons and Starters widgets in your page are not affected. The page-side iadvize('set', { launcher: false }) override hides chat bubbles only: it has no effect on this button, and there is no page-side command that hides it. To keep it off a page, don't load the tag on that page.

Closing the panel brings it up on the same page. When the shopper closes the panel with a conversation in progress, the button appears right away and keyboard focus moves to it, whichever control opened the panel. Screen readers announce it as collapsed, since the panel it opens is closed.

The shopper can hide it. A small ✕ sits on the button's corner facing the page, always visible, on desktop and touch alike. Clicking it hides the button on every page and tab of your site and brings the floating widgets back. Opening the panel again, from any entry point, gives the button back for the next time the panel closes.

What it looks and sounds like. The button shows an icon and no text. Screen readers announce "Continue your conversation", followed by the AI disclosure, and the ✕ as "Hide this button", in the shopper's language (the six languages the assistant converses in). It fades in just after the panel slides out, with no animation when the shopper's system asks for reduced motion. It's fixed to the screen, so showing or hiding it moves nothing on your page, and it sits on the same layer as a chat bubble, below the panel and its backdrop. On a page that extends under a phone's notch or home bar, the tag adds that safe area to its offsets.

What you can measure. The button writes three event types to your engagement report's Exposures tab: Reduced button shown (once it's actually on screen), Opened from the reduced button and Reduced button hidden. Each is recorded at most once per tab session, never for a shopper who objected, and never from a previewed page. To follow every occurrence, use the resume-button: events of the Command API.

What can go wrong.

  • The conversation can't be found. The button shows from a record the tag keeps on your own site (see What the tag stores in the browser), but the conversation still opens from the ownership cookie, or from the key the panel keeps where the browser blocks that cookie. When the two disagree (the shopper restarted their browser, which clears the cookie but not the record; the panel's key was discarded after 24 hours without use; the agent answering on the site changed), clicking the button opens the panel on a new conversation, with no error, and the button stays off for the rest of that tab.
  • Another subdomain shows no button. Browsers keep that record per origin, so a page on checkout.yourshop.com doesn't see a conversation started on www.yourshop.com, even though the conversation itself resumes there.
  • The browser blocks storage. No button shows and nothing breaks. Your other entry points still resume the conversation.

Cookies the tag sets

If your legal or technical team asks whether the widget sets cookies on your site: yes, one, and here's exactly what it does.

  • What it's for. It's the small ownership token the assistant sets the moment a shopper sends their first message, so a later request can be recognized as the same conversation. That same cookie is also what makes the resume behavior above possible: it's used to look the conversation back up, not just to authorize it. No second cookie was added for that, and nothing about consent changed.
  • What it isn't. It doesn't identify the shopper across visits, and it doesn't correlate them across different sites. It's cleared automatically when the shopper closes their browser; it's not a long-lived tracking cookie.
  • Consent. Because its only purpose is to technically enable the conversation the shopper themselves started (not analytics, marketing, or advertising), it falls under the "strictly necessary" (functional) cookie exemption, the same category as a shopping-cart cookie. It does not require a cookie-consent banner or opt-in under GDPR/ePrivacy. That's the category name to cite if your legal team asks.

What the tag stores in the browser

Besides the cookie above, which belongs to iAdvize's own domain, the tag keeps a few values in your storefront's own browser storage. This is the complete list. None holds message content, a conversation id or anything that identifies the shopper.

KeyStorageWhat it holdsWrittenRemoved
iadvize:optoutlocalStorage1: the shopper objected to measurement.When the shopper objects, in the panel or through your privacy call.When the objection is withdrawn. Otherwise kept: an objection never expires.
iadvize:resume:<site key>localStorageThe Panel reduced state button's record: the time of the last message sent or answer received on this site, and whether the shopper hid the button.At each message sent and each answer that finishes, and when the shopper hides the button. Never for a shopper who objected, nor in a tab holding the marker below.At New conversation or Delete this conversation, when the panel opens and finds no conversation to resume, on an objection, and when the tag reads it and finds it 30 minutes old or more.
iadvize:sidsessionStorageThe session-scoped measurement key, a random value.On the first page of a tab session. Never for a shopper who objected.When the tab closes, or on an objection.
iadvize:handofflocalStorageThe session key above and the time, as one short value: it lets a tab opened from a link of the panel continue the session (see Holdout test).When the shopper opens a link of the panel in a new tab. Never for a shopper who objected.Ignored once it is 15 seconds old, and removed when a tab that starts a session finds it that old. It is not removed when read, so several links opened in a row each continue the session.
iadvize:seensessionStorage1: the panel has loaded once in this tab, so a later page can tell whether the ownership cookie survived the navigation.The first time the panel loads in a tab session. Never for a shopper who objected.When the tab closes, or on an objection.
iadvize:launcher_shownsessionStorage1: a chat bubble has been recorded as seen in this tab session.The first time a chat bubble is on screen. Never for a shopper who objected.When the tab closes.
iadvize:widget_shownsessionStorageThe list of what was already recorded as seen in this tab session: widget versions seen, starter questions per widget, and the Panel reduced state button's three events, plus a widget_loaded:<id> and a widget_mounted:<id> entry per widget version (applied on the page, and its host inserted in the page). It keeps each one to a single record per session.Each time one of them is recorded for the first time. Never for a shopper who objected.When the tab closes.
iadvize:noresume:<site key>sessionStorage1: the panel opened while the record said a conversation was in progress, and found none to resume. While it's set, this tab shows no Panel reduced state button and writes no record.When that happens.When the tab closes, or on an objection.

<site key> is the public key in your install snippet (pk_site_…), so two sites served from the same origin (/fr and /de, say) each keep their own record, and a conversation on one never shows the button on the other. localStorage survives the browser being closed, sessionStorage is cleared when the tab closes, and both are kept by the browser per origin. The iadvize:resume: record is only ever read on your page to decide whether the button shows: it's never sent to iAdvize, and it can't open a conversation on its own. A record edited by hand at most shows the button, which then opens the conversation the ownership cookie points to, or a new one.

"On an objection" means an objection made in the panel, or with a privacy call once the tag has loaded. A privacy call your CMP queues before the tag loads stops every write from that page on, but doesn't delete what an earlier page already wrote. Those values stay in storage, unused while the objection holds: the sessionStorage ones until the tab closes, the iadvize:resume: record until the tag reads it again after the objection is withdrawn.

One more write lands outside the browser's storage: on a Shopify store, the tag puts the conversation's key on the store's own cart as the iadvize_attribution attribute, so an order can be tied back to the conversation (see Shopify order webhooks). It doesn't do this for a shopper who objected.

Not in this version yet

To set expectations for what you're embedding today:

  • No inline, in-page engagement widgets. A block of chips woven into your page layout (inside a product page's content) isn't part of the web tag yet. The chat bubble and question bar are both fixed, floating overlays, and the starter-question chips they can carry render above the widget itself, not in your page flow. The dashboard's format catalog lists the in-page formats as Coming soon; they can't be created.
  • No greeting or auto-invite. Both the chat bubble and the question bar are static, always-there surfaces: neither pops up or sends a proactive first message on its own, and a question bar only sends anything once the shopper types it themselves. A question bar does move: it types your starter questions into its field at rest, widens when focused, and folds into a bubble on a phone (see The question bar).
  • No durable cross-session visitor profile. The measurement key is cleared when the tab closes; the tag doesn't build a shopper profile that persists or follows a visitor across sessions.
  • No consent gate before the first message. The tag doesn't block a conversation until a shopper accepts cookies: objecting suppresses measurement, not the conversation itself. Wire your own CMP as described above if a consent choice needs to reach the assistant before a shopper ever opens the panel.

Each of these is planned separately and isn't part of the web tag today.

On this page