Reference

Embed reference

Every attribute, CSS token, custom event, and imperative method exposed by the <breeze-buddy-assist> custom element.

<breeze-buddy-assist> is a Svelte 5 custom element that renders inside a Shadow DOM, so host-page CSS cannot bleed in and widget CSS cannot bleed out.


Attributes

All attributes map to Svelte component props. Attribute names are kebab-case; the internal prop name is camelCase.

Required

AttributeTypeDescription
tenantstringThe public_widget_key from your widget_config row. Identifies the merchant and the allowed-origin list to verify against.
api-basestringBase URL of the Clairvoyance backend. Default: https://clairvoyance.breezelabs.app.

Session

AttributeTypeDefaultDescription
shopstring"unknown.myshopify.com"The .myshopify.com permanent domain of the Shopify store. Forwarded to the template as template_vars.shop_url and used to scope the Shopify MCP tools. Required for Shopify storefronts; safe to omit on non-Shopify sites.
customer-tokenstring""Optional short-lived token minted by your backend that carries customer identity (e.g. Shopify customer ID, email). Forwarded to the template as template_vars.shopify_customer_token; not validated by the widget itself.

Modes

AttributeTypeDefaultDescription
modesstring"text,voice"Comma-separated list of enabled channels. Currently supported values are text and voice. Pass "text" to hide the voice button.
default-mode"text" \| "voice""text"Which mode is active when the panel first opens.

Appearance

AttributeTypeDefaultDescription
theme"light" \| "dark""light"Colour scheme. The widget respects this attribute, not the OS prefers-color-scheme; sync them yourself if you want auto dark mode.
position"bottom-right" \| "bottom-left""bottom-right"Which viewport corner the launcher anchors to.
offset-xCSS length"24px"Horizontal distance from the chosen edge. Accepts any CSS length (24px, 2%, 3vh, calc(…)).
offset-yCSS length"24px"Vertical distance from the bottom edge.
launcher-style"mascot" \| "solid""mascot""mascot" — pearly orb with eyes. "solid" — oil-slick sunset orb, no face.
launcher-labelstring"Talk to an Agent"CTA text on the launcher pill. Set to "" to collapse the pill to a bare orb.
AttributeTypeDefaultDescription
header-titlestring"Buddy Assist"Text shown next to the logo in the chat header. Set to your merchant / brand name.
header-logo-urlstringURL of a square merchant logo image shown in the chat header. Replaces the default mascot orb. Rendered at 22 × 22 px with a circular crop; use a 44 × 44 px image at 2× for sharpness on retina screens.

Theming

Each prop sets a CSS custom property on the shadow host. If unset the widget falls back to its built-in light/dark token defaults. A pinned brand colour wins over both light and dark defaults, so the colour won’t shift when theme flips.

AttributeCSS variableAffects
primary-color--primary-colorAccent colour — send button, active states, focus rings
surface-color--surface-colorChat panel background
text-color--text-colorPrimary text
muted-text-color--muted-text-colorSecondary / placeholder text
user-bubble-bg--user-bubble-bgUser message bubble background
user-bubble-fg--user-bubble-fgUser message bubble text

For finer control, set any --bb-* / --fg-* / --surface-* token directly via an inline style attribute on the host element:

<breeze-buddy-assist
  style="--bb-launcher-glow-color: #6c47ff40"
  tenant=""
  api-base=""
></breeze-buddy-assist>

Development

AttributeTypeDefaultDescription
mockbooleanfalseDeprecated as of client-sdk 0.3.0 — the mock transport was retired with the SpecStream migration. Setting mock="true" logs a console warning and falls through to the real transport.

Declarative open

Add the bare open HTML attribute to start the widget open on page load. This is a one-shot read on mount — toggling the attribute after mount has no effect; use the imperative API instead.

<breeze-buddy-assist open tenant="" api-base=""></breeze-buddy-assist>

Imperative API

After the widget mounts it exposes three ways to control it from any script on the page. All three support the same actions: open, close, reset.

1 — DOM method (same-page scripts)

The simplest option. Query the element and call the method directly:

const el = document.querySelector('breeze-buddy-assist');

el.open();   // open the panel
el.close();  // close the panel (session + history preserved)
el.reset();  // close and destroy the current session

reset() is client-side only — the server session stays ACTIVE until idle-timeout. Call POST /widget/session/{id}/end for immediate server cleanup.

2 — window.BreezeAssist global

The widget publishes a global so any script — including ones that load before or after the element — can call it without querying the DOM:

window.BreezeAssist.open();
window.BreezeAssist.close();
window.BreezeAssist.reset();
window.BreezeAssist.isOpen(); // returns boolean

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

3 — CustomEvent (GTM / tag managers)

Dispatch a breeze-buddy-assist:command event on document. Works from Google Tag Manager custom HTML tags, Segment, or any tool that can run document.dispatchEvent:

document.dispatchEvent(
  new CustomEvent('breeze-buddy-assist:command', {
    detail: { action: 'open' }   // 'open' | 'close' | 'reset'
  })
);

4 — postMessage (iframes)

If your page embeds the storefront in an iframe, or you need to trigger from a cross-origin context, post a message to the parent window:

// From inside an iframe:
window.parent.postMessage(
  { type: 'breeze-buddy-assist', action: 'open' },  // 'open' | 'close' | 'reset'
  '*'
);

Trigger from a button

The most common use-case — a CTA button elsewhere on the page opens the widget:

<button id="open-chat">Chat with us</button>

<breeze-buddy-assist
  tenant="pk_live_…"
  api-base="https://clairvoyance.breezelabs.app"
></breeze-buddy-assist>
<script src="https://widget.breezebuddy.com/assist.js" async></script>

<script>
  document.getElementById('open-chat').addEventListener('click', () => {
    window.BreezeAssist.open();
  });
</script>

To hide the default launcher FAB when using your own button, listen for ready and then hide it:

document.querySelector('breeze-buddy-assist').addEventListener(
  'breeze-buddy-assist:ready',
  () => document.getElementById('open-chat').style.display = 'none'
);

React / framework usage

import { useEffect } from 'react';

export function ChatButton() {
  return (
    <button onClick={() => (window as any).BreezeAssist?.open()}>
      Chat with us
    </button>
  );
}

Or typed properly:

declare global {
  interface Window {
    BreezeAssist?: {
      open(): void;
      close(): void;
      reset(): void;
      isOpen(): boolean;
    };
  }
}

Custom events

All events are dispatched on the host element (outside the Shadow DOM) with bubbles: true and composed: true, so standard addEventListener on the element or any ancestor catches them.

Event names are prefixed with breeze-buddy-assist:.

Eventdetail shapeWhen
breeze-buddy-assist:readyundefinedElement mounted. Fires before any session is created.
breeze-buddy-assist:openundefinedPanel opened.
breeze-buddy-assist:closeundefinedPanel closed.
breeze-buddy-assist:message{ role: "user" \| "assistant", content: string, sessionId: string \| null }A message was sent or received. Fires for both sides of the conversation.
breeze-buddy-assist:error{ error: string, code: string }An error occurred. See error codes below.
breeze-buddy-assist:open-url{ url: string, target: "_self" \| "_blank", reason?: string, lifecycle?: string }The agent asked to navigate to a URL (via a generative-UI action). The event is cancelable — call event.preventDefault() to intercept the navigation. If not cancelled the widget opens the URL via window.open.

Error codes

CodeDescription
voice_live_conflictA chat message was sent while a voice attachment was live, or vice versa. The two channels are mutually exclusive.
turn_exceptionAn unhandled exception was thrown during the chat turn.
session_errorA generic error emitted by the SDK session.

Example — analytics tap

document.querySelector('breeze-buddy-assist').addEventListener(
  'breeze-buddy-assist:message',
  (e) => {
    analytics.track('chat_message', {
      role: e.detail.role,
      sessionId: e.detail.sessionId
    });
  }
);
document.querySelector('breeze-buddy-assist').addEventListener(
  'breeze-buddy-assist:open-url',
  (e) => {
    e.preventDefault(); // stop the widget from calling window.open
    myRouter.push(e.detail.url); // handle with your SPA router
  }
);
Was this helpful?