> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# WebSocket

> **Note**
>
> Cette documentation s’adresse aux développeurs intégrant directement l’API WebSocket d’ElevenLabs. Pour plus de
> simplicité, envisagez d’utiliser [les SDK officiels fournis par ElevenLabs](/docs/fr/eleven-agents/libraries/python).

L’API WebSocket d’[ElevenAgents](https://elevenlabs.io/agents) permet de créer des conversations vocales interactives en temps réel avec des agents IA. En établissant une connexion WebSocket, vous pouvez envoyer des entrées audio et recevoir des réponses audio en temps réel, pour créer des expériences conversationnelles réalistes.

> **Note**
>
> Point de terminaison : `wss://api.elevenlabs.io/v1/convai/conversation?agent_id={agent_id}`

## Authentification

### Utiliser l’ID de l’agent

Pour les agents publics, vous pouvez utiliser directement `agent_id` dans l’URL WebSocket, sans authentification supplémentaire :

```bash
wss://api.elevenlabs.io/v1/convai/conversation?agent_id=<your-agent-id>
```

### Utiliser une URL signée

Pour les agents privés ou les conversations nécessitant une autorisation, obtenez une URL signée depuis votre serveur, qui communique de manière sécurisée avec l’API ElevenLabs à l’aide de votre clé API.

### Exemple avec cURL

**Requête :**

```bash
curl -X GET "https://api.elevenlabs.io/v1/convai/conversation/get-signed-url?agent_id=<your-agent-id>" \
     -H "xi-api-key: <your-api-key>"
```

**Réponse :**

```json
{
  "signed_url": "wss://api.elevenlabs.io/v1/convai/conversation?agent_id=<your-agent-id>&token=<token>"
}
```

> **Warning**
>
> N’exposez jamais votre clé API ElevenLabs côté client.

## Événements WebSocket

### Événements du client vers le serveur

Les événements suivants peuvent être envoyés du client vers le serveur :

#### Mises à jour contextuelles

Envoyez des informations contextuelles sans interrompre la conversation afin de mettre à jour son état. Vous pouvez ainsi fournir un contexte supplémentaire sans perturber le déroulement de la conversation en cours.

```javascript
{
  "type": "contextual_update",
  "text": "User clicked on pricing page"
}
```

**Cas d’utilisation :**

* Mise à jour du statut ou des préférences de l’utilisateur
* Fourniture d’un contexte environnemental
* Ajout d’informations générales
* Suivi des interactions avec l’interface utilisateur

**Points clés :**

* N’interrompt pas le déroulement de la conversation en cours
* Les mises à jour sont intégrées sous forme d’appels d’outils dans l’historique de la conversation
* Aide à préserver le contexte sans rompre le dialogue naturel

> **Note**
>
> Les mises à jour contextuelles sont traitées de manière asynchrone et ne nécessitent pas de réponse directe du serveur.

#### [Guide de l’API WebSocket](/docs/fr/eleven-agents/api-reference/eleven-agents/websocket)

Consultez la documentation de référence de l’API WebSocket ElevenLabs Agents pour obtenir des structures de messages,
des paramètres et des exemples détaillés.

## Exemple d’implémentation Next.js

Cet exemple montre comment implémenter un client d’agent conversationnel basé sur WebSocket dans Next.js à l’aide de l’API WebSocket d’ElevenLabs.

> **Note**
>
> Bien que cet exemple utilise le package `voice-stream` pour gérer l’entrée du microphone, vous pouvez
> implémenter votre propre solution pour capturer et encoder l’audio. L’objectif est ici de présenter
> la connexion WebSocket et la gestion des événements avec l’API ElevenLabs.

#### Installer les dépendances requises

Commencez par installer les packages nécessaires :

```bash
npm install voice-stream
```

Le package `voice-stream` gère l’accès au microphone et le streaming audio, en encodant automatiquement l’audio au format base64 requis par l’API ElevenLabs.

> **Note**
>
> Cet exemple utilise Tailwind CSS pour la mise en forme. Pour ajouter Tailwind à votre projet Next.js :
>
> ```bash
> npm install -D tailwindcss postcss autoprefixer
> npx tailwindcss init -p
> ```
>
> Suivez ensuite le [guide officiel de configuration de Tailwind CSS pour Next.js](https://tailwindcss.com/docs/guides/nextjs).
>
> Vous pouvez également remplacer les attributs className par vos propres styles CSS.

#### Créer les types WebSocket

Définissez les types des événements WebSocket :

**`app/types/websocket.ts`**

```typescript app/types/websocket.ts
type BaseEvent = {
  type: string;
};

type UserTranscriptEvent = BaseEvent & {
  type: "user_transcript";
  user_transcription_event: {
    user_transcript: string;
  };
};

type AgentResponseEvent = BaseEvent & {
  type: "agent_response";
  agent_response_event: {
    agent_response: string;
  };
};

type AgentResponseCorrectionEvent = BaseEvent & {
  type: "agent_response_correction";
  agent_response_correction_event: {
    original_agent_response: string;
    corrected_agent_response: string;
  };
};

type AudioResponseEvent = BaseEvent & {
  type: "audio";
  audio_event: {
    audio_base_64: string;
    event_id: number;
    alignment: {
      chars: string[];
      char_durations_ms: number[];
      char_start_times_ms: number[];
    };
  };
};

type InterruptionEvent = BaseEvent & {
  type: "interruption";
  interruption_event: {
    reason: string;
  };
};

type PingEvent = BaseEvent & {
  type: "ping";
  ping_event: {
    event_id: number;
    ping_ms?: number;
  };
};

type AgentChatResponsePartEvent = BaseEvent & {
  type: "agent_chat_response_part";
  text_response_part: {
    type: "start" | "delta" | "stop";
    text: string;
    event_id: number;
    response_id: string;
  };
};

export type ElevenLabsWebSocketEvent =
  | UserTranscriptEvent
  | AgentResponseEvent
  | AgentResponseCorrectionEvent
  | AudioResponseEvent
  | InterruptionEvent
  | PingEvent
  | AgentChatResponsePartEvent;
```

#### Créer le hook WebSocket

Créez un hook personnalisé pour gérer la connexion WebSocket :

**`app/hooks/useAgentConversation.ts`**

```typescript app/hooks/useAgentConversation.ts
'use client';

import { useCallback, useEffect, useRef, useState } from 'react';
import { useVoiceStream } from 'voice-stream';
import type { ElevenLabsWebSocketEvent } from '../types/websocket';

const sendMessage = (websocket: WebSocket, request: object) => {
  if (websocket.readyState !== WebSocket.OPEN) {
    return;
  }
  websocket.send(JSON.stringify(request));
};

export const useAgentConversation = () => {
  const websocketRef = useRef<WebSocket>(null);
  const [isConnected, setIsConnected] = useState<boolean>(false);

  const { startStreaming, stopStreaming } = useVoiceStream({
    onAudioChunked: (audioData) => {
      if (!websocketRef.current) return;
      sendMessage(websocketRef.current, {
        user_audio_chunk: audioData,
      });
    },
  });

  const startConversation = useCallback(async () => {
    if (isConnected) return;

    const websocket = new WebSocket("wss://api.elevenlabs.io/v1/convai/conversation");

    websocket.onopen = async () => {
      setIsConnected(true);
      sendMessage(websocket, {
        type: "conversation_initiation_client_data",
      });
      await startStreaming();
    };

    websocket.onmessage = async (event) => {
      const data = JSON.parse(event.data) as ElevenLabsWebSocketEvent;

      // Handle ping events to keep connection alive
      if (data.type === "ping") {
        setTimeout(() => {
          sendMessage(websocket, {
            type: "pong",
            event_id: data.ping_event.event_id,
          });
        }, data.ping_event.ping_ms);
      }

      if (data.type === "user_transcript") {
        const { user_transcription_event } = data;
        console.log("User transcript", user_transcription_event.user_transcript);
      }

      if (data.type === "agent_response") {
        const { agent_response_event } = data;
        console.log("Agent response", agent_response_event.agent_response);
      }

      if (data.type === "agent_response_correction") {
        const { agent_response_correction_event } = data;
        console.log("Agent response correction", agent_response_correction_event.corrected_agent_response);
      }

      if (data.type === "interruption") {
        // Handle interruption
      }

      if (data.type === "audio") {
        const { audio_event } = data;
        // Implement your own audio playback system here
        // Note: You'll need to handle audio queuing to prevent overlapping
        // as the WebSocket sends audio events in chunks
      }

      if (data.type === "agent_chat_response_part") {
        const { text_response_part } = data;
        const { type: partType, text, response_id } = text_response_part;
        // Handle the agent's response text as it is generated. Enable
        // agent_chat_response_part in the agent's client_events to receive
        // this during voice conversations.
        console.log("Chat response part:", partType, text, response_id);
      }
    };

    websocketRef.current = websocket;

    websocket.onclose = async () => {
      websocketRef.current = null;
      setIsConnected(false);
      stopStreaming();
    };
  }, [startStreaming, isConnected, stopStreaming]);

  const stopConversation = useCallback(async () => {
    if (!websocketRef.current) return;
    websocketRef.current.close();
  }, []);

  useEffect(() => {
    return () => {
      if (websocketRef.current) {
        websocketRef.current.close();
      }
    };
  }, []);

  return {
    startConversation,
    stopConversation,
    isConnected,
  };
};
```

#### Créer le composant de conversation

Créez un composant qui utilise le hook WebSocket :

**`app/components/Conversation.tsx`**

```typescript app/components/Conversation.tsx
'use client';

import { useCallback } from 'react';
import { useAgentConversation } from '../hooks/useAgentConversation';

export function Conversation() {
  const { startConversation, stopConversation, isConnected } = useAgentConversation();

  const handleStart = useCallback(async () => {
    try {
      await navigator.mediaDevices.getUserMedia({ audio: true });
      await startConversation();
    } catch (error) {
      console.error('Failed to start conversation:', error);
    }
  }, [startConversation]);

  return (
    <div className="flex flex-col items-center gap-4">
      <div className="flex gap-2">
        <button
          onClick={handleStart}
          disabled={isConnected}
          className="px-4 py-2 bg-blue-500 text-white rounded disabled:bg-gray-300"
        >
          Start Conversation
        </button>
        <button
          onClick={stopConversation}
          disabled={!isConnected}
          className="px-4 py-2 bg-red-500 text-white rounded disabled:bg-gray-300"
        >
          Stop Conversation
        </button>
      </div>
      <div className="flex flex-col items-center">
        <p>Status: {isConnected ? 'Connected' : 'Disconnected'}</p>
      </div>
    </div>
  );
}
```

## Prochaines étapes

1. **Lecture audio** : implémentez votre propre système de lecture audio à l’aide de Web Audio API ou d’une bibliothèque. Pensez à gérer la mise en file d’attente audio pour éviter les chevauchements, car le WebSocket envoie les événements audio par segments.
2. **Gestion des erreurs** : ajoutez une logique de nouvelle tentative et des mécanismes de récupération après erreur.
3. **Retours de l’interface** : ajoutez des indicateurs visuels d’activité vocale et de statut de connexion.

## Gestion de la latence

Pour garantir des conversations fluides, mettez en œuvre les stratégies suivantes :

* **Mise en mémoire tampon adaptative :** ajustez la mise en mémoire tampon audio selon les conditions réseau.
* **Tampon de gigue :** implémentez un tampon de gigue afin de lisser les variations des temps d’arrivée des paquets.
* **Surveillance ping-pong :** utilisez les événements ping et pong pour mesurer le temps aller-retour et ajuster les paramètres en conséquence.

## Bonnes pratiques de sécurité

* Renouvelez régulièrement les clés API et utilisez des variables d’environnement pour les stocker.
* Implémentez une limitation du débit pour prévenir les abus.
* Expliquez clairement votre intention lorsque vous demandez aux utilisateurs l’accès au microphone.
* Segmentation optimisée : ajustez la durée des segments audio pour équilibrer latence et efficacité.

## Ressources supplémentaires

* [Documentation ElevenLabs Agents](/docs/fr/eleven-agents/overview)
* [SDK ElevenLabs Agents](/docs/fr/eleven-agents/libraries/python)