Web Chat

AI Suggestion Buttons

Inject a row of contextual question buttons on your storefront — either AI-generated per page (from the product the visitor is looking at) or a static list — that open the chat with the question pre-filled.

AI Suggestion Buttons (also called interaction buttons internally) render a row of clickable questions on the merchant's storefront. Clicking one opens the Octocom chat widget with the question pre-filled, so the customer can drop into a guided conversation about the product without typing.

There are two content sources: AI-generated (the backend looks up the product for the current URL and asks an LLM to draft questions a shopper might want answered) and manual (a static list of question strings shipped with the config). Layout, styling, and target placement are merchant-controlled.

The feature is shipped as part of the web chat widget — no extra script tag. Make sure the chat widget is deployed first.


How it works

  1. The widget script loads on a page and reads the merchant's webChatConfig. If interactionButtonConfigurationId is set, the widget fetches that configuration row.
  2. If the configuration's enabled (desktop) or mobileEnabled (mobile) flag is off for the current device, nothing is injected.
  3. If pathRegex is set for the active device, the widget skips injection when the URL pathname doesn't match.
  4. The widget finds the selector CSS selector on the page, then renders the HTML template (visual-builder default or merchant-authored custom HTML) at the configured insertionPosition. The template contains a data-octocom-button-template element that the widget clones for each suggestion.
  5. Button labels are produced one of two ways:
    • AI (generateButtonsFromPageContext = true) — the backend resolves the URL to a product in the catalog, walks suggestionPrompts until it finds one whose urlPattern matches the URL, calls Gemini with that prompt and the product data, and caches the resulting list. If no product can be found for the URL, no buttons are rendered.
    • Manual (generateButtonsFromPageContext = false) — the strings in staticButtonTextValues (desktop) or staticButtonTextValuesMobile (mobile) are used verbatim.
  6. Each cloned button is hydrated with its label. If showSparkleIcon is on, a ✨ prefix is prepended. If includeAskSomethingElse is on, an extra "Ask something else" button is appended.
  7. Clicking any button opens the chat widget with the button label as the first user message.

Per-product AI suggestions are cached in Postgres (interactionButtonCaches), keyed by (productId, businessId, mobile, promptHash), so the LLM only runs once per (product, prompt) per device.


Singleton per business

Unlike virtual try-on, interaction buttons are a singleton per business — at most one row in interactionButtonConfigurations per business. The webChatConfig.interactionButtonConfigurationId FK is a pointer to that singleton, not a sentinel: the feature is turned on/off via enabled and mobileEnabled on the row itself, not by clearing the FK.

When the configuration is first written for a business, the singleton row is created and every webChatConfig for that business is pointed at it. Subsequent writes update the same row in place.


Desktop and mobile

Almost every field has a desktop and a mobile counterpart so the merchant can configure each device independently — different selectors, path regexes, HTML templates, static button labels, and sparkle-icon toggles.

When mirrorDesktopConfigToMobile is true (the default and the most common case), mobile reuses every desktop value at runtime — the mobile-specific fields on the row are ignored. When false, both sets of fields are read and mobile renders its own variant.

The mobileEnabled flag is independent of enabled — it's common to enable buttons on desktop and disable them on mobile (smaller viewport, less room for an extra UI element).


Per-field reference

Selector

selector (desktop, required) and selectorMobile (mobile, optional / required when not mirroring). CSS selector identifying the element to inject relative to. Comma-separate multiple selectors — the first match wins. Pick something stable across the merchant's product templates.

Insertion position

insertionPosition (desktop) and insertionPositionMobile (mobile). One of:

  • before — inserts as a sibling immediately before the target.
  • after — inserts as a sibling immediately after the target.
  • inside — appends as the last child of the target.
  • replace — replaces the target element entirely.

Page targeting (pathRegex)

pathRegex (desktop) and pathRegexMobile (mobile). Optional regex matched against window.location.pathname. When set, the buttons are only injected on matching pages. Common examples: ^/products/ to scope to product pages only, ^/en/ to scope to a locale. Leave null/empty to inject on every page.

Suggestion source

generateButtonsFromPageContext. When true, button labels are generated per-page by an LLM. When false, the labels in staticButtonTextValues (and staticButtonTextValuesMobile if not mirroring) are used verbatim.

Suggestion prompts (when AI is enabled)

suggestionPrompts is an ordered list of { urlPattern, prompt } entries. At runtime the backend walks the list and uses the first entry whose urlPattern matches the current URL. An entry with an empty urlPattern is a catch-all that matches every page.

The prompt is the system message sent to Gemini. It receives the product (as JSON) and must return an array of short strings to render as buttons. Use this to differentiate prompts per category (e.g. a "furniture" prompt that nudges the model to ask about dimensions and material vs. an "apparel" prompt that asks about fit and care).

When you save a new set of prompts, the per-product caches keyed by the removed prompt hashes are cleared in a background job so the next page view triggers regeneration.

Static labels (when manual is enabled)

staticButtonTextValues (desktop) and staticButtonTextValuesMobile (mobile). Plain string arrays — each entry becomes one button label, in order, identical on every page.

Ask something else

includeAskSomethingElse. When on, an extra button is appended after the suggestions. Clicking it opens the widget without a pre-filled question, so the customer can type anything.

Sparkle icon

showSparkleIcon (desktop) and showSparkleIconMobile (mobile). When on, a ✨ glyph is prepended to AI-generated labels (manual labels are left as-is).

Minimum price (USD)

minimumPriceUsd. Optional floor below which suggestion generation is skipped. Useful when the merchant has a long tail of low-value SKUs where suggestion buttons aren't worth the LLM cost.

Custom HTML

htmlIsCustom (desktop) and htmlIsCustomMobile (mobile). When false, the bundled visual-builder template is rendered — minimal CSS, sensible defaults, configurable via the dashboard's color pickers and sliders. When true, the merchant's HTML in htmlTemplateDesktop / htmlTemplateMobile is rendered as-is.

Custom HTML must include at least one element with data-octocom-button-template — the widget removes it from the DOM and clones it once per suggestion, setting each clone's textContent to the label. If the template has multiple elements with this marker, suggestions are distributed across them in order (useful for splitting buttons across multiple containers).

Optional markers:

MarkerElementPurpose
data-octocom-button-templateany elementCloned per suggestion. textContent is set to the label (or "✨ " + label when showSparkleIcon is on). Multiple markers split buttons across containers in order.
data-octocom-ask-something-else<button>The "Ask something else" button. Appended after the cloned suggestions if includeAskSomethingElse is on.

You don't write any JavaScript — the widget hydrates these markers at runtime and binds the click handlers. Anything without a marker is rendered as-is.


Managing via MCP

Three MCP tools cover the lifecycle:

ToolPurpose
get_interaction_buttons_configFetch the singleton config for a business. Returns null if the feature has never been configured.
upsert_interaction_buttons_configCreate or partial-update the config. First write creates a new row (required: selectorDesktop); subsequent writes are partial patches. Pointer FK on every webChatConfig for the business is updated to the singleton. Per-prompt caches are cleared in the background for removed prompts.
preview_interaction_buttons_for_urlRun the AI suggestion pipeline against a sample URL with bypassCache=true. Useful for iterating on suggestionPrompts before saving.

A typical end-to-end MCP flow for setting up a new business:

  1. Confirm webChatConfig exists for the business (web chat must be deployed first).
  2. upsert_interaction_buttons_config with enabled: false, selectorDesktop set to a stable selector, and the rest left at defaults. The row is created with the default catch-all suggestion prompt.
  3. Iterate on suggestionPrompts using preview_interaction_buttons_for_url to test different prompts against representative product URLs. Pass the candidate prompts directly to the preview call — don't bother saving between iterations.
  4. Once the prompts look good, upsert_interaction_buttons_config with the final suggestionPrompts.
  5. Tweak styling (visual builder or custom HTML) and the desktop/mobile split.
  6. Set enabled: true (and mobileEnabled if desired) to roll the feature live.

On this page