Speech To Text
ElevenLabsOfficialPublished by ElevenLabs
- Skill
- Tool integration
- Automation and integrations
- MIT
- Medium risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a comprehensive interface for the ElevenLabs Scribe v2 speech-to-text engine. It supports batch processing of audio and video files, as well as low-latency real-time streaming for live applications. The tool includes advanced features such as speaker diarization, word-level timestamps, multi-channel audio processing, and keyterm boosting to improve recognition accuracy for specialized terminology.
What it does
- Transcribes audio and video files into text with high accuracy.
- Supports real-time streaming transcription with ultra-low latency.
- Identifies individual speakers in multi-speaker audio recordings.
- Provides word-level timestamps for precise timing and synchronization.
- Allows keyterm boosting to improve recognition of specific jargon or names.
- Supports automatic language detection across 90+ languages.
When to use it
- When building applications that require live voice-to-text feedback.
- When processing large volumes of meeting recordings or interviews.
- When you need to generate accurate subtitles for video content.
- When working with multi-channel audio where speakers are isolated.
- When you need specialized transcription for medical or clinical audio.
Advantages
- State-of-the-art transcription accuracy across 90+ languages.
- Flexible integration options via Python, JavaScript, or CLI.
- Robust real-time capabilities with configurable commit strategies.
- Advanced features like speaker role detection and speaker library matching.
- Comprehensive support for various audio and video file formats.
Usage examples
- “Transcribe this audio file using the Scribe v2 model.”
- The agent uses the ElevenLabs client to process the file and returns the full text transcription.
- “Identify who is speaking in this meeting recording.”
- The agent processes the audio with diarization enabled, returning a transcript labeled with speaker IDs.
- “Set up a real-time transcription stream for a live microphone.”
- The agent initializes a real-time connection using the VAD commit strategy to provide live text updates.
- “Help the model recognize technical terms like 'ElevenLabs' and 'Scribe'.”
- The agent includes the specified keyterms in the transcription request to improve accuracy for those specific words.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/elevenlabs/speech-to-text/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip speech-to-text.zip -d .agents/skills
Documentation by ElevenLabs
ElevenLabs Speech-to-Text
Transcribe audio to text with Scribe v2 - supports 90+ languages, speaker diarization, and word-level timestamps.
Setup, before writing any code: if
ELEVENLABS_API_KEYisn't set for this project, runnpx -y @elevenlabs/cli@latest onboard initfrom the app's folder first and follow what it prints: it signs the user in and stores a key for the project, so nobody copies one by hand. Otherwise see the Installation Guide. For JavaScript, use@elevenlabs/*packages only.
Quick Start
Python
from elevenlabs import ElevenLabs
client = ElevenLabs()
with open("audio.mp3", "rb") as audio_file:
result = client.speech_to_text.convert(file=audio_file, model_id="scribe_v2")
print(result.text)JavaScript
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { createReadStream } from "fs";
const client = new ElevenLabsClient();
const result = await client.speechToText.convert({
file: createReadStream("audio.mp3"),
modelId: "scribe_v2",
});
console.log(result.text);CLI
elevenlabs speech-to-text convert --file audio.mp3 --model-id scribe_v2Models
| Model ID | Description | Best For |
|---|---|---|
scribe_v2 | State-of-the-art accuracy, 90+ languages | Batch transcription, subtitles, long-form audio |
scribe_v2_medical | Specialized recognition for medical and clinical audio, 90+ languages | Clinical documentation, medical dictation, patient calls |
scribe_v2_realtime | Low latency (~150ms) | Live transcription, voice agents |
scribe_v2_realtime_turbo | Realtime transcription variant | Live transcription |
scribe_v2_realtime_lite | Realtime transcription variant | Live transcription |
Transcription with Timestamps
Word-level timestamps include type classification and speaker identification:
result = client.speech_to_text.convert(
file=audio_file, model_id="scribe_v2", timestamps_granularity="word"
)
for word in result.words:
print(f"{word.text}: {word.start}s - {word.end}s (type: {word.type})")
Speaker Diarization
Identify WHO said WHAT - the model labels each word with a speaker ID, useful for meetings, interviews, or any multi-speaker audio:
result = client.speech_to_text.convert(
file=audio_file,
model_id="scribe_v2",
diarize=True
)
for word in result.words:
print(f"[{word.speaker_id}] {word.text}")For call recordings, the batch API can label diarized speakers as agent and customer by setting detect_speaker_roles=true alongside diarize=true. This option is not compatible with use_multi_channel=true.
If your workspace has registered speaker profiles, set use_speaker_library=true with diarize=true to match detected speakers against the speaker library.
elevenlabs speech-to-text convert \
--file call.mp3 \
--model-id scribe_v2 \
--diarize true \
--detect-speaker-roles true \
--use-speaker-library trueMultichannel Audio
Use use_multi_channel=true when each speaker is isolated on a separate audio channel. By default, the API returns one transcript per channel under transcripts; set multichannel_output_style="combined" to receive one transcript merged by timestamp, with channel_index on each word.
result = client.speech_to_text.convert(
file=audio_file,
model_id="scribe_v2",
use_multi_channel=True,
multichannel_output_style="combined",
)Keyterm Prompting
Help the model recognize specific words it might otherwise mishear - product names, technical jargon, or unusual spellings (up to 100 terms):
result = client.speech_to_text.convert(
file=audio_file,
model_id="scribe_v2",
keyterms=["ElevenLabs", "Scribe", "API"]
)Language Detection
Automatic detection with optional language hint:
result = client.speech_to_text.convert(
file=audio_file,
model_id="scribe_v2",
language_code="eng" # ISO 639-1 or ISO 639-3 code
)
print(f"Detected: {result.language_code} ({result.language_probability:.0%})")Supported Formats
Audio: MP3, WAV, M4A, FLAC, OGG, WebM, AAC, AIFF, Opus Video: MP4, AVI, MKV, MOV, WMV, FLV, WebM, MPEG, 3GPP
Limits: Up to 5.0GB file size, 10 hours duration
Response Format
{
"text": "The full transcription text",
"language_code": "eng",
"language_probability": 0.98,
"words": [
{"text": "The", "start": 0.0, "end": 0.15, "type": "word", "speaker_id": "speaker_0"},
{"text": " ", "start": 0.15, "end": 0.16, "type": "spacing", "speaker_id": "speaker_0"}
]
}Word types:
word- An actual spoken wordspacing- Whitespace between words (useful for precise timing)audio_event- Non-speech sounds the model detected (laughter, applause, music, etc.)
Error Handling
try:
result = client.speech_to_text.convert(file=audio_file, model_id="scribe_v2")
except Exception as e:
print(f"Transcription failed: {e}")Common errors:
401: Invalid API key
422: Invalid parameters
429: Rate limit exceeded
Tracking Costs
Monitor usage via request-id response header:
response = client.speech_to_text.with_raw_response.convert(file=audio_file, model_id="scribe_v2")
result = response.data
print(f"Request ID: {response.headers.get('request-id')}")Real-Time Streaming
For live transcription with ultra-low latency (~150ms), use the real-time API. The real-time API produces two types of transcripts:
Partial transcripts: Interim results that update frequently as audio is processed - use these for live feedback (e.g., showing text as the user speaks)
Committed transcripts: Final, stable results after you "commit" - use these as the source of truth for your application
A "commit" tells the model to finalize the current segment. You can commit manually (e.g., when the user pauses) or use Voice Activity Detection (VAD) to auto-commit on silence.
Python (Server-Side)
import asyncio
from elevenlabs import CommitStrategy, ElevenLabs, RealtimeEvents, RealtimeUrlOptions
client = ElevenLabs()
async def transcribe_realtime():
done = asyncio.Event()
connection = await client.speech_to_text.realtime.connect(RealtimeUrlOptions(
model_id="scribe_v2_realtime",
url="https://npr-ice.streamguys1.com/live.mp3",
commit_strategy=CommitStrategy.VAD, # URL streams never commit on their own
include_timestamps=True,
keyterms=["ElevenLabs", "Scribe"],
no_verbatim=True,
))
def on_error(error):
print(f"Error: {error}")
done.set()
connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, lambda data: print(f"Partial: {data.get('text', '')}"))
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, lambda data: print(f"Final: {data.get('text', '')}"))
connection.on(RealtimeEvents.ERROR, on_error)
connection.on(RealtimeEvents.CLOSE, done.set)
try:
await done.wait()
finally:
await connection.close()
asyncio.run(transcribe_realtime())JavaScript (Client-Side with React)
import { useScribe, CommitStrategy } from "@elevenlabs/react";
function TranscriptionComponent() {
const [transcript, setTranscript] = useState("");
const scribe = useScribe({
modelId: "scribe_v2_realtime",
commitStrategy: CommitStrategy.VAD, // Auto-commit on silence for mic input
keyterms: ["ElevenLabs", "Scribe"],
noVerbatim: true,
includeLanguageDetection: true,
onPartialTranscript: (data) => console.log("Partial:", data.text),
onCommittedTranscript: (data) => setTranscript((prev) => prev + data.text),
});
const start = async () => {
// Get token from your backend (never expose API key to client)
const { token } = await fetch("/scribe-token").then((r) => r.json());
await scribe.connect({
token,
microphone: { echoCancellation: true, noiseSuppression: true },
});
};
return <button onClick={start}>Start Recording</button>;
}Commit Strategies
| Strategy | Description |
|---|---|
| Manual | You call commit() when ready - use for file processing or when you control the audio segments |
| VAD | Voice Activity Detection auto-commits when silence is detected - use for live microphone input |
Set includeLanguageDetection: true to receive the detected language code in delayed final
transcript events.
// React: set commitStrategy on the hook (recommended for mic input)
import { useScribe, CommitStrategy } from "@elevenlabs/react";
const scribe = useScribe({
modelId: "scribe_v2_realtime",
commitStrategy: CommitStrategy.VAD,
keyterms: ["ElevenLabs", "Scribe"],
noVerbatim: true,
// Optional VAD tuning:
vadSilenceThresholdSecs: 1.5,
vadThreshold: 0.4,
});// JavaScript client: pass vad config on connect
const connection = await client.speechToText.realtime.connect({
modelId: "scribe_v2_realtime",
keyterms: ["ElevenLabs", "Scribe"],
noVerbatim: true,
vad: {
silenceThresholdSecs: 1.5,
threshold: 0.4,
},
});Event Types
| Event | Description |
|---|---|
partial_transcript | Live interim results |
final_transcript | Stable segment result sent before the segment is committed |
final_transcript_with_timestamps | Delayed final result with timestamps and/or detected language |
committed_transcript | Final results after commit |
committed_transcript_with_timestamps | Final with word timing |
committed_transcript_entities | Entities detected in a committed segment |
edited_transcript | Original and edited text for a committed segment when transcript editing is enabled |
invalid_request | Connection parameters were rejected and the session closes |
error | Error occurred |
See real-time references for complete documentation.
References
Files
- ATTRIBUTION.mdAdded by AutoGineer812 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md10.6 KiB
- references/installation.md2.9 KiB
- references/realtime-client-side.md7.3 KiB
- references/realtime-commit-strategies.md4.6 KiB
- references/realtime-events.md9.0 KiB
- references/realtime-server-side.md11.5 KiB
- references/transcription-options.md10.7 KiB
references/transcription-options.md
Transcription Options
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
file | file | Yes | Audio or video file to transcribe |
model_id | string | Yes | scribe_v2 for general batch transcription or scribe_v2_medical for medical and clinical audio |
token | string | No | Single-use authentication token from POST /v1/single-use-token/batch_scribe. Alternative to API key or bearer authentication for frontend clients; expires after 15 minutes and is consumed on use. |
language_code | string | No | Language hint (ISO 639-1 or ISO 639-3, e.g., en or eng) |
transcript_edit | string | No | Natural-language instruction applied to the final transcript (maximum 2,000 characters). Cannot be combined with entity_detection, entity_redaction, or use_multi_channel. Adds a 30% surcharge, billed for at least 10 seconds of audio. |
timestamps_granularity | string | No | none, word, or character (default: word) |
diarize | boolean | No | Enable speaker diarization (default: false; up to 32 speakers) |
use_speaker_library | boolean | No | Match diarized speakers against registered speaker profiles in the workspace speaker library. Requires diarize=true |
detect_speaker_roles | boolean | No | Label diarized speakers as agent and customer instead of speaker_0, speaker_1, etc. Requires diarize=true and cannot be used with use_multi_channel=true |
num_speakers | integer | No | Maximum speakers to detect (up to 32 for batch) |
diarization_threshold | number | No | Tune diarization sensitivity (default: ~0.22; only when diarize=true and num_speakers is not set) |
keyterms | array | No | Terms to bias transcription (up to 100 terms; each ≤50 chars, ≤5 words) |
tag_audio_events | boolean | No | Detect non-speech sounds like laughter, applause (default: true) |
entity_detection | string or array | No | Detect entities (e.g., pii, phi, pci, offensive_language) |
no_verbatim | boolean | No | If true, removes filler words, false starts, and non-speech sounds (supported with scribe_v2) |
use_multi_channel | boolean | No | Split multichannel audio into separate transcripts (default: false; max 5 channels, max 1 hour) |
multichannel_output_style | string | No | separate (default) returns one transcript per channel under transcripts; combined returns one merged transcript sorted by word start time with channel_index on each word. Requires timestamps and is only used with use_multi_channel=true |
cloud_storage_url | string | No | HTTPS URL to transcribe instead of uploading a file (max 2GB) |
source_url | string | No | URL of an audio or video file to transcribe, including hosted media, YouTube, TikTok, and other video services |
webhook | boolean | No | Process async and send result to webhook (default: false) |
webhook_id | string | No | Target specific webhook (only when webhook=true) |
webhook_metadata | string or object | No | Custom metadata included in webhook responses (max 16KB) |
temperature | double | No | Output randomness (0.0-2.0); defaults vary by model |
seed | integer | No | Deterministic output (0-2147483647); same seed = same result |
additional_formats | array | No | Export transcript as docx, html, pdf, srt, txt, or segmented_json |
file_format | string | No | pcm_s16le_16 (for lower latency) or other (default) |
enable_logging | boolean | No | Set false for zero retention mode (enterprise only; default: true) |
Single-Use Token Authentication
Generate a batch Scribe token on a trusted backend, then pass it as the token query parameter
from the frontend. Do not expose the API key to the client.
TOKEN=$(elevenlabs tokens single-use create --token-type batch_scribe --query token --format raw)
elevenlabs speech-to-text convert \
--file audio.mp3 \
--model-id scribe_v2 \
--token "$TOKEN"Python Example
from elevenlabs import ElevenLabs
client = ElevenLabs()
with open("audio.mp3", "rb") as audio_file:
result = client.speech_to_text.convert(
file=audio_file,
model_id="scribe_v2",
language_code="eng",
timestamps_granularity="word",
diarize=True,
keyterms=["ElevenLabs", "Scribe"]
)JavaScript Example
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { createReadStream } from "fs";
const client = new ElevenLabsClient();
const result = await client.speechToText.convert({
file: createReadStream("audio.mp3"),
modelId: "scribe_v2",
languageCode: "eng",
timestampsGranularity: "word",
diarize: true,
keyterms: ["ElevenLabs", "Scribe"],
});CLI Example
elevenlabs speech-to-text convert \
--file audio.mp3 \
--model-id scribe_v2 \
--language-code eng \
--timestamps-granularity word \
--diarize trueAgent and Customer Role Detection
Use detect_speaker_roles with diarization when you want speaker labels tailored for contact center recordings:
Python
result = client.speech_to_text.convert(
file=audio_file,
model_id="scribe_v2",
diarize=True,
detect_speaker_roles=True
)
for word in result.words:
print(f"[{word.speaker_id}] {word.text}")JavaScript
const result = await client.speechToText.convert({
file: createReadStream("call.mp3"),
modelId: "scribe_v2",
diarize: true,
detectSpeakerRoles: true,
});
for (const word of result.words ?? []) {
console.log(`[${word.speakerId}] ${word.text}`);
}CLI
elevenlabs speech-to-text convert \
--file call.mp3 \
--model-id scribe_v2 \
--diarize true \
--detect-speaker-roles true \
--use-speaker-library trueCloud Storage URL
If your media is already stored remotely and accessible over HTTPS, use cloud_storage_url
instead of uploading a local file:
result = client.speech_to_text.convert(
cloud_storage_url="https://storage.example.com/audio.mp3?signature=abc123",
model_id="scribe_v2"
)Transcribing from a URL
Use source_url when the media is already hosted online and you do not want to upload a file directly.
Python
result = client.speech_to_text.convert(
model_id="scribe_v2",
source_url="https://example.com/interview.mp4",
)JavaScript
const result = await client.speechToText.convert({
modelId: "scribe_v2",
sourceUrl: "https://example.com/interview.mp4",
});CLI
elevenlabs speech-to-text convert \
--model-id scribe_v2 \
--source-url "https://www.youtube.com/watch?v=dQw4w9WgXcQ"Response Structure
{
"text": "The complete transcribed text from the audio file.",
"language_code": "eng",
"language_probability": 0.98,
"audio_duration_secs": 12.4,
"words": [
{
"text": "The",
"start": 0.0,
"end": 0.15,
"type": "word",
"speaker_id": "speaker_0"
},
{
"text": " ",
"start": 0.15,
"end": 0.16,
"type": "spacing",
"speaker_id": "speaker_0"
}
]
}Response Fields
| Field | Type | Description |
|---|---|---|
text | string | Full transcription text |
language_code | string | Detected language (ISO 639-1 or ISO 639-3) |
language_probability | float | Confidence in detection (0-1) |
audio_duration_secs | float | Duration of the transcribed audio in seconds |
words | array | Word-level timestamps (if requested) |
words[].text | string | The transcribed word or spacing |
words[].start | float | Start time in seconds |
words[].end | float | End time in seconds |
words[].type | string | word, spacing, or audio_event |
words[].speaker_id | string | Speaker identifier (if diarization enabled) |
words[].channel_index | integer or null | Channel index for multichannel audio; null for single-channel transcriptions |
transcription_id | string | Unique identifier for this transcription |
additional_formats | array | Exported transcript formats (if requested) |
entities | array | Detected entities with text, type, and character offsets (if entity_detection enabled) |
edited_transcript | object or null | Transcript edit result when transcript_edit is set. A successful result has kind: "transcript" and text; a failed edit has kind: "error", error_type: "edit_failed", and message. |
Supported Languages (90+)
Common languages (ISO 639-3 codes):
| Code | Language | Code | Language |
|---|---|---|---|
eng | English | jpn | Japanese |
spa | Spanish | kor | Korean |
fra | French | zho | Mandarin |
deu | German | ara | Arabic |
ita | Italian | hin | Hindi |
por | Portuguese | tur | Turkish |
nld | Dutch | swe | Swedish |
pol | Polish | dan | Danish |
rus | Russian | fin | Finnish |
Full list: Afrikaans, Amharic, Armenian, Azerbaijani, Belarusian, Bengali, Bosnian, Bulgarian, Burmese, Cantonese, Catalan, Cebuano, Croatian, Czech, Estonian, Filipino, Georgian, Greek, Gujarati, Hausa, Hebrew, Hungarian, Icelandic, Indonesian, Irish, Javanese, Kannada, Kazakh, Khmer, Kyrgyz, Lao, Latvian, Lithuanian, Luxembourgish, Macedonian, Malay, Malayalam, Maltese, Māori, Marathi, Mongolian, Nepali, Norwegian, Odia, Pashto, Persian, Punjabi, Romanian, Serbian, Shona, Sindhi, Slovak, Slovenian, Somali, Swahili, Tamil, Tajik, Telugu, Thai, Ukrainian, Urdu, Uzbek, Vietnamese, Welsh, Wolof, Xhosa, Yoruba, Zulu.
Format Requirements
Audio: MP3, WAV, M4A, FLAC, OGG, WebM, AAC, AIFF, Opus Video: MP4, AVI, MKV, MOV, WMV, FLV, WebM, MPEG, 3GPP
Limits:
Maximum file size: 5.0GB (file upload) or 2GB (cloud storage URL)
Maximum duration: 10 hours (standard) or 1 hour (multichannel mode)
Use Cases
Subtitle Generation with Speakers
result = client.speech_to_text.convert(
file=audio_file,
model_id="scribe_v2",
timestamps_granularity="word",
diarize=True
)
# Generate SRT with speaker labels
for i, word in enumerate(result.words, 1):
if word.type == "word":
print(f"[{word.speaker_id}] {word.text} ({word.start:.2f}s)")Meeting Transcription with Custom Terms
with open("meeting.mp3", "rb") as f:
result = client.speech_to_text.convert(
file=f,
model_id="scribe_v2",
diarize=True,
keyterms=["Q4 forecast", "revenue target", "ACME Corp"]
)
# Group by speaker
current_speaker = None
for word in result.words:
if word.type == "word":
if word.speaker_id != current_speaker:
current_speaker = word.speaker_id
print(f"\n[{current_speaker}]:", end=" ")
print(word.text, end="")Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an API key, Needs Python, Needs Node.js
The author says: Requires internet access and an ElevenLabs API key (ELEVENLABS_API_KEY).
Security
What our scanner noticed· Medium risk
- Instructions that use the network
- Downloads piped into a shell
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- ElevenLabs
- Publisher
- ElevenLabs (Official)
- Source
- elevenlabs/skills · speech-to-text · commit 9763c39
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by ElevenLabs.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download speech-to-text.zip