Integration Guide
Step-by-step patterns for integrating the Virbe web widget into vanilla JavaScript websites and React applications.
This guide covers how to load the widget script, embed it in your page, and control it programmatically from both vanilla JavaScript and React applications.
Loading the Script
The widget is distributed as a JavaScript module. Load it before using the <virbe-plugin> element.
Script Tag (recommended for most sites)
<script type="module" src="https://YOUR_DASHBOARD_URL/web-component/virbe-plugin.es.js"></script>Replace YOUR_DASHBOARD_URL with your Virbe dashboard domain (e.g. https://your-dashboard-name.virbe.app). The script registers the <virbe-plugin> custom element globally. This is the same script tag that the Profile's Deployment tab includes in the copy-paste embed code – see Web Widget Deployment.
Dynamic Script Loading
If you need to load the widget conditionally or at a specific point in your application lifecycle, load it dynamically:
function loadVirbeWidget(dashboardUrl) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.type = 'module';
script.async = true;
script.src = `${dashboardUrl}/web-component/virbe-plugin.es.js`;
script.onload = resolve;
script.onerror = reject;
document.body.appendChild(script);
});
}
// Usage
await loadVirbeWidget('https://YOUR_DASHBOARD_URL');Vanilla HTML Integration
A complete, copy-pasteable example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Virbe Widget Demo</title>
</head>
<body>
<!-- 1. Place the widget -->
<virbe-plugin
profileId="YOUR_PROFILE_ID"
profileSecret="YOUR_PROFILE_SECRET"
mode="floating"
position="bottom">
</virbe-plugin>
<!-- 2. Load the script -->
<script type="module" src="https://YOUR_DASHBOARD_URL/web-component/virbe-plugin.es.js"></script>
<!-- 3. Interact with the widget -->
<script type="module">
// Wait for the custom element to be defined
await customElements.whenDefined('virbe-plugin');
const widget = document.querySelector('virbe-plugin');
// Listen for initialization
widget.subscribeToEvent('onInitialized', () => {
console.log('Widget ready');
});
// Listen for messages
widget.subscribeToEvent('onConversationMessage', (event) => {
console.log('Message:', event.detail.action);
});
</script>
</body>
</html>Programmatic Element Creation
You can also create the widget entirely in JavaScript:
const widget = document.createElement('virbe-plugin');
widget.profileId = 'YOUR_PROFILE_ID';
widget.profileSecret = 'YOUR_PROFILE_SECRET';
widget.mode = 'floating';
widget.position = 'bottom';
document.body.appendChild(widget);React Integration
Script Loading Hook
Create a hook to load the widget script dynamically:
import { useState, useEffect } from 'react';
function useLoadScript(src: string): boolean {
const [loaded, setLoaded] = useState(false);
useEffect(() => {
if (!src) return;
const existing = document.querySelector(`script[src="${src}"]`);
if (existing) {
setLoaded(true);
return;
}
const script = document.createElement('script');
script.type = 'module';
script.async = true;
script.src = src;
script.onload = () => setLoaded(true);
document.body.appendChild(script);
}, [src]);
return loaded;
}Wrapper Component
Wrap the <virbe-plugin> custom element in a React component to expose its methods via a ref:
import { useRef, useEffect, useImperativeHandle, forwardRef } from 'react';
interface VirbePluginMethods {
showWidget(): void;
hideWidget(): void;
startNewConversation(endUserId: string): void;
startConversation(conversationId: string, endUserId?: string): void;
stopConversation(): void;
sendText(message: string, language?: string): void;
sendSignal(signal: string, value?: string): void;
mute(): void;
unmute(): void;
startSpeechRecord(): void;
stopSpeechRecord(): void;
interruptSpeech(): void;
subscribe(event: string, callback: (event: CustomEvent) => void): () => void;
}
interface VirbePluginWrapperProps {
profileId: string;
profileSecret: string;
dashboardUrl: string;
mode?: 'floating' | 'embedded';
position?: 'top' | 'bottom';
}
const VirbePluginWrapper = forwardRef<VirbePluginMethods, VirbePluginWrapperProps>(
({ profileId, profileSecret, dashboardUrl, mode = 'floating', position = 'bottom' }, ref) => {
const elementRef = useRef<HTMLElement>(null);
const isScriptLoaded = useLoadScript(`${dashboardUrl}/web-component/virbe-plugin.es.js`);
useImperativeHandle(ref, () => ({
showWidget: () => (elementRef.current as any)?.showWidget(),
hideWidget: () => (elementRef.current as any)?.hideWidget(),
startNewConversation: (endUserId) =>
(elementRef.current as any)?.startNewConversation(endUserId),
startConversation: (conversationId, endUserId) =>
(elementRef.current as any)?.startConversation(conversationId, endUserId),
stopConversation: () => (elementRef.current as any)?.stopConversation(),
sendText: (message, language) =>
(elementRef.current as any)?.sendText(message, language),
sendSignal: (signal, value) =>
(elementRef.current as any)?.sendSignal(signal, value),
mute: () => (elementRef.current as any)?.mute(),
unmute: () => (elementRef.current as any)?.unmute(),
startSpeechRecord: () => (elementRef.current as any)?.startSpeechRecord(),
stopSpeechRecord: () => (elementRef.current as any)?.stopSpeechRecord(),
interruptSpeech: () => (elementRef.current as any)?.interruptSpeech(),
subscribe: (event, callback) => {
const sub = (elementRef.current as any)?.subscribeToEvent(event, callback);
return () => sub?.unsubscribe();
},
}));
if (!isScriptLoaded) return null;
return (
// @ts-expect-error virbe-plugin is a custom element
<virbe-plugin
ref={elementRef}
profileId={profileId}
profileSecret={profileSecret}
mode={mode}
position={position}
/>
);
}
);Using the Wrapper
import { useRef, useEffect } from 'react';
function App() {
const pluginRef = useRef<VirbePluginMethods>(null);
useEffect(() => {
if (!pluginRef.current) return;
const unsubInit = pluginRef.current.subscribe('onInitialized', () => {
console.log('Widget ready');
});
const unsubStatus = pluginRef.current.subscribe('onApiStatusChanged', (event) => {
if (event.detail.action === 'connected') {
pluginRef.current?.unmute();
pluginRef.current?.startNewConversation('user-123');
}
});
const unsubMessages = pluginRef.current.subscribe('onConversationMessage', (event) => {
console.log('Message:', event.detail.action);
});
return () => {
unsubInit();
unsubStatus();
unsubMessages();
};
}, []);
return (
<VirbePluginWrapper
ref={pluginRef}
profileId="YOUR_PROFILE_ID"
profileSecret="YOUR_PROFILE_SECRET"
dashboardUrl="https://YOUR_DASHBOARD_URL"
/>
);
}Controlling the Widget from Your Application
Show or Hide Based on User Actions
// Open widget when user clicks a help button
document.getElementById('help-button').addEventListener('click', () => {
widget.showWidget();
});
// Hide widget when navigating to a checkout page
router.on('/checkout', () => {
widget.hideWidget();
});Start Conversations Programmatically
// Start a new conversation with context variables
widget.startNewConversation('user-123', [
{ key: 'page', value: window.location.pathname },
{ key: 'language', value: navigator.language },
]);Send Signals from External UI
Use signals to trigger specific conversation flows configured in the dashboard:
// A button in your app triggers a signal
document.getElementById('product-question').addEventListener('click', () => {
widget.sendSignal('ask-about-product', 'premium-plan');
});Route Events to Your Own UI
Listen to widget events and display data in your own components:
widget.subscribeToEvent('onConversationMessage', (event) => {
const message = event.detail.action;
// Render message in your custom chat panel
appendToChatLog(message);
});
widget.subscribeToEvent('onUiAction', (event) => {
const { cards, buttons } = event.detail.action;
// Render action buttons in your own UI
renderActionButtons(buttons);
});When controlling conversations programmatically, disable automatic conversation start in your Profile's dashboard settings:
- Set Auto-start on widget focused to
false - Set Auto-start on page focused to
false - Set Send signal on new conversation to
false
Otherwise the widget may start conversations before your code is ready to manage them.