Documentation

JavaScript API

The embedded widget exposes one global on the host page, window.VAWaveWidget. This page covers the methods you can call on it, the state you can read, and the three events it emits. If you have not embedded the widget yet, start with Embedding the widget.

Getting a reference to the widget

The embed script creates the widget instance and assigns it to window.VAWaveWidget. Two things are worth knowing before you call anything:

  • Until the instance exists, window.VAWaveWidget may hold the widget class instead of the live instance. Check for the method you are about to call rather than checking that the global is set.
  • The widget fetches its settings from the server before it renders. isReady flips to true only after that succeeds and the DOM is in place. If authentication fails, nothing renders and isReady stays false forever.
function onWidgetReady(callback) {
  const tick = () => {
    const w = window.VAWaveWidget;
    if (w && w.isReady === true && typeof w.activateChat === 'function') {
      callback(w);
    } else {
      setTimeout(tick, 200);
    }
  };
  tick();
}

onWidgetReady((widget) => {
  console.log('Widget ready, session:', widget.sessionId);
});

Method summary

Method Returns What it does
activateChat() — Opens the chat panel and focuses the input
activateVoice(options?) Promise Starts a voice session
toggle() — The orb's own click behaviour: opens chat when idle, closes chat or stops voice when active
closeChat() — Leaves chat and returns the widget to its idle state
stop() — Ends the voice session and returns the widget to its idle state
start() Promise Nothing. Empty method kept for backwards compatibility
processMessage(text, textMode?) Promise Sends text to the assistant as if the visitor had said it
sendChatMessage() Promise Sends whatever is currently typed in the input. Takes no argument
resetChat() Promise Ends the conversation on the server and starts a fresh one
minimize() — Collapses the widget
expand() — Restores a minimized widget
toggleMinimize() — Calls minimize() or expand() depending on current state
expandToFullscreen(mode) — Expands the Minimal presentation. mode is 'chat', 'voice' or 'idle'
collapseFromFullscreen() — Collapses the Minimal presentation back to its ambient pill
destroy() — Tears the widget down completely and removes it from the page
registerTool(name, def) boolean Registers a page tool the assistant may call
registerTools(map) number Registers several page tools at once, returns how many were accepted
unregisterTool(name) boolean Removes a previously registered page tool
setContext(state) — Publishes ambient page state to the assistant

Anything else you find on the object is internal. It can change without notice.

Sending messages

processMessage(text, textMode)

This is the method to use when your page needs to say something on the visitor's behalf.

window.VAWaveWidget.activateChat();
window.VAWaveWidget.processMessage('What are your opening hours?', true);
  • text — the message content.
  • textMode — pass true to treat it as a typed message. Defaults to false, in which case the reply is spoken aloud whenever a voice session is running.

Warning

The message is discarded if the widget is idle. Messages are only processed when the widget is in chat or voice mode, or when the Minimal presentation is expanded. Call activateChat() (or activateVoice()) first, as in the example above.

Other behaviour worth knowing: messages are queued, so calling processMessage() twice in a row runs both turns in order. If the conversation ended because the account ran out of credits, the call is refused and an error flash is shown instead.

sendChatMessage()

sendChatMessage() takes no argument. It reads the current value of the chat input, clears it, and sends it. This is what the Enter key and the mic button call. Passing a string to it does nothing — the string is ignored and the input value is sent instead.

Use processMessage(text) to send text programmatically.

The method also ignores calls that arrive within 100 ms of the previous send, and calls made while the assistant is still answering.

Opening and closing

activateChat()

Opens chat. On the Minimal presentation it expands the whole surface rather than showing a corner panel. If a voice session is running it is stopped first — chat and voice are mutually exclusive outside the Minimal surface.

activateVoice(options)

Starts a voice session and resolves when the connection attempt finishes.

await window.VAWaveWidget.activateVoice({ greet: false });
  • options.greet — pass false to suppress the spoken greeting, true to force it. Omitted, the assistant greets unless a conversation is already visible on screen.

Call it from inside a real user gesture (a click or tap handler). Browsers only unlock audio playback and microphone access during a gesture, so a voice session started from a timer or on page load will not produce sound. If voice is turned off for the assistant, the call returns immediately and does nothing.

closeChat()

Returns the widget to idle: stops audio playback and capture, aborts the in-flight request, clears the input, and closes the mobile takeover. Conversation history is preserved, so reopening chat shows the same thread.

Warning

closeChat() does not collapse the Minimal presentation. On a Minimal widget it leaves the expanded surface in place with no chat in it. Call collapseFromFullscreen() instead — that method closes chat, stops voice, and returns the surface to its ambient pill.

stop()

Ends the voice session — closes the voice connection, releases the microphone, stops playback and clears the message queue — and puts the widget back in its idle state. Display history is kept.

start()

An empty method. It exists only so older host-page code that calls it does not break. It does not start voice; use activateVoice().

minimize(), expand(), toggleMinimize()

minimize() closes chat or voice first, then collapses the widget. expand() restores it.

Warning

The widget provides no on-screen control to expand a minimized widget. If you call minimize(), your page must provide its own control that calls expand(), or the visitor is left with no way back. The minimized flag is also cleared on the next page load, so the collapsed state does not persist across navigation.

resetChat()

Ends the current conversation on the server, generates a new session, clears both the on-screen history and the history sent to the model, and shows the welcome message again. This is what the New conversation control in the widget does.

destroy()

Stops everything, removes the widget's DOM and injected styles, releases the microphone, and closes the audio context. There is no matching re-create call — after destroy() the widget stays gone until the page reloads.

Page tools

registerTool(), registerTools(), unregisterTool() and setContext() let your page expose functions the assistant can call and keep the assistant aware of what is on screen. They have their own page: Page tools.

State you can read

These properties are readable at any time. Treat them as read-only — assigning to them does not update the UI, and the widget overwrites them on its next state change.

Property Type Meaning
isReady boolean true once settings loaded and the widget rendered
mode string 'hover' (idle), 'chat' or 'voice'
state string 'idle', 'loading', 'listening', 'processing', 'speaking' or 'error'
displayMode string 'widget' for the orb presentation, 'fullscreen' for Minimal
fsExpanded boolean Whether the Minimal surface is expanded
minimized boolean Whether the widget is collapsed
isProcessing boolean An assistant turn is in flight
isSpeaking boolean The assistant is currently speaking
conversationEnded boolean The conversation is closed
endReason string / null Why it closed, e.g. 'insufficient_credits'
sessionId string / null Current conversation session
visitorId string Stable per-browser visitor identifier, stored in localStorage
siteId string The assistant this embed is bound to
botName string The assistant's display name
voiceEnabled boolean Whether voice is available on this assistant
ttsEnabled boolean Whether the assistant may speak
displayHistory array Messages currently rendered in the widget
conversationHistory array { role, content } turns sent to the model

Note

displayMode: 'fullscreen' is the internal name for the Minimal presentation. It is not a browser fullscreen mode.

Observing the widget from the page

The widget keeps its container's class list in sync with its state, which is the most reliable way to react to changes. The container is a div.va-container appended to document.body; its id is generated at runtime, so select it by class.

Class Present when
va-loading / va-ready Before / after the widget finishes initializing
chat-mode Chat is open
voice-mode A voice session is running
minimized The widget is collapsed
fs-collapsed Minimal presentation, ambient pill
fullscreen-mode Minimal presentation, expanded
const container = document.querySelector('.va-container');
new MutationObserver(() => {
  console.log('chat open:', container.classList.contains('chat-mode'));
}).observe(container, { attributes: true, attributeFilter: ['class'] });

Events

The widget emits three things. That is the complete list.

va-balance-update

A CustomEvent dispatched on window when a reply carries a remaining credit balance for the visitor.

window.addEventListener('va-balance-update', (e) => {
  console.log('Balance:', e.detail.balance);
});

This only happens when the assistant is wired to an external usage webhook that returns a balance. Ordinary replies do not carry one, so most sites never see this event.

va-voice-unavailable

A CustomEvent dispatched on window when speech synthesis is refused because the account is out of credits. The widget disables its own speech for the rest of the page session when this fires.

window.addEventListener('va-voice-unavailable', (e) => {
  // e.detail.reason === 'insufficient_credits'
  showNoticeToUser('Voice is unavailable right now.');
});

va-widget-state (postMessage)

When the widget runs inside an iframe, it posts a message to the parent window every time its container state changes:

{ "type": "va-widget-state", "expanded": true }

expanded is true while chat or voice is active. The message is posted with the widget page's own origin as the target origin, so only a same-origin parent receives it. If your parent page is on a different domain than the iframe, nothing arrives.

window.addEventListener('message', (e) => {
  if (e.origin !== window.location.origin) return;
  if (e.data && e.data.type === 'va-widget-state') {
    resizeIframe(e.data.expanded);
  }
});

What the widget does not have

  • No callback registry. There is no on(), off(), addEventListener() or onMessage hook on window.VAWaveWidget. You cannot subscribe to messages, turns, or tool calls from the host page.
  • No inbound postMessage listener. The widget never listens for messages from a parent frame, so you cannot control it from an outer page by posting to the iframe. Control it by calling methods on the global inside the same document.

To observe more than the three events above, you have two options:

  1. In the browser — watch the DOM, as shown in Observing the widget from the page.
  2. On your server — use Actions. Hiroi sends signed HTTPS requests to your endpoint on conversation, message, form, escalation and contact events, which is the supported way to react to what happens in a conversation.