Skip to main content

ElevenLabs WebSocket TTS

ElevenLabsWebSocketTTS is an opt-in, low-latency variant of ElevenLabsTTS that streams over the ElevenLabs /v1/text-to-speech/{voice_id}/stream-input WebSocket endpoint instead of the HTTP /stream endpoint. It is a drop-in replacement: same constructor surface, same synthesize(text) async iterator, same telephony factories (for_twilio, for_telnyx).

Why use it

  • Saves ~50 ms HTTP request setup per utterance. No new HTTP request / TLS handshake is built for each turn.
  • Avoids cold-start TLS when calls are bursty (the WebSocket holds a warm connection for the duration of the utterance).
  • Native telephony output formats — μ-law @ 8 kHz for Twilio and PCM @ 16 kHz for Telnyx, no client-side resampling.
When not to use it:
  • You need eleven_v3 / eleven_v3_preview — those models are not supported by the stream-input WebSocket. Use the HTTP ElevenLabsTTS instead.
  • Your traffic is so low that the per-utterance HTTP round trip is irrelevant.

Install

websockets is already a runtime dependency of getpatter, so no extra install is required:

Quickstart

Namespaced import:
In an agent:

Constructor parameters

Telephony factories

ElevenLabsWebSocketTTS.for_twilio(...) and ElevenLabsWebSocketTTS.for_telnyx(...) mirror the HTTP variant. They pre-set output_format and (for Twilio) tune voice_settings for low-bandwidth μ-law:

Carrier auto-detect — set_telephony_carrier

When you don’t know the carrier at construction time, StreamHandler calls set_telephony_carrier(carrier) at call start to advise the provider of the wire format:
When output_format was passed explicitly to the constructor (or via for_twilio / for_telnyx), set_telephony_carrier is a no-op — the user’s choice always wins. Calling with an unknown carrier ("" / "custom") is also a no-op.

Limitations

  • eleven_v3 family is rejected at construction time. The stream-input WebSocket does not support v3 models. Use the HTTP ElevenLabsTTS instead.
  • Per-utterance lifecycle. A new WebSocket is opened and closed per synthesize(text) call, matching HTTP semantics. A pooled WS shared across turns of the same call session is on the roadmap.
  • optimize_streaming_latency is officially deprecated by ElevenLabs and is not exposed.

Errors

ElevenLabsTTSError is raised when:
  • The server emits a JSON error frame.
  • No frame is received within frame_timeout seconds (stalled connection).
  • A binary audio frame exceeds the safety cap (512 KB).
The connection is always closed in finally, and a best-effort close_context message is sent so ElevenLabs stops billing for unconsumed audio.

See also