---
title: "CDN / Script-Tag"
description: "Fügen Sie das ThunderPhone-Sprach-Widget ohne Bundler zu jeder Website hinzu"
---

Der CDN-Build bündelt React intern, sodass Sie das Widget auf statischen Websites, WordPress, Webflow oder jeder Seite verwenden können, auf der Sie HTML hinzufügen können. Kein npm, kein Bundler und kein Framework erforderlich.

## CDN-URLs

<CodeGroup>
```html Latest (recommended)
<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
```

```html Pinned version
<!-- Each stable release also publishes an immutable /widget/vX.Y.Z/ path
     matching the @thunderphone/widget npm version (v1.1.2 at the time of
     writing). If you pin, you own updating the URL for new releases. -->
<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/v1.1.2/style.css" />
<script src="https://cdn.thunderphone.com/widget/v1.1.2/widget.js"></script>
```
</CodeGroup>

<Tip>
  Die `latest`-URLs werden vom Generator für Embed-Snippets im Dashboard erzeugt. Sie werden 5 Minuten zwischengespeichert und übernehmen neue stabile Releases automatisch. Angeheftete `/widget/vX.Y.Z/`-Pfade sind unveränderlich und werden langfristig zwischengespeichert -- wenn Sie eine Version anheften, muss sie dem `@thunderphone/widget`-npm-Release entsprechen, gegen das Sie entwickeln.
</Tip>

---

## Grundlegende Verwendung

```html
<!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',
      publishableKey: 'pk_live_your_publishable_key',
    })
  </script>

</body>
</html>
```

Das Widget wird im Zielelement eingebunden und als **Leiste mit fester Position in einer Ecke des Viewports** dargestellt (standardmäßig `bottom-right`, gesteuert durch die Option `position`). Das Einbindungselement ist lediglich die React-Root -- seine Position auf der Seite beeinflusst nicht, wo das Widget erscheint.

---

## Einbindungsoptionen

`ThunderPhone.mount()` akzeptiert dieselben Optionen wie die React-Komponente sowie die Eigenschaft `element`:

| Option | Typ | Erforderlich | Standard | Beschreibung |
|--------|------|-------------|----------|--------------|
| `element` | `string \| HTMLElement` | Ja | -- | CSS-Selektor (z. B. `'#thunderphone'`) oder Referenz auf ein DOM-Element. |
| `publishableKey` | `string` | Ja | -- | Veröffentlichbarer API-Schlüssel (`pk_live_...`). Der Agent wird automatisch anhand der Widget-Konfiguration des Schlüssels aufgelöst. |
| `theme` | `'light' \| 'dark'` | Nein | `'light'` | Farbschema. |
| `primaryColor` | `string` | Nein | `'#000000'` (hell) / `'#ffffff'` (dunkel) | CSS-Farbzeichenfolge, die als Akzentfarbe verwendet wird. |
| `title` | `string` | Nein | `'Voice assistant'` | Text, der in der Widget-Leiste angezeigt wird. |
| `position` | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | Nein | `'bottom-right'` | Feste Position im Viewport. |
| `apiBase` | `string` | Nein | `'https://api.thunderphone.com/v1'` | Überschreibung der API-Basis-URL. |
| `language` | `string` | Nein | -- | Sprachüberschreibung pro Sitzung – ein Sprachcode oder Gebietsschema wie `en`, `es` oder `fr-FR`. Wenn nicht festgelegt, gilt die konfigurierte Sprache des Agenten. Erfordert `language` unter den [Browser-Überschreibungen](/de/guides/embed-web-widget) des Schlüssels. |
| `voice` | `string` | Nein | -- | Stimmenüberschreibung pro Sitzung – ein Stimmenname wie `maria`. Wenn nicht festgelegt, gilt die konfigurierte Stimme des Agenten. Erfordert `voice` unter den [Browser-Überschreibungen](/de/guides/embed-web-widget) des Schlüssels. |
| `context` | `string` | Nein | -- | Faktischer Seiten- oder Website-Kontext pro Sitzung, der an den Agenten übergeben wird. Serverseitig auf 12.000 Zeichen gekürzt. Erfordert `context` unter den [Browser-Überschreibungen](/de/guides/embed-web-widget) des Schlüssels. |
| `onConnect` | `() => void` | Nein | -- | Wird aufgerufen, wenn die Sprachsitzung verbunden wird. |
| `onDisconnect` | `() => void` | Nein | -- | Wird aufgerufen, wenn die Sitzung endet. |
| `onError` | `(error) => void` | Nein | -- | Wird bei Fehlern aufgerufen. Der Fehler enthält die Felder `error` (Code) und `message`. |
| `ringtone` | `boolean \| string` | Nein | `false` | Spielen Sie während des Verbindungsaufbaus einen Klingelton ab. `true` für den Standardklingelton oder eine URL-Zeichenfolge für eigenes Audio. |

---

## Bereinigung

`ThunderPhone.mount()` gibt eine Widget-Instanz mit Bereinigungsmethoden zurück:

```html
<script>
  var widget = ThunderPhone.mount({
    element: '#thunderphone',
    publishableKey: 'pk_live_your_publishable_key',
  })

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

  // Or equivalently:
  widget.destroy()
</script>
```

Sowohl `unmount()` als auch `destroy()` bewirken dasselbe – sie trennen alle aktiven Sprachsitzungen und entfernen das Widget aus dem DOM. Verwenden Sie die Variante, die sich in Ihrem Code besser liest.

<Note>
  Bereinigen Sie das Widget immer, wenn Sie in Single-Page-Anwendungen weg navigieren oder das enthaltende Element entfernt wird. Dadurch wird sichergestellt, dass aktive Sprachsitzungen ordnungsgemäß getrennt werden.
</Note>

---

## Beispiele

### Dunkles Theme mit benutzerdefinierter Farbe

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

<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  ThunderPhone.mount({
    element: '#thunderphone',
    publishableKey: 'pk_live_your_publishable_key',
    theme: 'dark',
    primaryColor: '#8b5cf6',
    title: 'Talk to our AI',
  })
</script>
```

### Benutzerdefinierte Position

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

<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  ThunderPhone.mount({
    element: '#thunderphone',
    publishableKey: 'pk_live_your_publishable_key',
    position: 'bottom-left',
  })
</script>
```

### Mit Ereignis-Callbacks

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

<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  ThunderPhone.mount({
    element: '#thunderphone',
    publishableKey: 'pk_live_your_publishable_key',
    onConnect: function () {
      console.log('Call started')
    },
    onDisconnect: function () {
      console.log('Call ended')
    },
    onError: function (error) {
      console.error('Widget error:', error.error, error.message)
    },
  })
</script>
```

### Mit Klingelton

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

<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>
<script>
  ThunderPhone.mount({
    element: '#thunderphone',
    publishableKey: 'pk_live_your_publishable_key',
    ringtone: true, // or a custom URL: 'https://example.com/ringtone.mp3'
  })
</script>
```

### Mit einer DOM-Elementreferenz

```html
<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,
    publishableKey: 'pk_live_your_publishable_key',
  })
</script>
```

### WordPress-/CMS-Integration

Fügen Sie dies zu einem benutzerdefinierten HTML-Block oder zum Footer Ihres Themes hinzu:

```html
<link rel="stylesheet" href="https://cdn.thunderphone.com/widget/latest/style.css" />
<script src="https://cdn.thunderphone.com/widget/latest/widget.js"></script>

<div id="thunderphone-widget"></div>
<script>
  ThunderPhone.mount({
    element: '#thunderphone-widget',
    publishableKey: 'pk_live_your_publishable_key',
  })
</script>
```

<Tip>
  Das `<div>` kann überall platziert werden – es dient nur als Einbindungspunkt. Das Widget selbst wird als fest positioniertes Overlay in einer Ecke des Viewports gerendert (festgelegt durch die Option `position`) und fließt nicht mit dem umgebenden Inhalt.
</Tip>

---

## Fehlerbehebung

<AccordionGroup>
  <Accordion title="Widget wird nicht angezeigt">
    Stellen Sie sicher, dass sowohl die CSS- als auch die JS-Dateien geladen sind. Prüfen Sie die Browserkonsole auf Netzwerkfehler. Vergewissern Sie sich, dass das Zielelement im DOM vorhanden ist, bevor Sie `ThunderPhone.mount()` aufrufen.
  </Accordion>

  <Accordion title="ThunderPhone ist nicht definiert">
    Das Skript wurde noch nicht geladen. Stellen Sie sicher, dass das `<script>`-Tag für `widget.js` vor Ihrem Mount-Aufruf erscheint, oder kapseln Sie den Mount-Aufruf in einen `DOMContentLoaded`-Listener.
  </Accordion>

  <Accordion title="Fehler: Domain nicht zulässig">
    Fügen Sie Ihre Domain auf der Seite **Web-Widgets** unter [app.thunderphone.com](https://app.thunderphone.com) zu den zulässigen Domains des Widgets hinzu. `localhost` ist in der Produktion nicht automatisch zulässig; fügen Sie es zur Liste hinzu, um lokal zu testen.
  </Accordion>
</AccordionGroup>

---

## Nächste Schritte

<CardGroup cols={2}>
  <Card title="Styling" icon="palette" href="/de/widget/styling">
    Passen Sie das Erscheinungsbild des Widgets mit benutzerdefinierten CSS-Eigenschaften an.
  </Card>
  <Card title="React-Komponente" icon="react" href="/de/widget/react">
    Sie verwenden React? Die Komponentenintegration ist einfacher.
  </Card>
</CardGroup>
