useThunderPhone hook gives you complete control over the user interface while ThunderPhone manages the voice session, audio routing, and connection state. Use it when the pre-built widget does not fit your design or you need custom call flows.
Installation
The headless hook does not require importing
@thunderphone/widget/style.css since you are providing your own UI. However, you must still install the same @thunderphone/widget package.Basic Usage
Options
Pass these options touseThunderPhone via UseThunderPhoneOptions:
| Option | Type | Required | Description |
|---|---|---|---|
apiKey | string | Yes | Publishable API key (pk_live_...) |
agentId | number | Yes | ID of the agent to connect to |
apiBase | string | No | API base URL override (defaults to https://api.thunderphone.com/v1) |
onConnect | () => void | No | Called when the voice session connects |
onDisconnect | () => void | No | Called when the session ends |
onError | (error) => void | No | Called on errors. Error has error (code) and message fields |
ringtone | boolean | string | No | Play a ringtone while connecting. true for the default ringtone, or a URL string for custom audio. Disabled by default |
Return Value
The hook returns aUseThunderPhoneReturn object:
| Property | Type | Description |
|---|---|---|
state | 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error' | Current connection state |
connect | () => void | Start a voice session |
disconnect | () => void | End the current session |
toggleMute | () => void | Toggle microphone mute on/off |
isMuted | boolean | Whether the microphone is currently muted |
error | string | undefined | Error message when state is 'error' |
agentName | string | undefined | Display name of the connected agent |
audio | ReactNode | Invisible element that handles the audio connection — must be rendered |
State Machine
Thestate property follows this lifecycle:
| State | Description |
|---|---|
idle | No active session. Ready to call connect(). |
connecting | Session is being established. Disable the call button during this state. |
connected | Voice session is active. The user is talking to the agent. |
disconnected | Session has ended cleanly. Transitions back to idle. |
error | Something went wrong. Check phone.error for the message. Automatically returns to idle after a timeout. |
Examples
With Mute Control
With Ringtone
Play a ringing sound while connecting to simulate a phone call:connecting state and fades out when the agent connects. Pass true for the built-in default ringtone, or a URL string to use your own audio file.
With Event Callbacks
Full Custom UI
Tips
Always render phone.audio
Always render phone.audio
The
phone.audio element is invisible but required. Place it anywhere in your JSX — it renders no visible DOM but manages the WebRTC audio connection internally.Disable the button while connecting
Disable the button while connecting
Handle the error state gracefully
Handle the error state gracefully
When the state is
error, display phone.error to the user. The state will automatically return to idle after a few seconds, so the user can try again.Use callbacks for side effects
Use callbacks for side effects
The
onConnect, onDisconnect, and onError callbacks are ideal for analytics, logging, or triggering other application logic without polling the state.