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
- The widget script loads on a page and reads the merchant's
webChatConfig. IfinteractionButtonConfigurationIdis set, the widget fetches that configuration row. - If the configuration's
enabled(desktop) ormobileEnabled(mobile) flag is off for the current device, nothing is injected. - If
pathRegexis set for the active device, the widget skips injection when the URL pathname doesn't match. - The widget finds the
selectorCSS selector on the page, then renders the HTML template (visual-builder default or merchant-authored custom HTML) at the configuredinsertionPosition. The template contains adata-octocom-button-templateelement that the widget clones for each suggestion. - Button labels are produced one of two ways:
- AI (
generateButtonsFromPageContext = true) — the backend resolves the URL to a product in the catalog, walkssuggestionPromptsuntil it finds one whoseurlPatternmatches 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 instaticButtonTextValues(desktop) orstaticButtonTextValuesMobile(mobile) are used verbatim.
- AI (
- Each cloned button is hydrated with its label. If
showSparkleIconis on, a ✨ prefix is prepended. IfincludeAskSomethingElseis on, an extra "Ask something else" button is appended. - 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:
| Marker | Element | Purpose |
|---|---|---|
data-octocom-button-template | any element | Cloned 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:
| Tool | Purpose |
|---|---|
get_interaction_buttons_config | Fetch the singleton config for a business. Returns null if the feature has never been configured. |
upsert_interaction_buttons_config | Create 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_url | Run 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:
- Confirm
webChatConfigexists for the business (web chat must be deployed first). upsert_interaction_buttons_configwithenabled: false,selectorDesktopset to a stable selector, and the rest left at defaults. The row is created with the default catch-all suggestion prompt.- Iterate on
suggestionPromptsusingpreview_interaction_buttons_for_urlto test different prompts against representative product URLs. Pass the candidate prompts directly to the preview call — don't bother saving between iterations. - Once the prompts look good,
upsert_interaction_buttons_configwith the finalsuggestionPrompts. - Tweak styling (visual builder or custom HTML) and the desktop/mobile split.
- Set
enabled: true(andmobileEnabledif desired) to roll the feature live.