本页还没有译文
本页 88 段还没译成Deutsch,下面显示的是英文原文。ElevenLabs
还没翻译译自英文(tanstack.com)本页 88 段都还没译
The ElevenLabs adapter is voice-focused. It exposes five capabilities:
- Realtime voice agents (
elevenlabsRealtime/elevenlabsRealtimeToken) — full-duplex voice-to-voice conversations powered by ElevenLabs Conversational AI agents. - Text-to-speech (
elevenlabsSpeech) — one-shot speech generation viagenerateSpeech(). - Music & sound effects (
elevenlabsAudio) — one-shot audio generation viagenerateAudio(). - Transcription (
elevenlabsTranscription) — speech-to-text viagenerateTranscription(). - Voice design (
elevenlabsVoiceDesign): create a new voice viagenerateVoice().
It does not support text chat() or summarize() — use OpenAI, Anthropic, or Gemini for those.
The realtime adapter uses an agent-based architecture where you configure your conversational AI agent in the ElevenLabs dashboard (voice, personality, knowledge base, tools) and then connect to it at runtime. The adapter wraps the @elevenlabs/client SDK for seamless integration with useRealtimeChat and RealtimeClient.
Installation
npm i @tanstack/ai-elevenlabspnpm add @tanstack/ai-elevenlabsyarn add @tanstack/ai-elevenlabsbun add @tanstack/ai-elevenlabsPeer dependencies:
npm i @tanstack/ai @tanstack/ai-clientpnpm add @tanstack/ai @tanstack/ai-clientyarn add @tanstack/ai @tanstack/ai-clientbun add @tanstack/ai @tanstack/ai-clientServer Setup
The server generates a signed WebSocket URL so your API key never reaches the client. The signed URL is valid for 30 minutes.
import { realtimeToken } from '@tanstack/ai'
import { elevenlabsRealtimeToken } from '@tanstack/ai-elevenlabs'
// In your API route (Express, Hono, TanStack Start, etc.)
export async function POST() {
const token = await realtimeToken({
adapter: elevenlabsRealtimeToken({
agentId: process.env.ELEVENLABS_AGENT_ID!,
}),
})
return Response.json(token)
}With Overrides
You can override agent settings at token generation time without changing your dashboard configuration:
const token = await realtimeToken({
adapter: elevenlabsRealtimeToken({
agentId: process.env.ELEVENLABS_AGENT_ID!,
overrides: {
voiceId: 'custom-voice-id',
systemPrompt: 'You are a helpful voice assistant.',
firstMessage: 'Hello! How can I help you today?',
language: 'en',
},
}),
})Client Setup
React (useRealtimeChat)
import { useRealtimeChat } from '@tanstack/ai-react'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
function VoiceChat() {
const {
status,
mode,
messages,
connect,
disconnect,
pendingUserTranscript,
pendingAssistantTranscript,
inputLevel,
outputLevel,
} = useRealtimeChat({
getToken: () =>
fetch('/api/realtime-token', { method: 'POST' }).then((r) => r.json()),
adapter: elevenlabsRealtime(),
})
return (
<div>
<p>Status: {status}</p>
<p>Mode: {mode}</p>
<button onClick={status === 'idle' ? connect : disconnect}>
{status === 'idle' ? 'Start Conversation' : 'End Conversation'}
</button>
{pendingUserTranscript && <p>You: {pendingUserTranscript}...</p>}
{pendingAssistantTranscript && (
<p>AI: {pendingAssistantTranscript}...</p>
)}
{messages.map((msg) => (
<div key={msg.id}>
<strong>{msg.role}:</strong>
{msg.parts.map((part, i) => (
<span key={i}>
{part.type === 'text' ? part.content : null}
{part.type === 'audio' ? part.transcript : null}
</span>
))}
</div>
))}
</div>
)
}Non-React (RealtimeClient)
import { RealtimeClient } from '@tanstack/ai-client'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
const client = new RealtimeClient({
getToken: () =>
fetch('/api/realtime-token', { method: 'POST' }).then((r) => r.json()),
adapter: elevenlabsRealtime(),
onMessage: (message) => {
console.log(`${message.role}:`, message.parts)
},
onStatusChange: (status) => {
console.log('Status:', status)
},
onModeChange: (mode) => {
console.log('Mode:', mode)
},
})
await client.connect()Client Tools
ElevenLabs supports client-side tools that execute in the browser. Define tools using the standard toolDefinition() API:
import { toolDefinition } from '@tanstack/ai'
import { useRealtimeChat } from '@tanstack/ai-react'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
import { z } from 'zod'
const getWeatherDef = toolDefinition({
name: 'getWeather',
description: 'Get weather for a location',
inputSchema: z.object({
location: z.string(),
}),
outputSchema: z.object({
temperature: z.number(),
conditions: z.string(),
}),
})
const getWeather = getWeatherDef.client(async ({ location }) => {
const res = await fetch(`/api/weather?location=${location}`)
return res.json()
})
// Pass tools to the hook
const chat = useRealtimeChat({
getToken: () =>
fetch('/api/realtime-token', { method: 'POST' }).then((r) => r.json()),
adapter: elevenlabsRealtime(),
tools: [getWeather],
})Tool results are automatically serialized to strings and returned to the ElevenLabs agent. The adapter converts TanStack tool definitions into the @elevenlabs/client clientTools format internally.
Configuration
elevenlabsRealtimeToken Options
Used on the server to generate a signed WebSocket URL.
| Option | Type | Required | Description |
|---|---|---|---|
agentId | string | No* | Agent ID configured in the ElevenLabs dashboard. *Falls back to ELEVENLABS_AGENT_ID; required only if that env var is unset |
overrides.voiceId | string | No | Custom voice ID to override the agent's default voice |
overrides.systemPrompt | string | No | Custom system prompt to override the agent's default |
overrides.firstMessage | string | No | First message the agent speaks when the session starts |
overrides.language | string | No | Language code (e.g., 'en', 'es', 'fr') |
elevenlabsRealtime Options
Used on the client to establish the connection.
| Option | Type | Default | Description |
|---|---|---|---|
connectionMode | 'websocket' | 'webrtc' | auto-detect | Transport protocol for the connection |
debug | boolean | DebugConfig | false | Enable debug logging — pass true for all categories, or a DebugConfig to select categories/sink |
Differences from OpenAI Realtime
ElevenLabs and OpenAI take different approaches to realtime voice:
| ElevenLabs | OpenAI | |
|---|---|---|
| Configuration | Agent-based. Configure voice, personality, and knowledge in the ElevenLabs dashboard or via overrides at token time. | Session-based. Configure instructions, voice, temperature, etc. per session via useRealtimeChat options. |
| Token type | Signed WebSocket URL (valid 30 minutes) | Ephemeral API token (valid ~10 minutes) |
| Transport | WebSocket (default) or WebRTC | WebRTC |
| Audio handling | @elevenlabs/client SDK manages audio capture and playback automatically | TanStack AI manages WebRTC peer connection and audio tracks |
| VAD | Handled by ElevenLabs server-side | Supports server, semantic, and manual modes |
| Runtime updates | Session config is set at creation time and cannot be changed mid-session | Supports updateSession() for mid-session config changes |
| Image input | Not supported | Supported via sendImage() |
| Time domain data | Not available from the SDK | Available for waveform visualizations |
Audio Visualization
The ElevenLabs adapter provides audio visualization data through the same interface as other realtime adapters:
import { useRealtimeChat } from '@tanstack/ai-react'
import { elevenlabsRealtime } from '@tanstack/ai-elevenlabs'
const {
inputLevel, // 0-1 normalized microphone volume
outputLevel, // 0-1 normalized speaker volume
getInputFrequencyData, // Uint8Array frequency spectrum
getOutputFrequencyData,
} = useRealtimeChat({
getToken: () =>
fetch('/api/realtime-token', { method: 'POST' }).then((r) => r.json()),
adapter: elevenlabsRealtime(),
})Note: ElevenLabs provides volume levels and frequency data but does not expose time-domain data. The getInputTimeDomainData() and getOutputTimeDomainData() methods return static placeholder arrays. The default audio sample rate is 16kHz.
Environment Variables
Set these in your server environment:
ELEVENLABS_API_KEY=your-elevenlabs-api-key
ELEVENLABS_AGENT_ID=your-agent-id| Variable | Required | Description |
|---|---|---|
ELEVENLABS_API_KEY | Yes | Your ElevenLabs API key, used server-side for generating signed URLs |
ELEVENLABS_AGENT_ID | No | Default agent ID. Can also be passed directly to elevenlabsRealtimeToken() |
Get your API key from the ElevenLabs dashboard. Create and configure agents in the Conversational AI section of the dashboard.
Text-to-Speech
For one-shot speech generation (not realtime), use elevenlabsSpeech with generateSpeech():
The format option supports mp3 (default), pcm, opus, and wav. WAV output contains 44.1 kHz, 16-bit mono PCM with a RIFF header. Requests for aac or flac throw before the API call. An explicit modelOptions.outputFormat overrides format and returns the selected provider format without WAV wrapping.
import { generateSpeech } from "@tanstack/ai";
import { elevenlabsSpeech } from "@tanstack/ai-elevenlabs";
const result = await generateSpeech({
adapter: elevenlabsSpeech("eleven_v4"),
text: "Hello from ElevenLabs!",
voice: "Rachel",
format: "mp3",
});
console.log(result.audio); // Base64-encoded audioDialogue and timings
ElevenLabs has a separate dialogue endpoint that takes up to 10 distinct
voices, and a timestamped twin of each endpoint. turns and timestamps
pick between them, so you never choose an endpoint by hand:
import { generateSpeech } from "@tanstack/ai";
import { elevenlabsSpeech } from "@tanstack/ai-elevenlabs";
const result = await generateSpeech({
adapter: elevenlabsSpeech("eleven_v4"),
turns: [
{ text: "Knock knock.", voice: "bYTqZQo3Jz7LQtmGTgwi" },
{ text: "Who is there?", voice: "6lCwbsX1yVjD49QmpkTR" },
],
timestamps: true,
});
// Character timings for the whole clip.
console.log(result.alignment?.unit); // 'character'
// One entry per turn, with the voice that spoke it.
for (const segment of result.segments ?? []) {
console.log(segment.turnIndex, segment.voice, segment.text);
}segments only comes back from the dialogue endpoint. A single-voice request
with timestamps: true returns alignment alone.
Music & Sound Effects
elevenlabsAudio covers both music generation and sound effects depending on the model:
import { generateAudio } from "@tanstack/ai";
import { elevenlabsAudio } from "@tanstack/ai-elevenlabs";
// Music generation
const music = await generateAudio({
adapter: elevenlabsAudio("music_v2_5"),
prompt: "An upbeat synthwave track for a product launch",
});
// Sound effects
const sfx = await generateAudio({
adapter: elevenlabsAudio("eleven_text_to_sound_v2"),
prompt: "A glass shattering on concrete",
});Listing Voices
elevenlabsSpeech can read the account's voice catalog, which includes anything generateVoice() has saved:
import { listVoices } from "@tanstack/ai";
import { elevenlabsSpeech } from "@tanstack/ai-elevenlabs";
const { voices } = await listVoices({
adapter: elevenlabsSpeech("eleven_v4"),
origins: ["generated", "cloned"],
});ElevenLabs has no origin filter on GET /v1/voices, so the adapter fetches the catalog and narrows in memory. Its famous and high_quality categories both read as professional.
Voice Design
elevenlabsVoiceDesign creates a new voice from a description. The voice IDs it returns go straight into generateSpeech():
import { generateVoice } from "@tanstack/ai";
import { elevenlabsVoiceDesign } from "@tanstack/ai-elevenlabs";
const result = await generateVoice({
adapter: elevenlabsVoiceDesign("eleven_ttv_v3"),
prompt: "A warm, gravelly narrator in his sixties with a slight Irish lilt",
name: "Irish Narrator",
});
const [voice] = result.voices;
if (!voice) throw new Error("The provider returned no voices.");
console.log(voice.voiceId);
console.log(voice.saved); // true, because a name was givenWithout a name, you get preview voices to audition. With a name, the best candidate is kept in your ElevenLabs voice library.
eleven_ttv_v3 also accepts referenceAudio, a clip of a real speaker used as a design reference — it still needs a prompt, and modelOptions.promptStrength balances the two. eleven_multilingual_ttv_v2 takes no reference audio. See Voice Creation for the full guide.
Models
| Family | Models |
|---|---|
| Text-to-speech | eleven_v4, eleven_v4_turbo, eleven_v3, eleven_v3_conversational, eleven_multilingual_v2, eleven_flash_v2_5, eleven_flash_v2 |
| Music | music_v2_5, music_v2 |
| Sound effects | eleven_text_to_sound_v2 |
| Transcription | scribe_v2, scribe_v2_medical |
| Voice design | eleven_ttv_v3, eleven_multilingual_ttv_v2 |
ElevenLabs deprecated eleven_turbo_v2, eleven_turbo_v2_5, eleven_monolingual_v1, scribe_v1, and music_v1. The adapter still accepts them, and each is commented as deprecated in model-meta.ts. Move to the current model in the same row.
Transcription
Transcribe audio with elevenlabsTranscription:
import { generateTranscription } from "@tanstack/ai";
import { elevenlabsTranscription } from "@tanstack/ai-elevenlabs";
import { audioFile } from "./audio";
const result = await generateTranscription({
adapter: elevenlabsTranscription("scribe_v2"),
audio: audioFile,
});
console.log(result.text);Behind a proxy
Route every request through a gateway, such as Cloudflare AI Gateway or a corporate proxy, with baseURL and defaultHeaders. These two option names are the same on every TanStack AI adapter, so one gateway config works for all of them.
import { createElevenLabsSpeech } from "@tanstack/ai-elevenlabs";
const adapter = createElevenLabsSpeech("eleven_v4", process.env.ELEVENLABS_API_KEY!, {
baseURL: "https://gateway.example.com/elevenlabs",
defaultHeaders: { "cf-aig-authorization": `Bearer ${process.env.GATEWAY_TOKEN}` },
});This applies to the speech, audio, and transcription adapters. baseUrl and headers are aliases of the same two options. If you set both forms, baseURL and defaultHeaders win.
API Reference
elevenlabsRealtimeToken(options)
Creates an ElevenLabs realtime token adapter for server-side use with realtimeToken().
Parameters:
options.agentId- Agent ID from the ElevenLabs dashboardoptions.overrides?.voiceId- Custom voice IDoptions.overrides?.systemPrompt- Custom system promptoptions.overrides?.firstMessage- First message the agent speaksoptions.overrides?.language- Language code
Returns: A RealtimeTokenAdapter for use with realtimeToken().
elevenlabsRealtime(options?)
Creates an ElevenLabs realtime client adapter for use with useRealtimeChat or RealtimeClient.
Parameters:
options.connectionMode?-'websocket'or'webrtc'(default: auto-detect)options.debug?- Enable debug logging
Returns: A RealtimeAdapter for use with useRealtimeChat() or RealtimeClient.
elevenlabsSpeech(model, config?) / createElevenLabsSpeech(model, apiKey, config?)
Creates an ElevenLabs text-to-speech adapter for use with generateSpeech().
elevenlabsAudio(model, config?) / createElevenLabsAudio(model, apiKey, config?)
Creates an ElevenLabs audio adapter that covers both music generation and sound effects (selected via the model id) for use with generateAudio().
elevenlabsTranscription(model, config?) / createElevenLabsTranscription(model, apiKey, config?)
Creates an ElevenLabs transcription adapter for use with generateTranscription().
elevenlabsVoiceDesign(model, config?) / createElevenLabsVoiceDesign(model, apiKey, config?)
Creates an ElevenLabs voice-design adapter for use with generateVoice().
elevenlabsSpeech(...).listVoices(options?)
Reads the account's voice catalog via GET /v1/voices, for use with listVoices().
Limitations
- No text chat support -- Use OpenAI, Anthropic, Gemini, or another text adapter for
chat(). - No summarization -- Use a text adapter for
summarize(). - No image input (realtime) -- ElevenLabs realtime does not support sending images during a conversation.
- No runtime session updates (realtime) -- Session configuration is fixed at connection time.
- No time-domain audio data (realtime) -- Frequency data and volume levels are available, but waveform data is not.
- Agent required (realtime) -- You must create and configure an agent in the ElevenLabs dashboard before using the realtime adapter.
Next Steps
- Realtime Voice Chat Guide - Complete guide to building realtime voice applications
- OpenAI Adapter - Alternative realtime voice provider with WebRTC
- Tools Guide - Learn about the isomorphic tool system