Context updates

Push live storefront context — a client-created cart_id, available offers, the current page — into an open Buddy Assist session without spending an LLM turn.

The storefront often knows things mid-conversation that the agent should use: the shopper just created a cart client-side, there’s a coupon available, they’re looking at a specific product. Context updates let you push that into a live session without sending a message — no LLM turn, no chat bubble. The agent picks it up on the shopper’s next message.

There are two kinds of context, and they go to two different places:

KindWhat it isExampleGoes to
StateIdentifiers the agent threads into tool calls — the shopper never reads themcart_id, checkout_id, selected variantagent_session_state.data
FactsAmbient hints the model reasons overavailable offers, cart summary, current page, localea clearly-delimited, untrusted context block

Next-turn-only

A context push silently stages state/facts; the agent uses them on the shopper's next message. It never triggers an unprompted reply.

The API

After the widget mounts it exposes the same control surfaces as the imperative API — a global, a DOM method, a CustomEvent, and postMessage. Every one of them funnels into the same context-push path.

window.BreezeAssist global

The recommended option for Shopify theme scripts, GTM custom HTML tags, and third-party snippets that don’t own the element reference:

// Full patch — state, facts, or both.
window.BreezeAssist.updateContext({
  state: { cart_id: 'gid://shopify/Cart/abc123' },
  facts: { offers: [{ code: 'WELCOME10', label: '10% off first order' }] }
});

// Sugar for the two common cases:
window.BreezeAssist.setCartId('gid://shopify/Cart/abc123');
window.BreezeAssist.setFacts({ offers: [{ code: 'WELCOME10' }] });

setCartId(id) is shorthand for updateContext({ state: { cart_id: id } }), and setFacts(facts) for updateContext({ facts }).

DOM method

If you hold the element reference, call the method directly:

const el = document.querySelector('breeze-buddy-assist');
el.updateContext({ state: { cart_id: 'gid://shopify/Cart/abc123' } });

CustomEvent (GTM / tag managers)

Dispatch a breeze-buddy-assist:context event on document — same pattern as the breeze-buddy-assist:command event:

document.dispatchEvent(
  new CustomEvent('breeze-buddy-assist:context', {
    detail: { state: { cart_id: 'gid://shopify/Cart/abc123' } }
  })
);

postMessage (iframes)

From a cross-origin context or an iframe:

window.parent.postMessage(
  {
    type: 'breeze-buddy-assist',
    action: 'context',
    detail: { facts: { offers: [{ code: 'WELCOME10' }] } }
  },
  '*'
);

Pushed before the panel opens? No problem.

If you push context before the shopper has opened the widget (no session exists yet), the widget buffers the latest patch and flushes it the moment the session is created — latest-wins, so a burst of cart edits collapses to the current truth.

Patch shape

type ClientContextPatch = {
  state?: Record<string, unknown>;
  facts?: Record<string, unknown>;
  merge?: 'shallow' | 'replace'; // default 'shallow'
  placement?: 'user_tail' | 'system'; // default 'user_tail'
};
FieldDefaultNotes
stateIdentifiers shallow-merged into the session’s runtime state. Only keys on the template’s state_allowlist are accepted; everything else is dropped.
factsAmbient hints, allowlisted + size-capped server-side. Non-allowlisted keys are dropped (and reported back so you can see what landed).
merge'shallow''shallow' merges top-level keys (latest-wins per key); 'replace' swaps the whole namespace.
placement'user_tail'Where rendered facts land. 'user_tail' frames them as data; 'system' requests instruction-strength adherence — honored only for keys on the template’s trusted_facts list, so shopper-supplied data can never be elevated to instructions.

Example — push a client-created cart_id

A shopper adds an item via the Storefront / Ajax API, which mints a cart_id on the page. Push it so the agent reuses that cart instead of creating a duplicate:

// After your add-to-cart call resolves:
async function onCartCreated(cart) {
  window.BreezeAssist.setCartId(cart.id);
}

The template’s tool-arg injection rule fills that cart_id into the next update_cart / checkout tool call automatically — the agent never has to ask “which cart?” and never creates a second one.

cart_id is safe to trust

A cart_id is just a handle — the agent re-fetches the authoritative cart from Shopify before acting on it. That's why it's the canonical first entry on the state_allowlist.

Example — push available offers

The page knows which coupons the shopper is eligible for. Surface them as facts so the agent can mention them:

window.BreezeAssist.setFacts({
  offers: [
    { code: 'WELCOME10', label: '10% off your first order' },
    { code: 'FREESHIP', label: 'Free shipping over ₹2,000' }
  ],
  cart_summary: { item_count: 3, subtotal_display: '₹4,500' },
  current_page: { type: 'product', title: 'Cabin Trolley 55cm', handle: 'cabin-trolley-55' }
});

The agent now knows there’s a WELCOME10 offer and can bring it up when the shopper asks about discounts.

Facts are untrusted hints

Storefront JS is shopper-editable, so pushed facts are treated as untrusted data: allowlisted, size-capped, and rendered as a clearly-delimited block the model is told to consider, never obey. Anything money-related — offer eligibility, prices, discounts — is re-validated server-side against Shopify before the agent applies it. A pushed offer is a hint to surface, not authoritative truth. Which keys are allowed (and which may use system placement) is gated by the template's client_context config.

Piggyback on a message

For the “create a cart, then immediately ask about it” flow, ride the patch along with the message so it applies to that turn — no separate round-trip. Pass context to send when using the SDK directly:

import { createBuddyChatStore } from '@juspay/breeze-buddy-client-sdk';

const chat = createBuddyChatStore({ publicWidgetKey, shopUrl });

await chat.send('Is my cart eligible for free shipping?', {
  context: { state: { cart_id: 'gid://shopify/Cart/abc123' } }
});

The server merges the patch before building the turn, so the very message that references the cart already has it.


SDK reference

If you’re driving the session through the SDK rather than the widget element, updateContext lives on both the widget session and the store:

const result = await chat.updateContext({
  state: { cart_id: 'gid://shopify/Cart/abc123' },
  facts: { offers: [{ code: 'WELCOME10' }] }
});

// result echoes the keys the server actually accepted after filtering:
// { applied: true, stateKeys: ['cart_id'], factsKeys: ['offers'], revision?: number }

updateContext does not mutate the message list — context updates don’t render. It maps the standard widget errors: 409 (another op holds the per-session lock — safe to retry), 410 (session ended), 413 (facts payload over the size cap), and 401 / 403 (auth).

Endpoint

POST /agent/voice/breeze-buddy/widget/session/{id}/context

Called by the embed with the widget_token bearer — you don’t call it directly unless you’re building your own client. Request body is the ClientContextPatch shape above, plus an optional monotonic revision so stale writes are dropped when pushes race. The response echoes the accepted keys:

{
  "applied": true,
  "state_keys": ["cart_id"],
  "facts_keys": ["offers", "cart_summary"],
  "revision": 7
}
Was this helpful?