---
title: "Intégrer le widget web"
description: "Ajoutez un agent vocal à votre site marketing ou d’assistance avec une seule balise de script — les visiteurs lui parlent directement depuis le navigateur, sans numéro de téléphone."
---

Le widget web offre aux visiteurs de votre site une conversation en un clic pour parler
avec un agent IA, en utilisant le microphone du navigateur. Il s’agit d’un SDK
JavaScript / React distinct avec sa propre [référence du SDK](/fr/widget/overview)
— ce guide se concentre sur la configuration côté ThunderPhone requise par le widget.

<Note>
  Vous pouvez tout faire sans cURL : la page **Widgets web** du tableau de bord
  (`/dashboard/web-widgets`) crée le widget, définit son mode
  et son agent, gère les domaines autorisés et vous fournit l’extrait d’intégration.
</Note>

## Prérequis

<Steps>
  <Step title="Créer un agent">
    L’agent dont le prompt et la voix exécuteront la session du widget. Définissez
    `widget_enabled: true` (valeur par défaut).
  </Step>
  <Step title="Choisir le mode de routage">
    - `mode="agent"` — un agent statique par clé. Le plus simple.
    - `mode="webhook"` — votre serveur choisit l’agent pour chaque visiteur via un
      [webhook `web.incoming`](/fr/webhooks/call-incoming). Utilisez ce mode pour les
      utilisateurs connectés, les tests A/B ou le routage par page.
  </Step>
  <Step title="Répertorier les domaines autorisés">
    Indiquez chaque nom d’hôte qui intégrera le widget. Les navigateurs envoient l’origine de la
    page avec chaque requête de session ; cette liste empêche donc votre clé de
    fonctionner si quelqu’un la copie sur un autre site. Il ne s’agit pas d’une
    authentification : un script hors d’un navigateur peut envoyer n’importe quel en-tête
    `Origin`. `localhost` n’est pas automatiquement autorisé en production ; pour
    effectuer des tests locaux avec l’API de production, ajoutez `localhost` à la
    liste.
  </Step>
  <Step title="Choisir les surcharges du navigateur">
    Déterminez quels paramètres de session votre page peut envoyer. Les nouvelles clés n’en acceptent
    aucun ; consultez [Surcharges du navigateur](#browser-overrides).
  </Step>
</Steps>

## Créer une clé publiable

<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>

La réponse inclut une `key` commençant par `pk_live_...`. **Les clés publiables
sont publiques par conception** — vous pouvez les inclure sans risque dans votre bundle front-end.
Consultez la [référence des clés publiables](/api-reference/publishable-keys) pour
tous les champs.

<Warning>
  `allowed_domains` doit contenir au moins une entrée. `*.example.com`
  correspond aux sous-domaines (par exemple, `api.example.com`), mais **pas** au
  domaine nu. Les jokers nus comme `*` ou `*.*` sont refusés.
</Warning>

## Ajoutez le widget à votre site

Trois options d’intégration sont présentées dans la
[documentation du SDK du widget](/fr/widget/overview) :

<CardGroup cols={3}>
  <Card title="Composant React" icon="react" href="/fr/widget/react">
    `<ThunderPhoneWidget publishableKey="pk_live_..." />`.
  </Card>
  <Card title="Hook sans interface" icon="circle-nodes" href="/fr/widget/headless-hook">
    `useThunderPhone()` pour les interfaces personnalisées.
  </Card>
  <Card title="Balise script CDN" icon="code" href="/fr/widget/cdn-script-tag">
    `ThunderPhone.mount({...})` pour les sites sans bundler.
  </Card>
</CardGroup>

Les trois acceptent la même `publishableKey` et affichent le bouton de microphone
ainsi que l’élément audio en appel.

## Remplacements du navigateur

Le widget peut envoyer quatre paramètres par session depuis la page :

| Paramètre | Propriété du widget | Ce que cela modifie |
|---------|-------------|-----------------|
| `context` | `context` | Texte de la page, ajouté au prompt de l’agent comme référence |
| `variables` | aucun (`POST /v1/widget/session` brut uniquement) | Valeurs des espaces réservés `{{variable}}` dans le prompt |
| `voice` | `voice` | La voix de l’agent pour cette session |
| `language` | `language` | La langue dans laquelle la session démarre |

Votre clé publiable est publique. Toute personne qui la possède peut donc envoyer ces
paramètres, y compris depuis un script qui usurpe votre domaine. Ils sont tous
désactivés tant que vous ne les autorisez pas sur la clé : cochez-les dans **Remplacements du navigateur**
lorsque vous créez ou modifiez le widget dans le tableau de bord, ou définissez
`allowed_overrides` via l’
[API des clés publiables](/api-reference/publishable-keys). N’autorisez que les paramètres
effectivement envoyés par votre page.

Une requête de session contenant un paramètre que la clé n’autorise pas échoue
avec `400` et le nomme :

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

La vérification s’applique dans les deux modes. En mode webhook, un paramètre autorisé est
également transmis à votre webhook `web.incoming` (`context` arrive sous le nom
`website_context`). Les clés créées avant l’existence de ce paramètre autorisent les quatre,
afin que les intégrations existantes continuent de fonctionner ; désactivez ceux que vous n’utilisez pas.

Le `context` du widget est tronqué à 12 000 caractères (environ 3 400
tokens de texte anglais standard) et compte dans le
[supplément lié à la taille du prompt](/fr/guides/billing-and-topups).
L’agent est invité à le traiter comme du contenu de page, et non comme des instructions.

## Webhooks en mode widget

Lorsque `mode="webhook"`, ThunderPhone appelle votre `webhook_url` au début de chaque
session avec une charge utile `web.incoming`. Renvoyez la configuration
de l’agent que vous souhaitez exécuter pour ce visiteur — elle suit le même
[schéma de réponse](/fr/webhooks/call-incoming) que les appels
téléphoniques :

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

Vous pouvez intégrer au prompt le contexte de votre propre session (le client qui navigue,
la page qu’il consulte) et changer d’agent selon le déploiement.

## Observer les sessions

Les sessions du widget apparaissent dans
[`GET /v1/calls`](/api-reference/calls#list-calls) avec
`direction="widget"` — même transcription, enregistrement, évaluation et
facturation que les appels téléphoniques. Filtrez par `direction` pour créer un
tableau de bord dédié au widget.

---

## Étapes suivantes

<CardGroup cols={2}>
  <Card title="Référence du SDK Widget" icon="window-maximize" href="/fr/widget/overview">
    Détails d’intégration React / hook / CDN.
  </Card>
  <Card title="Configuration dynamique par appel" icon="bolt" href="/fr/guides/dynamic-call-config">
    Implémentez le flux `mode="webhook"` de bout en bout.
  </Card>
  <Card title="Référence des clés publiables" icon="key" href="/api-reference/publishable-keys">
    Chaque champ de la ressource clé.
  </Card>
  <Card title="API des sessions micro" icon="microphone" href="/api-reference/mic-sessions">
    Ignorez le widget ; pilotez LiveKit directement pour des interfaces personnalisées.
  </Card>
</CardGroup>
