Skip to main content
The CDN build bundles React internally, so you can use the widget on static sites, WordPress, Webflow, or any page where you can add HTML. No npm, no bundler, no framework required.

CDN URLs

<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/v0.3.0/style.css" />
<script src="https://cdn.thunderphone.com/widget/v0.3.0/widget.js"></script>
Use a versioned URL in production to avoid unexpected changes. The latest URL is cached for 5 minutes and is useful during development.

Basic Usage

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
</head>
<body>

  <div id="thunderphone"></div>

  <script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
  <script>
    ThunderPhone.mount({
      element: '#thunderphone',
      apiKey: 'pk_live_your_publishable_key',
      agentId: 123,
    })
  </script>

</body>
</html>
The widget renders inside the target element and is ready to use immediately.

Mount Options

ThunderPhone.mount() accepts the same options as the React component, plus the element property:
OptionTypeRequiredDescription
elementstring | HTMLElementYesCSS selector (e.g., '#thunderphone') or a DOM element reference
apiKeystringYesPublishable API key (pk_live_...)
agentIdnumberYesID of the agent to connect to
apiBasestringNoAPI base URL (defaults to https://api.thunderphone.com/v1)
onConnect() => voidNoCalled when the voice session connects
onDisconnect() => voidNoCalled when the session ends
onError(error) => voidNoCalled on errors. Error has error (code) and message fields
ringtoneboolean | stringNoPlay a ringtone while connecting. true for the default ringtone, or a URL string for custom audio. Disabled by default

Cleanup

ThunderPhone.mount() returns a widget instance with cleanup methods:
<script>
  const widget = ThunderPhone.mount({
    element: '#thunderphone',
    apiKey: 'pk_live_your_publishable_key',
    agentId: 123,
  })

  // Later, when you want to remove the widget:
  widget.unmount()

  // Or equivalently:
  widget.destroy()
</script>
Both unmount() and destroy() do the same thing — they disconnect any active session and remove the widget from the DOM. Use whichever reads better in your code.
Always clean up the widget when navigating away in single-page applications or when the containing element is removed. This ensures active voice sessions are properly disconnected.

Examples

With Event Callbacks

<div id="thunderphone"></div>

<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  ThunderPhone.mount({
    element: '#thunderphone',
    apiKey: 'pk_live_your_publishable_key',
    agentId: 123,
    onConnect: function () {
      console.log('Call started')
    },
    onDisconnect: function () {
      console.log('Call ended')
    },
    onError: function (error) {
      console.error('Widget error:', error.error, error.message)
    },
  })
</script>

With Ringtone

<div id="thunderphone"></div>

<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  ThunderPhone.mount({
    element: '#thunderphone',
    apiKey: 'pk_live_your_publishable_key',
    agentId: 123,
    ringtone: true, // or a custom URL: 'https://example.com/ringtone.mp3'
  })
</script>

Using a DOM Element Reference

<div id="thunderphone"></div>

<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  var container = document.getElementById('thunderphone')

  ThunderPhone.mount({
    element: container,
    apiKey: 'pk_live_your_publishable_key',
    agentId: 123,
  })
</script>

WordPress / CMS Integration

Add this to a Custom HTML block or your theme’s footer:
<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/v0.3.0/style.css" />
<script src="https://cdn.thunderphone.com/widget/v0.3.0/widget.js"></script>

<div id="thunderphone-widget"></div>
<script>
  ThunderPhone.mount({
    element: '#thunderphone-widget',
    apiKey: 'pk_live_your_publishable_key',
    agentId: 123,
  })
</script>
Place the <div> wherever you want the widget to appear on the page. The widget renders inline, so it flows naturally with surrounding content.

Troubleshooting

Make sure both the CSS and JS files are loaded. Check the browser console for network errors. Verify that the target element exists in the DOM before calling ThunderPhone.mount().
The script has not loaded yet. Ensure the <script> tag for widget.js appears before your mount call, or wrap the mount call in a DOMContentLoaded listener.
Add your domain to the allowed domains list in Developers settings at app.thunderphone.com. Remember that localhost is always allowed.

Next Steps