Product & User Context
Send relevant product and user data so the assistant can answer with better context.
Context lets the assistant understand who the user is and what they are viewing.
For page-type matrices, init fields, and the full runtime API table, see Host Integration API.
Send context during init
window.LoopsAI.q.push([
"init",
{
agentId: "YOUR_AGENT_ID",
productContext: {
productCode: "SKU-123",
productName: "Premium Headphones",
category: "audio",
},
userContext: {
id: "user-456",
email: "user@example.com",
name: "Jane Doe",
},
},
]);Update context dynamically
Use these methods when page state changes in a SPA, after login, or after product navigation.
window.LoopsAI.setProductContext({
productCode: "SKU-999",
productName: "Travel Backpack",
});
window.LoopsAI.setUserContext({
id: "user-789",
membership: "premium",
});You can also update both in one call:
window.LoopsAI.updateContext(
{
productCode: "SKU-777",
},
{
id: "user-789",
},
);Recommended fields
Product context
| Field | Type | Notes |
|---|---|---|
productCode | string | Loops catalog code for the product the shopper is viewing (must match your uploaded product catalog) |
productName | string | User-friendly display name; helps if code lookup needs a hint |
pageType | string | Set to PDP on product detail pages when using sidebar-on-PDP (see below) |
url | string | Optional; current PDP URL |
price | string | Optional; display price as a string if you already have it on the page |
currency | string | Optional; e.g. TRY, USD |
category | string | Optional but useful for hints |
User context
| Field | Type | Notes |
|---|---|---|
id | string | Stable internal user ID |
customerId | string | Legacy alias used in older setups |
email | string | Optional if available |
name | string | Optional |
membership | string | Optional segment or plan value |
Open as sidebar on product pages (PDP)
Some stores show the chat as a side panel on product detail pages instead of the default floating bubble. Your site controls this directly from code, per page — you decide which products get the sidebar.
1. Turn on sidebar mode for the page
Pass openAsSidebarOnProduct: true in your init config on the product pages where you want a sidebar. You set this yourself, per page, so some products can use the sidebar and others stay on the default bubble.
window.LoopsAI.q.push([
"init",
{
agentId: "YOUR_AGENT_ID",
openAsSidebarOnProduct: true,
productContext: { productCode: "YOUR_PRODUCT_CODE", pageType: "PDP" },
},
]);The same Open as Sidebar on Product Pages setting also lives in the configurator as a convenience for previewing the behavior while you test. The value you pass in init always wins, so you never have to enable it there.
2. Send pageType: "PDP" in product context
On every product detail page, include pageType: "PDP" in productContext (case-insensitive). Together with openAsSidebarOnProduct: true, the embed switches to sidebar mode for that page.
Context vs. auto-open
Sending pageType: "PDP" does not open the panel by itself. It only selects sidebar layout. Call LoopsAI.open() from your own button, or rely on ?loopsai_open=sidebar when the user lands from a product link inside the widget (see below).
Catalog product codes with PDP + sidebar
productCode must be the same code value as in your Loops agent product catalog (CSV upload or dashboard catalog). Storefront SKUs that differ from catalog codes will not resolve product details until they are mapped to catalog code.
Send string values only in productContext (numbers and arrays are not forwarded reliably to the chat backend).
Product page — catalog code + PDP + sidebar layout
/**
* Example: read the active variant from your PDP (data layer, JSON-LD, or DOM).
* Every code must exist in the Loops product catalog for the agent.
*/
function readPdpFromPage() {
const dataLayer = window.dataLayer?.find?.((e) => e.ecommerce?.detail?.products?.[0]);
const fromGtm = dataLayer?.ecommerce?.detail?.products?.[0];
return {
productCode: fromGtm?.id || document.querySelector("[data-catalog-code]")?.textContent?.trim() || "",
productName: fromGtm?.name || document.querySelector("h1")?.textContent?.trim() || "",
price: fromGtm?.price != null ? String(fromGtm.price) : "",
currency: fromGtm?.currency || "TRY",
url: window.location.href,
};
}
const pdp = readPdpFromPage();
window.LoopsAI = { q: [] };
window.LoopsAI.q.push([
"init",
{
agentId: "YOUR_AGENT_ID",
openAsSidebarOnProduct: true,
productContext: {
productCode: pdp.productCode, // e.g. "YOUR_PRODUCT_CODE" — Loops catalog code
productName: pdp.productName,
pageType: "PDP",
price: pdp.price,
currency: pdp.currency,
url: pdp.url,
category: "shirts",
},
userContext: {
id: "user-456",
},
},
]);
// Optional: open sidebar after init (pageType alone does not open the panel)
document.getElementById("loops-ask-btn")?.addEventListener("click", () => {
window.LoopsAI.open();
});Several catalog codes on one PDP (color / size swatches)
The assistant resolves the active catalog code via productCode. When the shopper selects another swatch, push the new code with updateContext (keep pageType: "PDP"):
function onVariantSelected(catalogCode, displayName) {
window.LoopsAI.updateContext(
{
productCode: catalogCode, // next Loops catalog code, e.g. "YOUR_OTHER_PRODUCT_CODE"
productName: displayName,
pageType: "PDP",
},
{ id: currentUserId },
);
}
// Example swatch handlers (replace with your storefront logic)
document.querySelectorAll("[data-catalog-code]").forEach((el) => {
el.addEventListener("click", () => {
onVariantSelected(el.dataset.catalogCode, el.dataset.productName);
});
});Hide the default bubble and use your own CTA (common on PDP)
// After embed.js loads, hide the floating bubble and open from your button:
// <button type="button" onclick="window.LoopsAI.open()">Ask about this product</button>If you hide the bubble, wait until the widget host exists (#loopsmart-ai-widget with a shadow root) before toggling #bubble display, same as any custom styling override.
Want this to happen automatically on a specific page (e.g., hide the bubble or bottom-bar only on checkout, restore it everywhere else)? See Host Integration API → Hide the widget on specific pages for the full pattern.
3. Update context on SPA route changes
When the user navigates client-side from a listing to a PDP (or between products), call updateContext so pageType and productCode stay in sync. The embed automatically opens the sidebar when all four conditions are true: the widget is in sidebar mode, openAsSidebarOnProduct: true is set, the user is navigating from a non-PDP page into a PDP (not PDP-to-PDP), and the panel is not already open.
function onRouteChange(route) {
if (route.name === "product") {
window.LoopsAI.updateContext(
{
productCode: route.params.sku,
productName: route.params.title,
pageType: "PDP",
},
{ id: currentUserId }, // same shape as init userContext
);
} else {
window.LoopsAI.setProductContext({
pageType: "PLP", // or omit pageType on non-PDP pages
});
}
}On non-PDP pages, omit pageType or send a value other than PDP so the widget does not stay in product-page sidebar behavior.
4. Optional URL trigger (loopsai_open=sidebar)
When sidebar-on-PDP is enabled in your published config, product links opened from inside the chat append ?loopsai_open=sidebar to the destination URL. On load, the embed script opens the sidebar automatically. You can use the same query param in tests:
https://your-store.com/products/example-shirt?loopsai_open=sidebar| Signal | Effect |
|---|---|
openAsSidebarOnProduct: true + pageType: "PDP" | Sidebar layout on PDP |
LoopsAI.open() | Opens the panel (any page) |
?loopsai_open=sidebar | Sidebar layout and auto-open on load |
Data minimization
Only send the fields required for conversation quality. Avoid sensitive personal data.
Continue to JavaScript API.