For advanced use cases like multi-speaker conversations or pre-buffering
audio, use the multi-context WebSocket endpoint (/ws/tts/multi). This allows
managing up to 20 independent audio streams over a single connection.
Use cases
- Multi-speaker conversations: Generate audio for different speakers concurrently
- Pre-buffering: Start generating the next response while the current one plays
- Interleaved audio: Dynamically switch between speakers in real-time
Example
Every SDK wraps /ws/tts/multi in a multi-context session. The raw WebSocket
version follows below.
Raw WebSocket
Protocol summary
Each context message carries a context_id; the first message for a new ID
creates the context and can include voice_settings. An empty-text message can
therefore create or keep alive a context, but voice_id must be set no later
than the first non-empty text message. Per context you can send text, flush, and
close_context (with "immediate": true for
barge-in);
{"close_socket": true} ends everything. The server tags every
context-specific response frame (context_created, generation_started,
audio, chunk_complete, word_timestamps, final, context_closed, and
per-context errors) with the originating context_id. The final
session_closed frame is connection-wide and has no context_id; it carries
total_audio_seconds across the connection. After each flush, a final frame
(ElevenLabs is_final equivalent) signals that all audio for the flushed text
has been delivered.
If a context ends without producing any audio for text it accepted, the server
replaces that final with a per-context error frame
(error_code: "INTERNAL_ERROR", code: 500) before context_closed, so a
lost turn is never indistinguishable from a completed one. Treat it as a failed
turn and retry the text on a new context.
The full message tables — every field of every client→server and
server→client frame — live in the
Text-to-Speech API reference.
Usage is billed per context: a synthesized, billable context’s
context_closed frame carries its usage block. A context closed before
synthesis starts has no usage block. See
Per-session usage.
Limits
- Maximum 20 concurrent contexts per connection
- Contexts auto-close after 20 seconds of inactivity
- Send empty text
{"text": "", "context_id": "..."} to reset the
per-context inactivity timeout
- Opening a context beyond the limit returns a per-context error
(
error_code: "TOO_MANY_CONTEXTS", code: 429) without closing the
connection — close an existing context, or wait for an idle one to be
released, then retry.
Last modified on September 22, 2026