Qunivex
Language
Log In
Widget SDK
  • Getting started
  • Visibility & pages
  • Messages & responses
  • Appearance & agents
  • Methods
  • Events
  • Errors & deployment
  • Qunivex documentation →
  • REST API reference →
Developer documentation

Widget JavaScript SDK

Connect your own buttons, page routes, and application code to the Qunivex chatbot on your website.

Getting started

The existing embed script also installs window.Qunivex (SDK v1). Create a project, add your knowledge and instructions, then enable the widget and allow your site's domain in Deployments. Replace YOUR_AGENT_KEY with the public Qunivex Address from that page. No private API key is needed.

<script src="https://qunivex.com/widget.js" data-agent="YOUR_AGENT_KEY"></script>
<script>
  Qunivex.ready().then(() => {
    document.querySelector('#support-button').addEventListener('click', () => {
      Qunivex.open().catch(console.error);
    });
  }).catch(console.error);
</script>

The SDK global is available as soon as the script executes. ready() resolves after configuration and widget markup load, or rejects if the widget is disabled, blocked by domain permissions, or unavailable. If you load the script asynchronously or with defer, wait for its load event before accessing Qunivex, then await ready(). Load the embed once per page; duplicate embeds are ignored.

Visibility and page routing

open() shows the widget and expands the conversation. close() minimizes it to the launcher. hide() closes it and hides everything, while show() restores the launcher. Hiding or closing keeps the conversation and lets an in-flight response finish; use stop() to cancel generation.

For selected pages in a single-page application, start hidden and connect the following function to your router's navigation callback. Traditional websites can include the script only in the selected page templates.

<script src="https://qunivex.com/widget.js" data-agent="YOUR_AGENT_KEY" data-hidden="true"></script>
<script>
  async function syncSupportWidget() {
    await Qunivex.ready();
    const path = window.location.pathname;
    const allowed = path === '/pricing' || path === '/support'
      || path === '/docs' || path.startsWith('/docs/');
    await (allowed ? Qunivex.show() : Qunivex.hide());
  }
  syncSupportWidget().catch(console.error);
  window.addEventListener('popstate', () => syncSupportWidget().catch(console.error));
  // Also call syncSupportWidget() after your router's pushState/navigation.
</script>

data-hidden="true" prevents the initial launcher flash and proactive popups on excluded pages. Visibility controls presentation; an allowlisted page that loads the widget can still send requests. A verified widget visit confirms installation even when the launcher starts hidden.

Send messages and receive responses

await Qunivex.ready();
const unsubscribe = Qunivex.on('delta', ({ text }) => {
  // Append plain text to your own response view.
  document.querySelector('#live-answer').textContent += text;
});
try {
  const response = await Qunivex.sendMessage('How do I get started?');
  console.log(response.text, response.conversationId, response.agent);
} catch (error) {
  console.error(error.code, error.message);
}
unsubscribe();

sendMessage(text) sends a non-empty text message through the widget's conversation and resolves with { text, feedback, agent, conversationId } when the complete answer arrives. It also renders the turn inside the widget, even while hidden. Calls must be sequential; pending attachments, the pre-chat form, visitor throttles, backend quotas, and domain permissions remain enforced. The Promise rejects on cancellation, a failed request, or an incomplete stream. delta events carry streamed response text; the response event carries the final answer, including when buffering is enabled.

Listeners also receive messages submitted through the built-in composer. Never insert response text into your page using unescaped innerHTML. getMessages() returns a copy of the locally persisted transcript using entries such as { r: 'user' | 'bot', t: 'text' }; workflow notices can use r: 'wf'. Images are not persisted in this transcript.

Change the widget and switch agents

await Qunivex.configure({
  title: 'Product support',
  placeholder: 'Ask a product question…',
  primary_color: '#2557D6',
  position: 'right',
  widget_position: 'middle',
  widget_size: 'large',
  starter_prompts: ['How does it work?', 'Where can I find pricing?']
});
await Qunivex.setMode('light'); // Requires a configured light palette.
await Qunivex.setAgent('ANOTHER_PUBLIC_AGENT_KEY');

Supported configure() options: title, welcome_message, placeholder, primary_color, avatar, position (left/right), widget_position (left/right/middle), widget_size (small/medium/large), and starter_prompts (up to five strings). These overrides affect the current browser page; save permanent appearance changes in the dashboard. Root-relative avatar paths resolve against the Qunivex script origin.

setAgent() validates the new agent before replacing the widget, restores that agent's session conversation, and preserves visibility. Each agent has separate conversation history, theme preference, contact capture, and throttle state. The new agent must be enabled and allow the current domain. Switching agents and rebuilding appearance are refused during generation; finish the response or call stop() and wait for the send Promise to settle.

Method reference

MethodResult / behavior
ready()Promise resolving to the initial ready state.
open(), close(), toggle()Promise resolving to state after expanding/minimizing.
show(), hide()Promise resolving to state after changing visibility.
configure(options)Promise; updates the current page's appearance.
setAgent(publicKey)Promise; switches to an enabled, allowlisted agent.
setMode('light' | 'dark')Promise; selects an available palette and saves the preference.
sendMessage(text)Promise resolving to the completed response.
stop()Aborts generation immediately; a pending send rejects with ABORTED.
reset()Promise; clears local conversation and starts a new conversation ID. Does not delete dashboard logs or reset visitor throttles.
getState()Returns { agent, conversationId, ready, open, visible, sending, mode, prechatRequired }.
getMessages()Returns a copy of the current local transcript.
on(name, callback)Returns an unsubscribe function.
off(name, callback)Removes that listener.

Events

Subscribe using Qunivex.on(name, callback), or listen on window for qunivex:NAME CustomEvents and read event.detail. Every payload includes agent and conversationId. Listener exceptions are isolated from the widget.

EventAdditional fields
readyInitial state. Late subscribers should await ready().
open, close, show, hidePanel or visibility action.
messagetext — a submitted user message.
deltatext — a streamed answer chunk.
responsetext, feedback — completed answer.
streamRaw public widget stream event (type and event-specific fields). Treat new event types as optional.
errorcode, message — a startup or generation failure.
configure, agent, resetSuccessful SDK action.
modemode — selected palette.

Errors and deployment checks

Catch Promise rejections and inspect error.code. Validation codes include INVALID_MESSAGE, INVALID_OPTION, BUSY, PRECHAT_REQUIRED, ATTACHMENTS_PENDING, RATE_LIMITED, and LOCAL_COMMAND. Request failures include UNAVAILABLE, DOMAIN_NOT_ALLOWED, HTTP_ERROR, RESPONSE_ERROR, INCOMPLETE_RESPONSE, and ABORTED. Browser/network errors may also be native Error objects.

Installation is confirmed when the backend accepts a widget visit from an allowed domain with a matching page URL. Dashboard previews and rejected origins do not confirm installation. This records that an integration has been observed; it does not continuously check whether the script is still present. Regenerating the public address, or removing the confirmed domain from the allowlist, requires a fresh visit. Update your embed after regeneration.

For platform setup, knowledge, tools, and guardrails, read the Qunivex documentation. For server-side authenticated API integrations, use the separate REST API reference. If an integration behaves unexpectedly, check these docs and the browser Network panel before changing the script.