Web Widget
Embed a Voisnap voice or chat widget on any website with a single script tag. Configuration, custom metadata, and React integration.
Web Widget
The Voisnap web widget lets you embed a voice or chat interface on any website with a single script tag. Users can talk to or chat with your agent directly without leaving your site.
Two modes
| Mode | Protocol | Best for |
|---|---|---|
| Voice | WebRTC | Customer support, voice-first experiences |
| Chat | ChatHub (WebSocket) | FAQ bots, lead capture, text-first flows |
Quick embed (HTML)
Add this to your page <body> — replace the data- attributes with your own:
<!-- Voice widget -->
<script
src="https://cdn.voisnap.ai/widget/v1/widget.js"
data-agent-id="agt_01HXK8Z3MNPQRS"
data-mode="voice"
data-primary-color="#6366f1"
data-position="bottom-right"
data-greeting="Hi there! Click to start a voice conversation."
data-widget-title="Talk to Aria"
defer
></script>
<!-- Chat widget -->
<script
src="https://cdn.voisnap.ai/widget/v1/widget.js"
data-agent-id="agt_01HXK8Z3MNPQRS"
data-mode="chat"
data-primary-color="#6366f1"
data-position="bottom-right"
data-greeting="Hi! How can I help you today?"
data-widget-title="Acme Support"
defer
></script>
That's it — the widget renders a floating button in the corner.
Configuration options
| Attribute | Type | Default | Description |
|---|---|---|---|
data-agent-id | string | required | Your agent ID |
data-mode | string | chat | voice or chat |
data-primary-color | string | #6366f1 | Hex color for the widget button and accents |
data-position | string | bottom-right | bottom-right, bottom-left, bottom-center |
data-greeting | string | Agent's first message | Pre-chat greeting shown before session starts |
data-widget-title | string | Agent's name | Title shown in the widget header |
data-locale | string | en-US | BCP 47 locale for widget UI labels |
data-open-on-load | boolean | false | Auto-open the widget when the page loads |
data-hide-branding | boolean | false | Hide "Powered by Voisnap" (Business+ plans) |
data-z-index | number | 9999 | CSS z-index of the widget |
Passing custom metadata per session
You can inject user-specific data into the session so your agent can personalize the conversation. This is useful for passing CRM data, account status, or page context.
<script src="https://cdn.voisnap.ai/widget/v1/widget.js"
data-agent-id="agt_01HXK8Z3MNPQRS"
data-mode="chat"
defer></script>
<script>
// Configure metadata BEFORE the widget initializes
window.VoisnapWidgetConfig = {
agentId: 'agt_01HXK8Z3MNPQRS',
mode: 'chat',
metadata: {
userId: '{{USER_ID}}', // server-rendered
accountTier: '{{TIER}}', // e.g. "premium"
currentPage: window.location.pathname,
cartValue: '{{CART_VALUE}}',
},
onSessionStart: (conversationId) => {
console.log('Chat started:', conversationId);
// Track in your analytics
analytics.track('chat_started', { conversationId });
},
onSessionEnd: (conversationId, durationSeconds) => {
console.log('Chat ended after', durationSeconds, 's');
},
};
</script>
In your agent's system prompt, reference the metadata:
You are helping {{metadata.userId}} who is a {{metadata.accountTier}} customer.
They are currently on the page: {{metadata.currentPage}}.
If their cart value ({{metadata.cartValue}}) is over $200, mention the free shipping offer.
JavaScript API
Control the widget programmatically:
// Open/close
window.VoisnapWidget.open();
window.VoisnapWidget.close();
window.VoisnapWidget.toggle();
// Check state
const isOpen = window.VoisnapWidget.isOpen();
// Send a message programmatically (chat mode only)
window.VoisnapWidget.sendMessage("I need help with my order");
// Destroy and reinitialize (useful for SPA route changes)
window.VoisnapWidget.destroy();
React integration
import { useEffect, useRef } from 'react';
import { useAuth } from './hooks/useAuth';
interface VoisnapWidgetProps {
agentId: string;
mode?: 'voice' | 'chat';
primaryColor?: string;
}
declare global {
interface Window {
VoisnapWidget?: {
open(): void;
close(): void;
destroy(): void;
isOpen(): boolean;
};
VoisnapWidgetConfig?: Record<string, unknown>;
}
}
export function VoisnapWidget({
agentId,
mode = 'chat',
primaryColor = '#6366f1',
}: VoisnapWidgetProps) {
const { user } = useAuth();
const scriptRef = useRef<HTMLScriptElement | null>(null);
useEffect(() => {
// Set config before loading script
window.VoisnapWidgetConfig = {
agentId,
mode,
primaryColor,
metadata: {
userId: user?.id,
email: user?.email,
plan: user?.plan,
currentPage: window.location.pathname,
},
};
const script = document.createElement('script');
script.src = 'https://cdn.voisnap.ai/widget/v1/widget.js';
script.defer = true;
document.body.appendChild(script);
scriptRef.current = script;
return () => {
window.VoisnapWidget?.destroy();
script.remove();
scriptRef.current = null;
};
}, [agentId, mode, primaryColor, user]);
return null; // widget renders itself
}
// In your app layout:
// <VoisnapWidget agentId="agt_01HXK8Z3MNPQRS" mode="chat" />
Content Security Policy
If your site uses a CSP, add these directives:
connect-src https://api.voisnap.ai wss://api.voisnap.ai;
script-src https://cdn.voisnap.ai;
frame-src https://cdn.voisnap.ai;