Skip to main content
Deepgram's Docs

Search documentation

Type to search this documentation.

On this pageOverview

Widget Embedding Guide

How to embed the Deepgram voice agent widget on any web page. Covers CDN and ES module installation, six layout modes, theming with design tokens, callbacks, and programmatic teardown.

Add a voice agent to any website. No framework required, no build step needed. The widget ships as a self-contained bundle with its own Preact runtime (~160KB gzipped), six layout modes, and full design-token theming. It works from a CDN or as an ES module, and tears down cleanly for single-page apps.

Bash
npm install @deepgram/agents-widget
JavaScript
import { init } from "@deepgram/agents-widget";

const teardown = init({
  tokenFactory: () => fetch("/api/deepgram-token").then((r) => r.text()),
  agent: "YOUR_AGENT_ID",
  layout: "sidebar",
});

// Call teardown() to unmount the widget and clean up

Replace YOUR_AGENT_ID with a Reusable Agent Configuration UUID, or pass an inline agent config object instead. See Agent Configuration for both patterns.

Load the widget from cdn.deepgram.com for a no-build path:

HTML
<script src="https://cdn.deepgram.com/widgets/latest/widget.umd.js"></script>
<script>
  const teardown = DeepgramAgent.init({
    tokenFactory: () => fetch("/api/deepgram-token").then((r) => r.text()),
    agent: "YOUR_AGENT_ID",
  });
</script>

The latest segment in the URL above is replaced with the current pinned version when this page loads, so the snippet you copy targets a specific build, not a moving release pointer.

The package ships a UMD bundle at dist/widget.umd.js for <script>-tag usage. Copy or symlink it from node_modules/@deepgram/agents-widget/dist/widget.umd.js into your static assets, then load it like any other script:

HTML
<script src="/assets/widget.umd.js"></script>
<script>
  const teardown = DeepgramAgent.init({
    tokenFactory: () => fetch("/api/deepgram-token").then((r) => r.text()),
    agent: "YOUR_AGENT_ID",
  });
</script>

The widget ships with six layout modes. Set the layout option to choose one.

A panel that slides in from the edge of the screen. Toggled by a floating action button (FAB).

JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  layout: "sidebar",
  placement: "bottom-right",
  defaultOpen: false,
  dismissible: true,
});

A FAB button that reveals a floating overlay panel.

JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  layout: "floating",
  placement: "bottom-right",
});

Mounts directly into an existing DOM element. No FAB, no overlay.

HTML
<div id="agent-container"></div>
JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  layout: "inline",
  containerId: "agent-container",
});

Full-width card with configurable aspect ratio. Includes the conversation transcript. Ideal for landing pages and product demos.

HTML
<div id="agent-embed"></div>
JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  layout: "embedded",
  containerId: "agent-embed",
  theme: {
    aspect: "16 / 9",
    minHeight: "400px",
  },
});

A single talk button -- press to start, press again to stop. Minimal footprint.

JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  layout: "button",
  placement: "bottom-right",
});

The Deepgram animated hoop visualization with start/stop controls. Audio-reactive -- the orb responds to input and output volume in real time.

JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  layout: "orb",
  placement: "bottom-right",
});

For layouts with a FAB (sidebar, floating, button, orb), set where the button appears:

JavaScript
placement: "bottom-right" // default
// Options: "bottom-right", "bottom-left", "bottom",
//          "top-right", "top-left", "top"

To use your own button instead of the built-in FAB, pass its element ID:

HTML
<button id="my-agent-btn">Talk to AI</button>
JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  layout: "sidebar",
  buttonId: "my-agent-btn",
});

To toggle the widget programmatically from anywhere:

JavaScript
document.dispatchEvent(new Event("dg-agent-toggle"));

Toggle UI features on or off:

JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  showTranscript: true,    // conversation history (default: true)
  showMicToggle: true,     // microphone mute button (default: true)
  showSpeakerToggle: true, // speaker mute button (default: true)
  showTextInput: true,     // text input field (default: true)
});

Override labels and placeholder text:

JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  text: {
    name: "Aria",
    startLabel: "Talk to Aria",
    stopLabel: "End conversation",
    connectingLabel: "Connecting...",
    inputPlaceholder: "Type a message...",
    emptyStateHint: "Press start to begin talking.",
  },
});

Override the agent's system prompt or greeting for this session without changing the agent configuration in the Deepgram console:

JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  overrides: {
    systemPrompt: "You are a customer support agent for Acme Corp.",
    greeting: "Hi! How can I help you with your Acme account?",
  },
});

Listen to agent lifecycle events for analytics, logging, or UI integration:

JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  on: {
    onConnect: () => console.log("Connected"),
    onDisconnect: (reason) => console.log("Disconnected:", reason),
    onError: (err) => console.error("Error:", err),
    onMessage: (msg) => console.log(`${msg.role}: ${msg.content}`),
    onAgentStartedSpeaking: (msg) => console.log("Agent speaking"),
    onFunctionCallRequest: (msg) => console.log("Function call:", msg),
    onAgentError: (msg) => console.error("Agent error:", msg),
    onReconnecting: (attempt, delayMs) =>
      console.log(`Reconnecting (attempt ${attempt}, ${delayMs}ms)`),
  },
});
Callback Fires when
onConnect WebSocket connection opens
onDisconnect Session ends (user or server side)
onError SDK-level error occurs
onMessage Any conversation turn (user or assistant text)
onAgentStartedSpeaking Agent begins speaking; includes latency metrics
onFunctionCallRequest Agent requests a client-side function call
onAgentError Agent-reported error (distinct from SDK errors)
onReconnecting Reconnect attempt starts; receives attempt number and delay

Control how the widget adapts to light and dark mode:

JavaScript
// Automatic -- follows prefers-color-scheme (default)
colorScheme: "auto"

// Force light or dark
colorScheme: "light"
colorScheme: "dark"

// Class-based -- for CSS framework integration (e.g., Tailwind dark mode)
colorScheme: {
  mode: "class",
  darkSelector: ".dark",   // default
  lightSelector: ".light", // default
}

The class-based option watches for a CSS selector on any ancestor element. Use it when the host app controls theme via a class on <html> rather than OS preference.

Customize the widget's appearance by overriding design tokens. Each property maps to a CSS custom property on the widget root element ([data-dg-agent]). Set a token here to override the built-in adaptive default in both light and dark modes.

JavaScript
init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  theme: {
    // Accent
    primary: "#6366f1",
    primaryHover: "#4f46e5",
    primaryActive: "#4338ca",
    onPrimary: "#ffffff",

    // Surface
    background: "#ffffff",
    backgroundRaised: "#f9fafb",
    backgroundInput: "#ffffff",
    backgroundHover: "#f3f4f6",
    backgroundActive: "#e5e7eb",

    // Text
    text: "#111827",
    textMuted: "#6b7280",

    // Chrome
    border: "#e5e7eb",
    error: "#ef4444",
    overlay: "rgba(0, 0, 0, 0.25)",

    // Messages
    userMessageBackground: "#f3f4f6",
    userMessageBorder: "#e5e7eb",

    // Radius
    panelRadius: "16px",
    buttonRadius: "9999px",
    inputRadius: "8px",
    messageRadius: "12px",

    // Structural
    fabSize: 56,
    padding: "16px",
    font: "Inter, system-ui, sans-serif",
  },
});

To override only one color scheme, skip the theme option and write CSS directly:

CSS
@media (prefers-color-scheme: dark) {
  [data-dg-agent] {
    --dg-va-bg: #0d1117;
  }
}

The embedded layout supports additional sizing tokens:

JavaScript
theme: {
  aspect: "4 / 3",       // CSS aspect-ratio (default: "4 / 3")
  minHeight: "320px",     // default: "320px"
  maxHeight: "80vh",      // default: "80vh"
}
JavaScript
init({
  // -- Auth (one required) --
  apiKey: "...",                              // Development only
  tokenFactory: () => Promise<string>,        // Production

  // -- Agent --
  agent: "AGENT_ID" | AgentSettingsObject,    // Required
  overrides: { systemPrompt, greeting },

  // -- Layout --
  layout: "sidebar",                          // sidebar | inline | floating
                                              // button | embedded | orb
  placement: "bottom-right",                  // FAB position
  containerId: "my-element",                  // Required for inline / embedded
  buttonId: "my-button",                      // External trigger element
  defaultOpen: false,                         // Start panel open (sidebar/floating)
  dismissible: true,                          // Allow close/dismiss

  // -- Features --
  showTranscript: true,
  showMicToggle: true,
  showSpeakerToggle: true,
  showTextInput: true,

  // -- Text --
  text: {
    name, startLabel, stopLabel,
    connectingLabel, inputPlaceholder, emptyStateHint,
  },

  // -- Theming --
  colorScheme: "auto" | "light" | "dark"
             | { mode: "class", darkSelector, lightSelector },
  theme: { /* design tokens listed above */ },

  // -- Callbacks --
  on: {
    onConnect, onDisconnect, onError, onMessage,
    onAgentStartedSpeaking, onFunctionCallRequest,
    onAgentError, onReconnecting,
  },

  // -- Audio --
  playerSampleRate: 24_000,                   // Agent audio sample rate

  // -- Network --
  url: "wss://...",                           // Custom WebSocket URL (proxy)
});

The init() function returns a teardown function. Call it to unmount the widget, remove all injected styles, and release audio resources. This is essential for single-page apps where the widget mounts and unmounts as the user navigates.

JavaScript
const teardown = init({
  tokenFactory,
  agent: "YOUR_AGENT_ID",
  layout: "sidebar",
});

// When the user navigates away or you no longer need the widget:
teardown();

For frameworks with lifecycle hooks, call teardown in the cleanup phase:

JavaScript
// React useEffect
useEffect(() => {
  const teardown = init({ tokenFactory, agent: "YOUR_AGENT_ID" });
  return teardown;
}, []);

// Vue onUnmounted
onMounted(() => {
  const teardown = init({ tokenFactory, agent: "YOUR_AGENT_ID" });
  onUnmounted(teardown);
});
Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu