Subchapter 7.5
references/realtime-server-side.mdMarkdown10 KBView on GitHub
Transcribe audio streams in real-time from your server with ultra-low latency.
# Python
pip install --upgrade elevenlabs python-dotenv pydub
# JavaScript
npm install @elevenlabs/elevenlabs-js@latest dotenvWarning: Do not use
npm install elevenlabs- that’s an outdated v1.x package. Always use@elevenlabs/elevenlabs-js.
Store your API key in a .env file:
ELEVENLABS_API_KEY=<your_api_key_here>| Purpose | Python / WebSocket | JavaScript |
|---|---|---|
| Limit language detection to expected additional languages | secondary_languages | secondaryLanguages |
| Return detected language in delayed final events | include_language_detection | includeLanguageDetection |
| Detect entities in committed segments | entity_detection | entityDetection |
| Reduce false activation from background speech and noise | filter_background_audio | filterBackgroundAudio |
| Disable history and logging for an enterprise zero-retention session | enable_logging=False | enableLogging: false |
secondary_languages accepts additional ISO-639-1 or ISO-639-3 codes. Entity detection accepts
all, a supported entity type or category, or a list of them. Background audio filtering cannot be
combined with timestamp output.
from dotenv import load_dotenv
import os
import asyncio
from elevenlabs import ElevenLabs
from elevenlabs import RealtimeEvents, RealtimeUrlOptions
load_dotenv()
async def main():
elevenlabs = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
stop_event = asyncio.Event()
connection = await elevenlabs.speech_to_text.realtime.connect(RealtimeUrlOptions(
model_id="scribe_v2_realtime",
url="https://npr-ice.streamguys1.com/live.mp3",
include_timestamps=True,
keyterms=["ElevenLabs", "Scribe"],
no_verbatim=True,
))
def on_partial_transcript(data):
print(f"Partial: {data.get('text', '')}")
def on_committed_transcript(data):
print(f"Committed: {data.get('text', '')}")
def on_error(error):
print(f"Error: {error}")
stop_event.set()
def on_close():
print("Connection closed")
connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, on_partial_transcript)
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, on_committed_transcript)
connection.on(RealtimeEvents.ERROR, on_error)
connection.on(RealtimeEvents.CLOSE, on_close)
try:
await stop_event.wait()
except KeyboardInterrupt:
print("\nStopping transcription...")
finally:
await connection.close()
if __name__ == "__main__":
asyncio.run(main())import "dotenv/config";
import { ElevenLabsClient, RealtimeEvents } from "@elevenlabs/elevenlabs-js";
const elevenlabs = new ElevenLabsClient();
const connection = await elevenlabs.speechToText.realtime.connect({
modelId: "scribe_v2_realtime",
url: "https://npr-ice.streamguys1.com/live.mp3",
includeTimestamps: true,
keyterms: ["ElevenLabs", "Scribe"],
noVerbatim: true,
});
connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, (transcript) => {
console.log("Partial transcript", transcript);
});
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (transcript) => {
console.log("Committed transcript", transcript);
});
connection.on(RealtimeEvents.ERROR, (error) => {
console.log("Error", error);
});
connection.on(RealtimeEvents.CLOSE, () => {
console.log("Connection closed");
});For local files or custom audio streams, convert to PCM format and send in chunks.
import asyncio
import base64
import os
from dotenv import load_dotenv
from pathlib import Path
from elevenlabs import ElevenLabs
from elevenlabs import AudioFormat, CommitStrategy, RealtimeEvents, RealtimeAudioOptions
from pydub import AudioSegment
load_dotenv()
def load_and_convert_audio(audio_path: str | Path, target_sample_rate: int = 16000
import "dotenv/config";
import * as fs from "node:fs";
import { ElevenLabsClient, RealtimeEvents, AudioFormat } from "@elevenlabs/elevenlabs-js";
const elevenlabs = new ElevenLabsClient();
const connection = await elevenlabs.speechToText.realtime.connect({
modelId: "scribe_v2_realtime",
audioFormat: AudioFormat.PCM_16000,
sampleRate: 16000,
includeTimestamps: true,
});
connection.on(RealtimeEvents.SESSION_STARTED, (data) => {
console.log("Session started", data);
sendAudio();
});
connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, (transcript) => {
console.log("Partial transcript", transcript);
});
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (transcript) => {
console.log("Committed transcript", transcript);
});
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT_WITH_TIMESTAMPS, (transcript) => {
console.log("Committed with timestamps", transcript);
});
connection.on(RealtimeEvents.ERROR, (error) => {
console.log("Error", error);
});
connection.on(RealtimeEvents.CLOSE, () => {
console.log("Connection closed");
});
async function sendAudio() {
const pcmFilePath = "audio.pcm";
const chunkSize = 32000;
const audioBuffer = fs.readFileSync(pcmFilePath);
const chunks: Buffer[] = [];
for (let i = 0; i < audioBuffer.length; i += chunkSize) {
const chunk = audioBuffer.subarray(i, i + chunkSize);
chunks.push(chunk);
}
for (let i = 0; i < chunks.length; i++) {
const chunk = chunks[i];
const chunkBase64 = chunk.toString("base64");
connection.send({
audioBase64: chunkBase64,
sampleRate: 16000,
});
if (i < chunks.length - 1) {
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
await new Promise((resolve) => setTimeout(resolve, 500));
connection.commit();
}For cases where the SDK cannot be used:
wss://api.elevenlabs.io/v1/speech-to-text/realtime?model_id=scribe_v2_realtimeAdd repeated keyterms query parameters to bias recognition toward specific terms, and set
no_verbatim=true to remove filler words, false starts, and disfluencies. Add repeated
secondary_languages parameters with ISO-639-1 or ISO-639-3 codes when the audio may contain
additional languages:
wss://api.elevenlabs.io/v1/speech-to-text/realtime?model_id=scribe_v2_realtime&keyterms=ElevenLabs&keyterms=Scribe&secondary_languages=es&secondary_languages=fr&no_verbatim=trueAdd entity_detection to detect entities in committed segments. It accepts all, one entity type
or category, or a comma-separated list. Categories include pii, phi, pci, other, and
offensive_language:
wss://api.elevenlabs.io/v1/speech-to-text/realtime?model_id=scribe_v2_realtime&entity_detection=pii,pciEach committed segment is followed by a committed_transcript_entities event containing the
detected entity text, type, and character offsets. See the
entity detection guide (opens in a new tab)
for specific entity types.
{
"message_type": "input_audio_chunk",
"audio_base_64": "<base64-encoded-audio>",
"commit": false,
"sample_rate": 16000
}{
"message_type": "commit"
}| Parameter | Value |
|---|---|
| Format | PCM 16-bit |
| Sample Rate | 16000 Hz (recommended) |
| Channels | Mono |
| Chunk Size | 32,000 bytes = 1 second |
Supported sample rates: 8kHz to 48kHz