Skip to main content
The ThunderPhoneWidget component renders a glassmorphic call bar with built-in controls for muting, ending the call, and displaying connection status. It is the fastest way to add voice AI to a React app.

Installation

npm install @thunderphone/widget

Basic Usage

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

function App() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
    />
  )
}
You must import the CSS file for the widget to render correctly. Without it, the widget will be unstyled.

Props

The component accepts the following props via ThunderPhoneWidgetProps:
PropTypeRequiredDefaultDescription
publishableKeystringYesPublishable API key (pk_live_...) from the Developers settings. The agent is resolved automatically from the key’s widget configuration.
theme'light' | 'dark'No'light'Color scheme. Applies tp--light or tp--dark class to the widget root.
primaryColorstringNo'#6366f1'CSS color string used as the accent color (call button, active indicators).
titlestringNo'Voice assistant'Text displayed in the widget bar.
position'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'No'bottom-right'Fixed viewport position for the widget.
apiBasestringNo'https://api.thunderphone.com/v1'API base URL override.
onConnect() => voidNoCalled when the voice session successfully connects.
onDisconnect() => voidNoCalled when the session ends.
onError(error) => voidNoCalled on errors. The error object has error (code) and message fields.
classNamestringNoAdditional CSS class name applied to the widget container.
ringtoneboolean | stringNofalsePlay a ringtone while connecting. true for the default ringtone, or a URL string for custom audio.

Examples

Dark Theme with Custom Color

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

function App() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      theme="dark"
      primaryColor="#8b5cf6"
      title="Talk to our AI"
    />
  )
}

Custom Position

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

function App() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      position="bottom-left"
    />
  )
}

With Event Callbacks

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

function SupportWidget() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      onConnect={() => {
        console.log('Voice session connected')
        analytics.track('widget_call_started')
      }}
      onDisconnect={() => {
        console.log('Voice session ended')
        analytics.track('widget_call_ended')
      }}
      onError={(error) => {
        console.error(`Widget error: ${error.error} - ${error.message}`)
      }}
    />
  )
}

With Custom Styling

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

function BrandedWidget() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      primaryColor="#4a90d9"
      className="my-custom-widget"
    />
  )
}
.my-custom-widget .tp-button--end {
  background-color: #e74c3c;
}
See the Styling guide for all available CSS classes and custom properties.

With Ringtone

Play a phone-ringing sound while the connection is being established:
import { ThunderPhoneWidget } from '@thunderphone/widget'
import '@thunderphone/widget/style.css'

function PhoneWidget() {
  return (
    <ThunderPhoneWidget
      publishableKey="pk_live_your_publishable_key"
      ringtone={true}
    />
  )
}
Use a custom ringtone by passing an audio file URL:
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  ringtone="https://example.com/my-ringtone.mp3"
/>
The ringtone loops while the widget is in the connecting state and fades out smoothly when the agent connects.

With Custom API Base

You only need to set apiBase if you are using a self-hosted or proxy API endpoint. The default points to https://api.thunderphone.com/v1.
<ThunderPhoneWidget
  publishableKey="pk_live_your_publishable_key"
  apiBase="https://your-proxy.example.com/v1"
/>

Error Handling

When the onError callback fires, it receives an error object with two fields:
FieldTypeDescription
errorstringMachine-readable error code
messagestringHuman-readable error description
Common error codes include domain not allowed, agent not found, and invalid API key.

Next Steps

Headless Hook

Need full control over the UI? Use the useThunderPhone hook instead.

Styling

Customize colors, sizes, and layout with CSS custom properties.