---
title: "Embeddable Voice Widget"
description: "Add a voice AI agent to any website with a few lines of code"
---

The ThunderPhone embeddable voice widget lets your website visitors talk to an AI agent directly from the browser. No phone call required -- users click a button and start a real-time voice conversation powered by ThunderPhone.

The widget renders as a glassmorphic bar that adapts to light and dark themes, with customizable accent colors and positioning. It is distributed as the `@thunderphone/widget` npm package and is also available via CDN for non-bundler environments.

<Frame>
  <img src="/images/widget-showcase.png" alt="ThunderPhone widget in light and dark themes with various accent colors" />
</Frame>

## Prerequisites

Before embedding the widget, complete these three steps in the [ThunderPhone Dashboard](https://app.thunderphone.com):

<Steps>
<Step title="Create a web widget">
  Go to **Web Widgets** in the dashboard and create a widget. Select the agent you want to expose. Each widget has its own publishable key (`pk_live_...`), which is safe to include in client-side code; the agent is resolved from the key.
</Step>

<Step title="Configure allowed domains">
  On the same widget, add the domains where it will be embedded. Wildcards are supported (e.g., `*.example.com`). The list keeps the widget from working when someone copies your key onto another site; it is not authentication, since a script outside a browser can send any `Origin` header. `localhost` is not allowed automatically in production: add it to the list to test locally against the production API.
</Step>

<Step title="Choose browser overrides">
  If your page sets `language`, `voice`, or `context`, turn each one on under **Browser overrides**. New widgets accept none, and a session request carrying a setting that is off fails with `400 override_not_allowed`. See [Browser overrides](/guides/embed-web-widget#browser-overrides).
</Step>
</Steps>

<Warning>
  Publishable keys (`pk_live_...`) are **not** the same as your secret API tokens. Publishable keys are designed for client-side use and are scoped to widget sessions on your allowed domains. Never use your secret API token in client-side code.
</Warning>

<Note>
  Widget sessions end after 30 minutes by default, or sooner if the agent's own max call duration is shorter. Change the limit per key with `max_call_duration_seconds` on the [publishable key](/api-reference/publishable-keys) (up to 6 hours), or set it to `null` to use the agent's own limit.
</Note>

---

## Quick Start

Install the package:

```bash
npm install @thunderphone/widget
```

Drop the widget into your app:

```tsx
import { ThunderPhoneWidget } from '@thunderphone/widget'
import '@thunderphone/widget/style.css'

function App() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      theme="dark"
      primaryColor="#8b5cf6"
    />
  )
}
```

That's it. Your users will see a glassmorphic call bar that connects them to your AI agent with a single click.

---

## Customization

The widget has four appearance props:

| Prop | Default | Description |
|------|---------|-------------|
| `theme` | `'light'` | `'light'` for white glass, `'dark'` for dark glass |
| `primaryColor` | `'#000000'` (light) / `'#ffffff'` (dark) | Accent color for the start button, waveform, and connecting indicator |
| `title` | `'Voice assistant'` | Text displayed in the widget |
| `position` | `'bottom-right'` | Viewport corner: `'bottom-right'`, `'bottom-left'`, `'top-right'`, `'top-left'` |

<CodeGroup>
```tsx Light theme (default)
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
/>
```

```tsx Dark theme with custom color
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  theme="dark"
  primaryColor="#8b5cf6"
  title="Ask our AI"
/>
```
</CodeGroup>

Three more props customize the session rather than the look -- all are forwarded to the session request when a call starts. Each works only when the widget's publishable key allows it under **Browser overrides**; otherwise the session request fails with `400 override_not_allowed`:

| Prop | Description |
|------|-------------|
| `language` | Per-session language override -- a code or locale such as `en`, `es`, or `fr-FR` |
| `voice` | Per-session voice override -- a voice name such as `maria` |
| `context` | Factual page or site context passed to the agent (truncated server-side to 12,000 characters) |

See the [React component reference](/widget/react) for the full props table.

For a fully custom UI, use the [headless hook](/widget/headless-hook) to manage the voice session while you build your own interface. The hook exposes real-time audio levels for building audio-reactive visualizations.

Each widget conversation is a call. It counts toward your organization's [concurrent-call limit](/api-reference/introduction#call-limits) (20 calls in progress by default, shared with phone and other calls) and a widget cap of 25 active sessions (or your concurrent-call limit, if that is higher). At either limit, a new conversation cannot start until a call ends.

---

## Integration Options

Choose the integration method that fits your stack:

<CardGroup cols={3}>
  <Card title="React Component" icon="react" href="/widget/react">
    Pre-built UI component with built-in call controls and status display. Import, pass props, done.
  </Card>
  <Card title="Headless Hook" icon="code" href="/widget/headless-hook">
    Full control over the UI. The `useThunderPhone` hook manages the voice session while you build your own interface.
  </Card>
  <Card title="CDN / Script Tag" icon="globe" href="/widget/cdn-script-tag">
    No bundler required. Load the widget via a script tag for static sites, WordPress, and other non-React environments.
  </Card>
</CardGroup>

---

## Styling

The widget ships with built-in light and dark themes controlled by the `theme` prop, and an accent color controlled by the `primaryColor` prop. For deeper customization, you can override CSS custom properties and classes. See the [Styling guide](/widget/styling) for details.

<Note>
  Need help? Contact us at [support@thunderphone.com](mailto:support@thunderphone.com)
</Note>
