Clueless Widget Integration
Launch the Clueless shopping assistant, configure script parameters, and connect your product feed.
Clueless Widget Integration Guide
Bring the Clueless conversational assistant to your storefront in just a few minutes. This guide covers the loader snippet, optional configuration flags, diagnostics, and how to ingest your product catalog so the assistant can answer inventory questions with confidence.
1. Add the loader snippet
Embed the loader script on every page that should host the widget. We recommend placing it as close to the end of the <head> element as possible so it boots as soon as the DOM becomes interactive.
<script
async
data-clueless-widget
data-merchant-key="your-merchant-key"
src="https://widget.clueless.chat/widget/loader.iife.js"
></script>The loader URL is stable — you never need to update your embed code to receive the latest widget changes.
Where to place the script
-
Direct HTML / platforms with template access – Paste the snippet right before
</head>in your global layout (e.g. Shopifytheme.liquid, WooCommerceheader.php, Custom React/Vue SSR template). -
Google Tag Manager – Create a Custom HTML tag, paste the snippet, trigger on All Pages, and publish. The loader works with both standard and consented container deployments.
-
Single-page applications (React, Vue, Next.js, etc.) – Dynamically inject the script once after hydration:
const script = document.createElement("script"); script.async = true; script.setAttribute("data-clueless-widget", ""); script.setAttribute("data-merchant-key", "your-merchant-key"); script.src = "https://widget.clueless.chat/widget/loader.iife.js"; document.head.appendChild(script);
2. Generate a preconfigured snippet
Use the generator to pre-fill the required merchant key and any optional parameters before handing the code to your developers or agency partners.
Embed Code Generator
<script
async
data-clueless-widget
data-merchant-key="your-merchant-key"
data-mode="fab"
src="https://widget.clueless.chat/widget/loader.iife.js"
></script>Where to add this code:
- Direct HTML: Add to your website's
<head>section - Google Tag Manager: Create a Custom HTML tag with "All Pages" trigger
- React/Vue/Angular: See the integration guide for framework-specific instructions
3. Loader attributes & query parameters
Customize behaviour by adding data attributes to the <script> tag. All options also support query-string equivalents on the loader URL.
| Attribute | Type | Default | When to use |
|---|---|---|---|
data-merchant-key | string | Required | Merchant identifier that tells the CLJ backend which catalog/config to use. This should be part of every production embed snippet. |
data-server-url | URL | unset | Legacy backend base URL. When set, the loader derives <server-url>/chat; new embeds should prefer data-chat-endpoint. ?serverUrl=https://api.example.com also works. |
data-chat-endpoint | URL | https://clueless-backend.gcp.clueless.chat/chat | Provide a fully qualified chat endpoint when you are explicitly testing a different backend. |
data-mode | fab | floating | expanded | fab | Control the initial resting state. fab is the safe default for merchant sites with sticky mobile CTAs. |
data-launcher | auto | none | auto | Hide the built-in FAB/floating launcher when your page owns the launch button. The widget still boots and can be opened through host triggers or window.cluelessWidget. |
data-primary-selector | gender | none | merchant default | Optional override for the first-class selector shown above the prompt. If omitted, the widget uses the merchant-specific default from GET /widget/experience?merchant=<merchantKey>. |
data-fab-color-scheme | default | inverted | default | Swap the resting FAB from the default frosted light shell to a solid trigger-colored treatment. Useful when the host page background makes the default FAB disappear. |
data-fab-position | preset string | auto | Anchor the resting FAB independently of the opened floating prompt. When omitted, the loader defaults to middle-right on compact viewports and bottom-right on larger ones. |
data-floating-position | preset string | bottom-center | Anchor the floating prompt independently of the FAB. This preserves the old bottom-centered dock behavior by default. |
data-fab-offset-inline / data-fab-offset-block | CSS length | unset | Nudge the FAB anchor without abandoning preset-based placement. |
data-floating-offset-inline / data-floating-offset-block | CSS length | unset | Nudge the floating prompt anchor independently of the FAB. |
data-css | URL path | /widget.css | Serve a tenant-specific stylesheet for the iframe shell. Useful for brand-specific theming. |
data-iframe | URL | <loader-origin>/app/ | Override the iframe location (e.g. QA builds hosted on Vercel). |
data-debug | boolean | false | Enable verbose console logging. Setting the attribute with no value or data-debug="true" turns logging on; ?debug=1 does the same. |
data-ga-id / data-ga-secret | strings | null | Wire Google Analytics 4 measurement IDs and secrets so widget events forward into your GTM data layer after consent. |
Tip: the loader copies all
data-*attributes onto its Shadow DOM host. You can safely set custom attributes for your own telemetry as long as they are prefixed withdata-.
Today the only built-in selector is gender. Disabling it with data-primary-selector="none" leaves the stock/inventory controls intact and avoids biasing the assistant toward a default gender, while omitting the attribute lets the merchant backend decide the default. Separately, data-fab-color-scheme="inverted" switches the resting launcher to the merchant trigger color when the default frosted shell needs more contrast.
4. Programmatic control and lifecycle events
Once the iframe signals readiness, the loader exposes a controller at window.cluelessWidget:
window.cluelessWidget?.open();
window.cluelessWidget?.close();
window.cluelessWidget?.toggle();
window.cluelessWidget?.minimize();
window.cluelessWidget?.setMode("floating");
window.cluelessWidget?.open({ mode: "expanded", triggerId: "hero-style" });
window.cluelessWidget?.prompt({
text: "Create a full outfit around this product",
mode: "expanded",
submit: true,
triggerId: "pdp-style-submit",
});
const context = window.cluelessWidget?.getContext();open() opens the primary chat surface. With data-launcher="none", open() defaults to expanded because there is no Clueless-owned resting launcher. Pass { mode: "floating" } when a host control should reveal the compact prompt instead. close() steps back one level. minimize() returns to the resting launcher, or hides the frame again when data-launcher="none" is active.
postMessage() is available for typed widget protocol messages, but ordinary integrations should use the controller helpers above.
Merchant-owned buttons and links
You can control the widget from ordinary host-page elements by adding Clueless data attributes. The loader listens at the document level, so elements rendered later by a CMS, tag manager, or SPA route still work.
Keep the default launcher and add a product CTA:
<button
type="button"
data-clueless-widget-trigger="open"
data-clueless-widget-mode="expanded"
data-clueless-widget-trigger-id="pdp-style-this"
>
Style this product
</button>Hide the built-in launcher and use only merchant-owned controls:
<script
async
data-clueless-widget
data-merchant-key="your-merchant-key"
data-launcher="none"
src="https://widget.clueless.chat/widget/loader.iife.js"
></script>
<button
type="button"
data-clueless-widget-trigger="open"
data-clueless-widget-mode="expanded"
>
Ask our stylist
</button>Submit a product-specific prompt from a host element:
<button
type="button"
data-clueless-widget-trigger="prompt"
data-clueless-widget-mode="expanded"
data-clueless-widget-prompt="Create a full outfit around this product"
data-clueless-widget-submit="true"
data-clueless-widget-trigger-id="pdp-outfit-submit"
>
Build an outfit
</button>Supported trigger actions are open, toggle, close, minimize, set-mode, and prompt. Prompt triggers require data-clueless-widget-prompt; data-clueless-widget-submit="true" sends immediately, while any other value only prefills the prompt. Prompt triggers can include data-clueless-widget-product-id to send chat metadata.productId. For non-button elements, add role="button" and tabindex="0" so Enter and Space work. Anchor triggers prevent navigation by default; set data-clueless-widget-prevent-default="false" when the link should still navigate.
Product suggested prompts
On product pages, add a placeholder when you want Clueless to show product-specific question buttons. The loader fetches questions lazily when the block approaches the viewport, then renders host prompt buttons into the placeholder. Clicking a question opens the widget in expanded mode and submits that question through the same controlled prompt path shown above.
<div
data-clueless-suggested-prompts
data-clueless-suggested-prompts-title="Vanliga frågor"
></div>By default, the loader resolves the product id from page context. On product pages this includes JSON-LD Product markup, using sku or productID when present. Add data-clueless-product-id only when the storefront does not expose usable product markup or when you need to force a specific backend article id. The request uses the same backend origin as chat and sends Accept-Language from data-clueless-suggested-prompts-language, page context locale, document language, or browser language.
Suggested question clicks forward the same resolved product id as chat metadata.productId. When that id resolves to a backend article, the assistant treats that product as already shown and can answer suggested questions from the current product data.
The placeholder receives data-clueless-suggested-prompts-state="idle|loading|ready|empty|error|skipped" and aria-busy while loading so storefront code can style or inspect it. If no buttons appear, verify that the product id exists, that the backend has related questions for the article, and that the storefront origin is allowed by backend CORS.
Listen for lifecycle events if you need to coordinate UI changes or analytics:
clueless-widget-ready– Fired after the iframe confirms it mounted successfully.event.detail.controllercontains the same controller instance shown above.clueless-widget-error– Fired if the iframe fails to boot (network errors, authorization, CSP violations).
window.addEventListener("clueless-widget-ready", (event) => {
console.info("Widget ready", event.detail.controller.getContext());
});
window.addEventListener("clueless-widget-error", (event) => {
console.error("Widget failed to load", event.detail);
});Product card navigation (SPA-friendly)
When a shopper clicks a product card inside the widget, the loader emits a cancelable event on the host window:
- Event name:
clueless-widget-navigate event.detail.url: fully-qualified URL that includesutm_source=cluelessandutm_medium=widget(we overwriteutm_sourceif it already exists)event.detail.action:"push"or"replace"event.detail.source:"product_card"
If your storefront is an SPA (Next.js / React Router / Vue Router / etc.), listen for this event, call event.preventDefault(), and route using your framework so the page updates without reloading the widget.
window.addEventListener("clueless-widget-navigate", (event) => {
const { url, action, source } = (event as CustomEvent<{
url?: string;
action?: "push" | "replace";
source?: string | null;
}>).detail ?? {};
if (source !== "product_card" || !url) {
return;
}
const target = new URL(url);
// Tell the widget loader "we'll handle this navigation"
event.preventDefault();
// Example (React Router / your router API here):
// navigate(`${target.pathname}${target.search}${target.hash}`, { replace: action === "replace" });
});If you don’t prevent the default, the loader will fall back to window.location.* navigation (MPA-safe). For MPAs, the widget restores its open state + chat state after the page transition.
Cross-document view transitions (optional)
If your storefront uses same-origin server navigations, you can progressively enhance widget-originated PDP transitions with the browser View Transitions API. This is a host-page opt-in, not a widget-only feature.
Add this to the merchant theme CSS on pages that participate in the transition:
@view-transition {
navigation: auto;
}That alone is enough for browsers with cross-document View Transition support
to animate same-origin page navigations triggered by the widget's default
window.location.* fallback.
If you want to route widget-originated navigations differently from ordinary page clicks, attach a host-side listener and mark the transition before navigating:
<script>
window.addEventListener("clueless-widget-navigate", (event) => {
const detail = event.detail ?? {};
if (detail.source !== "product_card" || !detail.url) {
return;
}
sessionStorage.setItem(
"clueless-widget-transition",
JSON.stringify({
kind: "product_card",
action: detail.action ?? "push",
url: detail.url,
at: Date.now(),
})
);
});
</script>Important limitations:
- The widget iframe is cross-origin, so browsers cannot do a native shared element transition from a product card inside the widget to a PDP image on the merchant page.
- The realistic first step is a page-level transition between same-origin documents.
- Advanced typed transitions using
pageswap/pagerevealrequire early host scripts in the merchant document, not the async widget loader. - Unsupported browsers will keep the current behavior automatically.
5. Verify your installation
- Open the site in an incognito window and confirm the widget loads as a compact FAB instead of a full-width prompt dock.
- Click the FAB and ask “Show me something new from your favourite brand” to validate that conversations start.
- Open DevTools (top-level browsing context) and run
window.cluelessWidget?.getContext()– you should see product/route metadata for the current page. - If the merchant has a sticky mobile CTA, move the resting FAB with
data-fab-positionor the FAB offset overrides so it sits outside that collision zone without disturbing the floating prompt dock. - Check for console warnings or CSP violations; if you see blocked resources, allow requests to
widget.clueless.chatand your configured API host. - Inspect your GTM
dataLayerfor entries withevent: "clueless_widget_event"and the expectedevent_namewhen the assistant opens, closes, submits prompts, or navigates.
6. Troubleshooting checklist
- Widget never appears: verify the script tag includes
data-clueless-widgetanddata-merchant-key, there are no duplicate CSP rules, and the script is not blocked by an ad blocker. Addingdata-debugwill print loader progress to the console. - Stuck after opening the widget – confirm the site can reach your Clueless chat host (no mixed-content or firewall blocks) and that any optional
data-chat-endpointoverride is correct. - Clicking product card links fails: for SPAs, ensure you handle
clueless-widget-navigateand call your router; for MPAs, ensure your site permitswindow.location.*redirects from scripts and that PDP URLs exist in your product feed (see next section). - Multiple widgets render: only include one loader snippet per page. Remove older snippets from tag managers or theme partials.
7. Keep the product feed in sync
The assistant relies on a structured product feed so it can recommend in-stock items. Provide at least one of the following to the Clueless team:
- Hosted feed URL – We accept Google Merchant-style RSS/Atom XML feeds. Each item should include
id,title,description,link,price,availability,image_link,brand,product_type, and gender indicators when available. - Locale configuration – If you sell in multiple markets, supply price/locale multipliers or let us know which currency to prioritize. We normalize prices to cents internally.
- Authentication, if required – Share HTTP basic credentials or signed URLs if the feed is not publicly accessible.
Once your feed is ready:
- Sign in to the Clueless Merchant Admin and open Catalog → Product Feed.
- Paste the secure feed URL, choose the default currency, and save.
- We queue the ingestion job immediately—no API calls or emails required.
You can revisit the same screen to see the latest sync status, next scheduled crawl, and any validation errors we detected (missing prices, unreachable images, etc.). Failed rows can be downloaded as a CSV for quick remediation.
8. What happens next?
- Dashboard analytics will start populating as soon as customers interact with the assistant.
- You can customize greetings, suggested prompts, and brand priorities from the Clueless dashboard or through your customer success manager.
- As your product feed changes, e.g. due to changes in inventory or new products being added, the ingestion will re-run using a nightly scheduler, so the assistant always stays up to date.
Still have questions? Reach us at support@clueless.chat – we reply within one business day.