JavaScript API
Reference for the window.Yedric global and the yedric-widget element, including how to open the chat, send prompts, and use setConfig and getConfig.
Once widget.js loads, two entry points are available:
window.Yedric: global object, works with any widget instance on the page.- The
<yedric-widget>element itself: useful when you want to target a specific instance or callsetConfig/getConfig.
window.Yedric
Section titled “window.Yedric”interface YedricGlobal { open(prompt?: string, persist?: boolean): void; close(persist?: boolean): void; toggle(state?: 'open' | 'closed'): void; getSessionId(): string | null; refresh(): void; on(eventName: string, callback: (eventName: string, data: unknown) => void): void; off(eventName: string, callback: (eventName: string, data: unknown) => void): void; setPreviewPageUrl(url: string | null | undefined): void; addContext(context: Record<string, unknown>): void; attachResource(uri: string, params?: Record<string, unknown>): void; registerClientTool( toolName: string, handler: (ctx: { toolCallId: string; toolName: string; args: unknown }) => Promise<unknown> | unknown, ): void; unregisterClientTool(toolName: string): void; event(name: string, payload?: Record<string, unknown>, opts?: { dedupeKey?: string }): void; eventStats(): ClientEventStats;}Yedric.open(prompt?, persist?)
Section titled “Yedric.open(prompt?, persist?)”Open the panel. If prompt is provided, it’s sent as a user message after the panel opens.
prompt |
persist |
Result |
|---|---|---|
| omitted | any | Open the panel. Existing thread preserved. No message sent. |
string |
false (default) |
Clear the thread, open the panel, send prompt as a new chat. |
string |
true |
Open the panel, keep existing messages visible, send prompt as a follow-up. |
Yedric.close(persist?)
Section titled “Yedric.close(persist?)”Minimize the panel to the launcher (or, if Hide beacon is enabled in Widget → Configure, just close it).
Pass persist: true to keep the current conversation, so the next open resumes the existing thread instead of showing a fresh prompt screen. Omitted or false, a later Yedric.open() with no arguments starts a new chat.
window.Yedric.close(true); // keep the threadwindow.Yedric.open(); // …and pick it back upYedric.toggle(state?)
Section titled “Yedric.toggle(state?)”Flip the panel open/closed. Pass 'open' or 'closed' to force a specific state.
Yedric.getSessionId()
Section titled “Yedric.getSessionId()”Returns the active conversation’s session id: the secure session id in secure mode, otherwise the anonymous browser session id, or null before a session exists. Use it to hand the active conversation off to another widget instance (see Secure Mode → Carrying a conversation across widget instances).
Yedric.refresh()
Section titled “Yedric.refresh()”Re-fetch the active secure thread’s messages from the server and replay them into the panel. Useful when another widget instance (e.g. a separate iframe on the same page) appended to the same thread and you want this instance to catch up. No-op outside secure mode or when there is no active session.
// after a fullscreen editor (its own widget instance) closes:window.Yedric.refresh();Yedric.on(eventName, callback)
Section titled “Yedric.on(eventName, callback)”Register a listener for widget events. See Events below.
window.Yedric.on('message_update', (eventName, data) => { console.log(data.content); // assistant message so far});The callback signature is (eventName, data), so the event name is repeated as the first argument for convenience. Listeners are additive.
Yedric.off(eventName, callback)
Section titled “Yedric.off(eventName, callback)”Remove a listener previously registered with Yedric.on. Pass the same event name and the same callback reference you registered.
function onOpen(name, data) { /* … */ }window.Yedric.on('open', onOpen);// …laterwindow.Yedric.off('open', onOpen);Yedric.setPreviewPageUrl(url)
Section titled “Yedric.setPreviewPageUrl(url)”Override window.location for page prompt matchUrl/ignoreUrl matching, suggestion {URL}/{{var}} templating, and the siteUrl field on POST /api/chat. Pass null, undefined, or '' to clear the override.
window.Yedric.setPreviewPageUrl('https://example.com/checkout');// …laterwindow.Yedric.setPreviewPageUrl(null); // back to window.locationYedric.addContext(context)
Section titled “Yedric.addContext(context)”Inject extra key/value context into the next chat request. The context object is merged with any existing context and sent as the context field on POST /api/chat. The assistant’s backend can surface these values in the system prompt via variable expansion.
window.Yedric.addContext({ currentPlan: 'pro', shopDomain: 'example-store.myshopify.com', cartItemCount: 3,});Context is additive, so each call merges into the existing map. Pass an empty object {} to replace without clearing (context persists across messages until the page reloads). Context is not cleared when the thread is reset via Yedric.open(prompt). It persists until the page reloads or you overwrite the keys via another addContext() call. Use this to pass page-level state the assistant should know about without including it in the user’s message.
Yedric.attachResource(uri, params?)
Section titled “Yedric.attachResource(uri, params?)”Attach an MCP resource to the current conversation by its URI. The backend loads the resource’s content into the assistant’s system context for the rest of the chat, so the assistant can reference it without a tool call. Optional params are merged into the widget context and used to substitute {{var}} placeholders in the resource’s path.
window.Yedric.attachResource('mesa://automations/12123', { _id: 123 });Use this to give the assistant the specific record the user is looking at (the automation, order, or document on screen) the moment the panel opens. When the resource loads, a resource_response event fires.
Yedric.registerClientTool(toolName, handler)
Section titled “Yedric.registerClientTool(toolName, handler)”Run a custom HTTP tool in the host page instead of having the server call it. See Advanced Configuration → Client-side tool execution for the full flow.
window.Yedric.registerClientTool('Contact_Support', ({ toolCallId, toolName, args }) => { window.HostApp.openSupportModal(); return 'Support modal opened.';});Yedric.unregisterClientTool(toolName)
Section titled “Yedric.unregisterClientTool(toolName)”Remove a previously registered handler.
Yedric.event(name, payload?, opts?)
Section titled “Yedric.event(name, payload?, opts?)”Report an app event to the assistant, fire and forget. This is the host-to-assistant direction; it is unrelated to Yedric.on, which observes widget events in the other direction. See Client Events for the full pipeline: gating, batching, the per-agent event definitions, and how the assistant reacts.
window.Yedric.event('test_run_halt', { automation_id: '68a1f0…', run_id: '68b2c1…', state: 'paused',});Semantics the host can rely on:
- Dropped unless the panel is open and the current conversation has at least one user message. An event never opens the panel and never creates a conversation.
- Events are batched for about 2 seconds and coalesced: a newer event with the same
opts.dedupeKeyreplaces the queued one. The default key is`${name}:${payload.automation_id ?? ''}`, so repeat events for one entity keep only the latest state. - The event name must be defined on the agent (
plugins/{server}/events/*.json); unknown names are dropped server-side. - May produce no visible reply: the server can decide the events are background context or noise.
- Payloads must contain only identifiers and enums, never customer data. They reach the model, the conversation store, and the browser console.
Yedric.eventStats()
Section titled “Yedric.eventStats()”Returns page-lifetime counters for the Yedric.event delivery funnel. Pairs with the [Yedric events] console lines for debugging; see Client Events → Debugging.
interface ClientEventStats { enqueued: number; // events accepted into the queue coalesced: number; // queued events replaced by a newer same-key event dropped: { notInitialized: number; panelClosed: number; noConversation: number; gatesAtFlush: number; queueOverflow: number; nonRetryableStatus: number; retriesExhausted: number; }; flushes: { attempted: number; retried: number }; verdicts: { respond: number; context: number; ignore: number; ignoreReasons: Record<string, number> }; turns: { started: number; handoffRejected: number; gaveUp: number };}Event-count fields (enqueued, dropped.*) count individual events; flushes, verdicts, and turns count batches.
Events
Section titled “Events”All events are emitted via Yedric.on(eventName, callback).
| Event | When it fires | Data shape |
|---|---|---|
open |
Panel opened (by user, by Yedric.open(), or on initial render when Default state is Open). |
{} |
close |
Panel closed. | {} |
message_create |
A new message is appended to the thread (user send or assistant response start). | { id: string; role: 'user' | 'assistant'; content: string } |
message_update |
Assistant message is being streamed, firing for each text chunk with the accumulated content so far. | { id: string; role: 'assistant'; content: string } |
tool_request |
A tool is invoked (custom HTTP, MCP, or client-delegated). Fires once per tool call, as it starts. | { type: 'tool_request'; toolCallId: string; toolName: string; args: unknown; transport: 'mcp' | 'custom' | 'client'; clientDelegate?: boolean; request?: { url: string; method: string; body?: unknown } } |
tool_response |
A tool result arrived (from server or from a client handler). | { toolCallId: string; result: unknown } |
frustration |
User message matched the frustration heuristic (profanity, “this is awful”, etc.). Fires at send time. | { messageId: string; text: string } |
newchat_submit |
User submits a typed prompt that starts a new chat thread (not a suggestion chip click). | { text: string } |
suggestion_click |
User clicks a starter suggestion chip instead of typing. | { name: string; prompt: string; useNameInMessage: boolean; anthropicSkillIds?: string[] } |
human_support |
User escalates to a human, via the escalation button or the TalkToHuman action, with the External provider selected. | { source: 'button' | 'tool'; reason: string | null; request: string; summary: string; toolCallId?: string } |
response_vote |
User votes on a response (or clears their vote) when Response voting is enabled. | { messageId: string; vote: 'up' | 'down' | null } |
review_ask |
User upvotes a response, a good moment to prompt for a review. | { messageId: string } |
resource_response |
An MCP resource was loaded into the assistant’s active context. | { uri: string; fromCache: boolean; isStatic: boolean; bytes: number; content?: string; error?: string } |
live_chat_started |
A live chat began. Built-in provider only. | { liveChatId: string } |
live_chat_resumed |
A page load rejoined a live chat that was already running. Separate from live_chat_started so a reload mid-chat is not counted as a second chat. |
{ liveChatId: string } |
live_chat_message |
A message was added to a live chat, from either side. | { id: string; sender: 'visitor' | 'agent' | 'system'; senderUserId?: string; senderName?: string; text: string; attachments?: unknown[]; createdAt: number } |
live_chat_ended |
A live chat closed. | { liveChatId: string; endedBy: 'visitor' | 'agent' | 'idle' | 'abandoned' } |
live_chat_rating |
The visitor rated the finished chat. | { liveChatId: string; sentiment: 'good' | 'bad' } |
The five live_chat_* events describe live chat and fire only when the assistant’s escalation provider is Built-in. With the External provider you get human_support instead, and none of these.
Subscribing early
Section titled “Subscribing early”Register listeners before the widget is fully connected. They’re stored in a shared Map and fire as soon as the event happens. No need to wait for any ready signal:
<script src="https://cdn.yedric.ai/widget.js?agent=agt_123"></script><script> window.Yedric.on('message_create', (name, data) => { console.log('[chat]', data.role, data.content); });</script><yedric-widget key="yk_abc…" agent="agt_123"></yedric-widget>tool_request vs registerClientTool
Section titled “tool_request vs registerClientTool”Both fire for client-delegated tool calls. They play different roles:
on('tool_request', …)is observation only, so returning a value from the callback does not provide the tool result.registerClientTool(name, handler)is execution, so the handler’s return value is sent to the server as the tool result.
Use on for telemetry, analytics, or UI cues (“the assistant is looking something up”). Use registerClientTool when you want to actually handle the call.
Element methods
Section titled “Element methods”Grab the element with document.querySelector('yedric-widget'). These methods are useful when:
- You have multiple widget instances (rare).
- You need
setConfig/getConfig(not exposed onwindow.Yedric).
interface YedricWidgetElement extends HTMLElement { open(prompt?: string, persist?: boolean): void; close(persist?: boolean): void; toggle(state?: 'open' | 'closed'): void; getSessionId(): string | null; refresh(): void; setConfig(config: Partial<YedricWidgetConfig>): void; getConfig(): YedricWidgetConfig;}setConfig(partial)
Section titled “setConfig(partial)”Merges the given fields into the widget config. Shallow merge, except customColors and mascotVideos.urls which are deep-merged.
const el = document.querySelector('yedric-widget');el.setConfig({ theme: 'dark', customColors: { primary: '#7c3aed' }, authToken: () => window.shopify.idToken(), // can be a string or a function});authToken accepts a string, a function, or an async function. The widget calls the function before each request, so you can use it for refreshing tokens. The legacy field authorization is still read if authToken is not set.
The backendUrl field is always derived from the widget.js script URL and cannot be overridden via setConfig.
getConfig()
Section titled “getConfig()”Returns a shallow copy of the current config. Useful for debugging, but don’t mutate it in place, use setConfig to change anything.
setConfig-only properties
Section titled “setConfig-only properties”These properties can only be set via setConfig(). They have no HTML attribute equivalents.
| Property | Type | Description |
|---|---|---|
greetingDescription |
string |
Secondary line shown below greeting in the empty-thread view. |
inputPlaceholder |
string |
Placeholder text in the prompt input. Default: 'Start a new conversation'. |
fontFamily |
string |
Sets the --yedric-font-family CSS variable for the panel. |
fontSize |
string |
Sets the --yedric-font-size CSS variable. |
inputBorderRadius |
string |
Sets --input-radius for the prompt textarea card. |
buttonBorderRadius |
string |
Sets --btn-radius for action buttons. |
greetingFontSize |
string |
Sets --greeting-size for the greeting headline. |
headerHeight |
string |
Sets --title-bar-height for the panel header. |
userAvatarStyle |
'initials' | 'gravatar' |
How user message avatars are rendered. Default: 'initials'. |
gravatarDefault |
string |
Gravatar d= fallback style (identicon, retro, mm, etc.). Applies when userAvatarStyle is 'gravatar'. |
gravatarForceDefault |
boolean |
When true, always use the Gravatar default image instead of a user’s own Gravatar. Applies when userAvatarStyle is 'gravatar'. Default false. |
beaconTooltip |
string |
Custom tooltip text shown on the launcher FAB. |
const el = document.querySelector('yedric-widget');el.setConfig({ greetingDescription: 'Ask me anything about your orders.', inputPlaceholder: 'Type your question…', fontFamily: "'Inter', sans-serif", userAvatarStyle: 'gravatar', beaconTooltip: 'Chat with us',});TypeScript typing stub
Section titled “TypeScript typing stub”If your host app uses TypeScript, add this to a .d.ts in your project so window.Yedric is typed:
export type YedricEventName = | 'open' | 'close' | 'frustration' | 'suggestion_click' | 'newchat_submit' | 'human_support' | 'response_vote' | 'review_ask' | 'resource_response' | 'tool_request' | 'tool_response' | 'message_create' | 'message_update' | 'live_chat_started' | 'live_chat_resumed' | 'live_chat_message' | 'live_chat_ended' | 'live_chat_rating';
export interface YedricClientToolContext { toolCallId: string; toolName: string; args: unknown;}
export interface YedricGlobal { open(prompt?: string, persist?: boolean): void; close(persist?: boolean): void; toggle(state?: 'open' | 'closed'): void; getSessionId(): string | null; refresh(): void; on( eventName: YedricEventName | (string & {}), callback: (eventName: string, data: unknown) => void, ): void; off( eventName: YedricEventName | (string & {}), callback: (eventName: string, data: unknown) => void, ): void; setPreviewPageUrl(url: string | null | undefined): void; addContext(context: Record<string, unknown>): void; attachResource(uri: string, params?: Record<string, unknown>): void; registerClientTool( toolName: string, handler: (ctx: YedricClientToolContext) => Promise<unknown> | unknown, ): void; unregisterClientTool(toolName: string): void; event(name: string, payload?: Record<string, unknown>, opts?: { dedupeKey?: string }): void; eventStats(): ClientEventStats;}
export interface ClientEventStats { enqueued: number; coalesced: number; dropped: { notInitialized: number; panelClosed: number; noConversation: number; gatesAtFlush: number; queueOverflow: number; nonRetryableStatus: number; retriesExhausted: number; }; flushes: { attempted: number; retried: number }; verdicts: { respond: number; context: number; ignore: number; ignoreReasons: Record<string, number> }; turns: { started: number; handoffRejected: number; gaveUp: number };}
declare global { interface Window { Yedric: YedricGlobal; }}
export {};The (string & {}) trick keeps IDE autocomplete for the known event names while still allowing any string (in case new events are added before this type is updated).
