Installation
You can load the widget two ways: the bare embed (one script tag, no dependency) or the
Vue wrapper (@monoverse/voicebot-vue). Most Vue apps want the wrapper.
Option A — the wrapper
Install
npm install @monoverse/voicebot-vue
vue (^3.4) is a peer dependency.
Render the widget
Render <VoiceBotWidget> once, near the root of your app. It renders nothing visible itself —
the widget UI is mounted by the deployed bundle it loads into its own Shadow DOM host.
<script setup lang="ts">
import { VoiceBotWidget } from '@monoverse/voicebot-vue';
</script>
<template>
<YourApp />
<VoiceBotWidget public-key="pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" />
</template>
The widget core is a one-per-page singleton: the wrapper reuses any VoiceBot script already on the page, so rendering it more than once never injects a second script or opens a second WebSocket/microphone.
Voice or chat
- Voice
- Chat
<VoiceBotWidget public-key="pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" variant="voice" />
variant="voice" (the default) loads widget-voice.js.
<VoiceBotWidget public-key="pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" variant="chat" />
variant="chat" loads widget-chat.js.
Props & events
| Prop / event | Type | Default | Description |
|---|---|---|---|
public-key | string (required) | — | Your pk_ publishable key. |
variant | 'voice' | 'chat' | 'voice' | Which widget bundle to load. |
lang | string | — | Force the widget UI language (e.g. 'uk', 'en'). |
script-src | string | https://api.monoverse.tech/widget | Override the CDN base (self-hosted API). |
on-action | VoiceBotActionHandlers | — | Cart/variant/filter handlers. See Capabilities. |
capabilities | VoiceBotCapability[] | — | Narrow the server-granted capability set for the current page. |
tool-handlers | VoiceBotToolHandlers | — | Low-level override for canonical action names. |
@error | (error: Error) => void | — | Emitted on script load failure or an empty key. |
@navigate | (target: VoiceBotNavTarget) => void | — | Emitted on any bot navigation action. Use for SPA client-side routing. |
Error handling is a Vue event, not a prop:
<VoiceBotWidget public-key="pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" @error="(e) => console.error(e)" />
Composable (imperative)
For custom layouts, useVoiceBot runs the same lifecycle without rendering an element. Call it
inside setup() — it registers onMounted / onBeforeUnmount internally:
<script setup lang="ts">
import { useVoiceBot } from '@monoverse/voicebot-vue';
useVoiceBot({ publicKey: 'pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', variant: 'chat' });
</script>
The composable takes options in camelCase (publicKey, scriptSrc) and accepts an onError
callback directly; the <VoiceBotWidget> component uses Vue-idiomatic kebab-case props and the
@error event.
Reactivity
The wrapper reads props at mount and is one-shot: it deliberately does not re-inject when a
prop changes (that would mint a duplicate token + WebSocket). To switch the key at runtime, remount
the host — a :key change or a v-if toggle.
Option B — the bare embed (no dependency)
If you'd rather not add a package, drop the deployed bundle in with a single script tag. This is the
same component shape, without @monoverse/voicebot-vue — inject in onMounted, tear down in
onBeforeUnmount:
<script setup lang="ts">
import { onBeforeUnmount, onMounted } from 'vue';
const props = withDefaults(
defineProps<{
publicKey: string;
apiBase?: string;
variant?: 'voice' | 'chat';
}>(),
{ variant: 'voice' },
);
let script: HTMLScriptElement | null = null;
onMounted(() => {
const base = props.apiBase ?? 'https://api.monoverse.tech';
script = document.createElement('script');
script.src = `${base}/widget/widget-${props.variant}.js`;
script.async = true;
script.dataset.publicKey = props.publicKey;
if (props.apiBase) script.dataset.apiBase = props.apiBase;
document.body.appendChild(script);
});
onBeforeUnmount(() => {
(window as { VoiceBot?: { destroy?: () => void } }).VoiceBot?.destroy?.();
script?.remove();
script = null;
});
</script>
<template>
<!-- The widget renders into its own Shadow DOM host; this component renders nothing. -->
</template>
The full reference lives in examples/embed/vue/.
Nuxt / SSR
The component is SSR-safe: it injects the script in onMounted (which never runs on the server)
and the embed itself guards window/document, so a server render is a no-op that never throws. On
Nuxt, render it client-side only so the widget code runs only in the browser:
<template>
<ClientOnly>
<VoiceBotWidget public-key="pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" />
</ClientOnly>
</template>
The package source, props table, and changelog live in the package README on npm.