SEC 04 / CORE SDKS
Core SDKs: Python & Node
The core SDKs — elevenlabs for Python and @elevenlabs/elevenlabs-js for
Node — are largely generated clients for the full ElevenLabs REST API. This
page walks the same operation, streaming text-to-speech, through both
languages side by side, then covers the retry/timeout defaults and the
adapter pattern worth building around either client.
Installation
Python
pip install elevenlabsNode
npm install @elevenlabs/elevenlabs-jsClient types
Python
from elevenlabs.client import ElevenLabs
from elevenlabs.client import AsyncElevenLabsUse the async client inside FastAPI, Starlette, aiohttp, or other asynchronous applications. Calling the synchronous client directly from an event-loop request handler can block the loop unless it is deliberately moved to a worker thread.
Node
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";There’s a single ElevenLabsClient — no separate sync/async split like
Python’s ElevenLabs/AsyncElevenLabs, since Node’s I/O model is
asynchronous by default.
Streaming TTS, same operation, both languages
Python
import os
from pathlib import Path
from elevenlabs.client import ElevenLabs
def generate_speech() -> Path:
api_key = os.environ["ELEVENLABS_API_KEY"]
voice_id = os.environ["ELEVENLABS_VOICE_ID"]
client = ElevenLabs(api_key=api_key)
audio_chunks = client.text_to_speech.stream(
voice_id=voice_id,
text="This audio begins downloading before generation is complete.",
model_id="eleven_flash_v2_5",
output_format="mp3_44100_128",
)
output_path = Path("speech.mp3")
with output_path.open("wb") as output:
for chunk in audio_chunks:
if chunk:
output.write(chunk)
return output_path
if __name__ == "__main__":
print(generate_speech())Node
import { createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
import { Readable } from "node:stream";
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
const apiKey = process.env.ELEVENLABS_API_KEY;
const voiceId = process.env.ELEVENLABS_VOICE_ID;
if (!apiKey || !voiceId) {
throw new Error(
"ELEVENLABS_API_KEY and ELEVENLABS_VOICE_ID must be configured",
);
}
const client = new ElevenLabsClient({ apiKey });
const audio = await client.textToSpeech.stream(voiceId, {
text: "This response is being streamed through the Node SDK.",
modelId: "eleven_flash_v2_5",
outputFormat: "mp3_44100_128",
});
await pipeline(
Readable.from(audio),
createWriteStream("speech.mp3"),
);Both examples write the stream to a file for simplicity; for a web service, forward chunks to the HTTP response rather than accumulating in memory.
Retry & timeout behaviour
The Node SDK documents its defaults explicitly:
- two automatic retries by default;
- exponential backoff;
- retries for HTTP 408, 409, 429, and 5xx responses;
- per-request
maxRetries; - a default timeout of 60 seconds;
- per-request
timeoutInSeconds.
The generated Python client supports per-request options for the same areas — timeouts and retries — but the documentation is less explicit than the Node documentation about universal defaults. Production Python code should therefore set its own timeout and retry policy rather than assuming parity with Node.
Wrap the client in an adapter
Use a small adapter around the generated client instead of spreading its types across the application:
export interface SpeechGenerator {
streamSpeech(input: {
voiceId: string;
text: string;
}): Promise<AsyncIterable<Uint8Array>>;
}
Keep model IDs, output formats, timeout policies, retry logic, and observability inside the adapter. This prevents generated SDK types from spreading across the application.
Going deeper: playback helpers and native dependencies
The Node SDK’s convenience playback helper relies on external MPV and FFmpeg installations. That makes it useful for local scripts but unsuitable as a general cross-runtime production abstraction.
Python’s optional PyAudio functionality can similarly introduce native build and operating-system dependency problems. In servers and containers, it is often cleaner to consume or forward raw audio bytes instead of trying to play audio through either SDK.
The Node package also advertises compatibility with Node.js 15+, Vercel, Cloudflare Workers, Deno, and Bun — but not every helper (including the MPV/FFmpeg-backed playback helper above) is equally portable across those runtimes.