---
title: "Sluit de webwidget in"
description: "Plaats met één script-tag een spraakagent op je marketing- of supportsite — bezoekers praten er rechtstreeks vanuit de browser mee, zonder telefoonnummer."
---

De webwidget geeft bezoekers van je site een gesprek via klik om te praten
met een AI-agent, met behulp van de microfoon van de browser. Het is een aparte
JavaScript- / React-SDK met een eigen [SDK-referentie](/nl/widget/overview)
— deze handleiding richt zich op de configuratie aan de ThunderPhone-kant die de widget nodig heeft.

<Note>
  Je kunt dit allemaal doen zonder cURL: de dashboardpagina **Webwidgets**
  (`/dashboard/web-widgets`) maakt de widget, stelt de modus
  en agent in, beheert toegestane domeinen en geeft je het embedfragment.
</Note>

## Vereisten

<Steps>
  <Step title="Maak een agent">
    De agent waarvan de prompt en stem de widgetsessie uitvoeren. Stel
    `widget_enabled: true` in (de standaardinstelling).
  </Step>
  <Step title="Bepaal de routeringsmodus">
    - `mode="agent"` — één statische agent per sleutel. Het eenvoudigst.
    - `mode="webhook"` — je server kiest de agent per bezoeker via een
      [`web.incoming`-webhook](/nl/webhooks/call-incoming). Gebruik dit voor
      ingelogde gebruikers, A/B-tests of routering per pagina.
  </Step>
  <Step title="Vermeld de toegestane domeinen">
    Geef elke hostnaam op die de widget insluit. Browsers sturen de
    oorsprong van de pagina mee met elk sessieverzoek, zodat de lijst voorkomt dat je sleutel
    werkt wanneer iemand deze naar een andere site kopieert. Dit is geen
    authenticatie: een script buiten een browser kan elke `Origin`-
    header versturen. `localhost` is in productie niet automatisch toegestaan; voeg
    `localhost` aan de lijst toe om lokaal te testen met de productie-API.
  </Step>
  <Step title="Kies de browseroverschrijvingen">
    Bepaal welke sessie-instellingen je pagina mag versturen. Nieuwe sleutels accepteren
    geen; zie [Browseroverschrijvingen](#browser-overrides).
  </Step>
</Steps>

## Maak een publiceerbare sleutel

<CodeGroup>
```bash Static agent
curl -X POST https://api.thunderphone.com/v1/publishable-key \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name":            "Marketing site (prod)",
    "mode":            "agent",
    "agent_id":        12,
    "allowed_domains": ["example.com", "*.example.com"],
    "allowed_overrides": ["context"]
  }'
```

```bash Dynamic via webhook
curl -X POST https://api.thunderphone.com/v1/publishable-key \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name":            "Support (dynamic)",
    "mode":            "webhook",
    "webhook_url":     "https://example.com/thunderphone/widget-hook",
    "allowed_domains": ["support.example.com"]
  }'
```
</CodeGroup>

Het antwoord bevat een `key` die begint met `pk_live_...`. **Publiceerbare
sleutels zijn standaard openbaar** — je kunt ze veilig opnemen in je front-endbundle.
Zie de [referentie voor publiceerbare sleutels](/api-reference/publishable-keys) voor
alle velden.

<Warning>
  `allowed_domains` moet minstens één invoer bevatten. `*.example.com`
  komt overeen met subdomeinen (bijv. `api.example.com`), maar **niet** met
  het hoofddomein. Losse wildcards zoals `*` of `*.*` worden afgewezen.
</Warning>

## Plaats de widget op je site

Drie integratieopties worden behandeld in de
[widget-SDK-documentatie](/nl/widget/overview):

<CardGroup cols={3}>
  <Card title="React-component" icon="react" href="/nl/widget/react">
    `<ThunderPhoneWidget publishableKey="pk_live_..." />`.
  </Card>
  <Card title="Headless hook" icon="circle-nodes" href="/nl/widget/headless-hook">
    `useThunderPhone()` voor aangepaste interfaces.
  </Card>
  <Card title="CDN-scripttag" icon="code" href="/nl/widget/cdn-script-tag">
    `ThunderPhone.mount({...})` voor sites zonder bundler.
  </Card>
</CardGroup>

Alle drie accepteren dezelfde `publishableKey` en renderen de microfoonknop
plus het audio-element tijdens gesprekken.

## Browseroverschrijvingen

De widget kan vier instellingen per sessie vanaf de pagina verzenden:

| Instelling | Widget-prop | Wat het verandert |
|---------|-------------|-----------------|
| `context` | `context` | Tekst van de pagina, als referentie toegevoegd aan de agentprompt |
| `variables` | geen (alleen onbewerkte `POST /v1/widget/session`) | Waarden voor tijdelijke aanduidingen `{{variable}}` in de prompt |
| `voice` | `voice` | De stem van de agent voor deze sessie |
| `language` | `language` | De taal waarin de sessie begint |

Je publishable key is openbaar, dus iedereen die deze heeft kan deze
instellingen verzenden, ook vanuit een script dat je domein nabootst. Ze staan
daarom allemaal uit totdat je ze voor de key toestaat: vink ze aan onder **Browser
overrides** wanneer je de widget in het dashboard maakt of bewerkt, of stel
`allowed_overrides` in via de
[API voor publishable keys](/api-reference/publishable-keys). Sta alleen toe wat
je pagina daadwerkelijk verzendt.

Een sessieverzoek met een instelling die de sleutel niet toestaat,
mislukt met `400` en vermeldt deze:

```json
{
  "error": "override_not_allowed",
  "fields": ["voice"],
  "message": "This publishable key does not allow the browser to set `voice`. ..."
}
```

De controle geldt in beide modi. In webhookmodus wordt een toegestane instelling
ook doorgestuurd naar je `web.incoming`-webhook (`context` komt aan als
`website_context`). Sleutels die zijn gemaakt voordat deze instelling bestond, staan alle
vier toe, zodat bestaande insluitingen blijven werken; schakel uit wat je niet gebruikt.

Widget-`context` wordt afgekapt op 12.000 tekens (ongeveer 3.400
tokens van typische Engelse tekst) en telt mee voor de
[toeslag voor promptgrootte](/nl/guides/billing-and-topups).
De agent krijgt de instructie dit als pagina-inhoud te behandelen, niet als instructies.

## Webhooks voor widgetmodus

Wanneer `mode="webhook"` is ingesteld, roept ThunderPhone je `webhook_url` aan bij elke
sessiestart met een `web.incoming`-payload. Geef de agentconfiguratie terug
die je voor die bezoeker wilt uitvoeren — deze volgt hetzelfde
[antwoordschema](/nl/webhooks/call-incoming) als telefoongesprekken:

```json
{
  "prompt":  "You are a VIP concierge for Jane Doe.",
  "voice":   "john",
  "product": "storm-base",
  "tools":   [ /* per-customer tools */ ]
}
```

Je kunt context uit je eigen sessie (welke klant browst,
op welke pagina ze zijn) in de prompt opnemen en agents per uitrol wisselen.

## Sessies bekijken

Widgetsessies verschijnen in
[`GET /v1/calls`](/api-reference/calls#list-calls) met
`direction="widget"` — met hetzelfde transcript, dezelfde opname, beoordeling en
facturering als telefoongesprekken. Filter op `direction` om een dashboard
alleen voor widgets te bouwen.

---

## Volgende stappen

<CardGroup cols={2}>
  <Card title="Widget SDK-referentie" icon="window-maximize" href="/nl/widget/overview">
    Details over React-, hook- en CDN-integratie.
  </Card>
  <Card title="Dynamische configuratie per oproep" icon="bolt" href="/nl/guides/dynamic-call-config">
    Implementeer de `mode="webhook"`-flow van begin tot eind.
  </Card>
  <Card title="Referentie voor publiceerbare sleutels" icon="key" href="/api-reference/publishable-keys">
    Elk veld van de sleutelresource.
  </Card>
  <Card title="API voor microfoonsessies" icon="microphone" href="/api-reference/mic-sessions">
    Sla de widget over; gebruik LiveKit rechtstreeks voor aangepaste UI's.
  </Card>
</CardGroup>
