ElevenLabs SDK — Field Guide
REV 2026-08-03PAGES 10STATUS CURRENT

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 elevenlabs

Node

npm install @elevenlabs/elevenlabs-js

Client types

Python

from elevenlabs.client import ElevenLabs
from elevenlabs.client import AsyncElevenLabs

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

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.

References