Voisnap Docs
Guides

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

ModeProtocolBest for
VoiceWebRTCCustomer support, voice-first experiences
ChatChatHub (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

AttributeTypeDefaultDescription
data-agent-idstringrequiredYour agent ID
data-modestringchatvoice or chat
data-primary-colorstring#6366f1Hex color for the widget button and accents
data-positionstringbottom-rightbottom-right, bottom-left, bottom-center
data-greetingstringAgent's first messagePre-chat greeting shown before session starts
data-widget-titlestringAgent's nameTitle shown in the widget header
data-localestringen-USBCP 47 locale for widget UI labels
data-open-on-loadbooleanfalseAuto-open the widget when the page loads
data-hide-brandingbooleanfalseHide "Powered by Voisnap" (Business+ plans)
data-z-indexnumber9999CSS 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;

On this page