Loading...
Loading...
Dub audio and video into other languages using the ElevenLabs Dubbing API (dubbing_v2), preserving the original speakers' voices. Use when translating videos, podcasts, or recordings into other languages, localizing media content, reviewing or correcting dubbing transcripts and translations, or regenerating a dub after edits.
npx skill4agent add elevenlabs/skills dubbingImportant: Use the Dubbing Projects API —in the SDKs, or theelevenlabs.dubbing.project.*REST endpoints. Do not use the legacy v1 dubbing surface (/v1/dubbing/project,client.dubbing.create(),client.dubbing.get(), or bareclient.dubbing.audio.get()routes) — that is the older dubbing API, now under Legacy in the API reference./v1/dubbing
Setup: See Installation Guide. REST base URL iswith your API key in thehttps://api.elevenlabs.ioheader; the SDKs readxi-api-keyautomatically.ELEVENLABS_API_KEY
| Concept | Meaning |
|---|---|
| Project | One source of media (file or URL) plus its source transcript. Prepared (transcribed) once, then rests in |
| Source transcript | Editable segments (text, speaker, timing) transcribed from the source. The single source of truth every language is translated from. |
| Language (target) | One dubbed output language. Each has its own transcript (source segments + a translation per segment) and its own dubbed audio output. |
| Revisions | Independent monotonic counters. The project's |
staleEnterprise: Transcript editing and regeneration are available to enterprise workspaces only. Creating projects, adding languages, and downloading dubs work on all plans.
queuedreadyqueuedprocessingcompletedoutputs.lossless_audiocompletedstalecompletedimport os
import time
import requests
from elevenlabs.client import ElevenLabs
elevenlabs = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
# 1. Create a project from a local file (or pass source_url=... instead of file)
with open("promo.mp4", "rb") as f:
project = elevenlabs.dubbing.project.create(
file=f,
source_language="en",
reference="Q3 marketing video",
)
# 2. Wait for the source media to be transcribed
while True:
project = elevenlabs.dubbing.project.get(project.project_id)
if project.status == "ready":
break
if project.status == "failed":
raise RuntimeError("Project preparation failed")
time.sleep(5)
# 3. Add a Spanish language target
language = elevenlabs.dubbing.project.language.create(
project.project_id,
target_language="es",
)
# 4. Wait for the dub to finish generating
while True:
language = elevenlabs.dubbing.project.language.get(
project.project_id, language.language_id
)
if language.status == "completed":
break
if language.status == "failed":
raise RuntimeError("Dub generation failed")
time.sleep(5)
# 5. Download the dubbed audio (signed URL, valid ~1 hour — re-fetch the language for a fresh one)
audio = requests.get(language.outputs.lossless_audio)
with open("promo_es.wav", "wb") as f:
f.write(audio.content)import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { writeFile } from "fs/promises";
const elevenlabs = new ElevenLabsClient();
// 1. Create a project (sourceUrl shown; file upload is also supported)
let project = await elevenlabs.dubbing.project.create({
sourceUrl: "https://example.com/promo.mp4",
sourceLanguage: "en",
reference: "Q3 marketing video",
});
// 2. Wait for the source media to be transcribed
while (true) {
project = await elevenlabs.dubbing.project.get(project.projectId);
if (project.status === "ready") break;
if (project.status === "failed") throw new Error("Project preparation failed");
await new Promise((resolve) => setTimeout(resolve, 5000));
}
// 3. Add a Spanish language target
let language = await elevenlabs.dubbing.project.language.create(project.projectId, {
targetLanguage: "es",
});
// 4. Wait for the dub to finish generating
while (true) {
language = await elevenlabs.dubbing.project.language.get(project.projectId, language.languageId);
if (language.status === "completed") break;
if (language.status === "failed") throw new Error("Dub generation failed");
await new Promise((resolve) => setTimeout(resolve, 5000));
}
// 5. Download the dubbed audio from the signed URL
const response = await fetch(language.outputs!.losslessAudio!);
await writeFile("promo_es.wav", Buffer.from(await response.arrayBuffer()));# 1. Create a project (use -F "source_url=https://..." instead of file to dub from a URL)
curl -X POST "https://api.elevenlabs.io/v1/dubbing/project" \
-H "xi-api-key: $ELEVENLABS_API_KEY" \
-F "file=@promo.mp4" \
-F "source_language=en"
# → {"project_id": "proj_...", "status": "queued", ...}
# 2. Poll until status is "ready"
curl "https://api.elevenlabs.io/v1/dubbing/project/proj_..." \
-H "xi-api-key: $ELEVENLABS_API_KEY"
# 3. Add a target language
curl -X POST "https://api.elevenlabs.io/v1/dubbing/project/proj_.../language" \
-H "xi-api-key: $ELEVENLABS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"target_language": "es"}'
# 4. Poll the language until "completed", then download outputs.lossless_audio
curl "https://api.elevenlabs.io/v1/dubbing/project/proj_.../language/lang_..." \
-H "xi-api-key: $ELEVENLABS_API_KEY"POST /v1/dubbing/projectmultipart/form-datafilesource_url| Field | Required | Notes |
|---|---|---|
| one of file/source_url | Source media to dub (audio or video), up to 3 GiB |
| one of file/source_url | Public URL to fetch the source media from |
| no | ISO 639 code (e.g. |
| no | Free-form label to identify the project on your end (max 500 chars) |
| no | |
| no | Optionally queue the first language target at creation; add more with |
| no | Terms to bias transcription/translation toward (product/brand names). Up to 100 terms of 200 chars each; repeat the field once per term in multipart |
readyrevisionid# Read the source transcript
transcript = elevenlabs.dubbing.project.transcript.get(project_id)
# Correct a segment's text — send only the fields to change (text, speaker_id, start_s, end_s)
elevenlabs.dubbing.project.transcript.update_segment(
project_id,
segment_id=transcript.segments[0].id,
text="Welcome to our latest product demo.",
)
# Add a segment (reuse an existing speaker_id so it's dubbed with that speaker's voice)
added = elevenlabs.dubbing.project.transcript.create_segment(
project_id,
text="Thanks for watching.",
speaker_id=transcript.segments[0].speaker_id,
start_s=40.0,
end_s=42.0,
)
# Delete a segment
elevenlabs.dubbing.project.transcript.delete_segment(project_id, segment_id=added.segment.id)GET /v1/dubbing/project/{project_id}/transcriptPATCH .../transcript/segment/{segment_id}curl -X PATCH "https://api.elevenlabs.io/v1/dubbing/project/{project_id}/transcript/segment/{segment_id}" \
-H "xi-api-key: $ELEVENLABS_API_KEY" -H "Content-Type: application/json" \
-d '{"text": "Welcome to our latest product demo."}'translationnull# Read the language's translations
target = elevenlabs.dubbing.project.language.transcript.get(project_id, language_id)
# Refine a single translation (pass translation=None to clear it and mark for re-translation)
elevenlabs.dubbing.project.language.transcript.update_segment(
project_id,
language_id,
segment_id=target.segments[0].id,
translation="Bienvenido a nuestra última demostración de producto.",
)
# Regenerate the dub from the current transcript (charged like a generation)
elevenlabs.dubbing.project.language.transcript.regenerate(project_id, language_id)PATCH /v1/dubbing/project/{project_id}/language/{language_id}/transcript/segment/{segment_id}{"translation": "..."}POST .../language/{language_id}/transcript/regenerate202 Acceptedcompletedstalecompletedoutput_revisionrevisionoutputs.lossless_audiolanguage.listfor lang in ["es", "fr", "de", "ja"]:
elevenlabs.dubbing.project.language.create(project_id, target_language=lang)
while True:
result = elevenlabs.dubbing.project.language.list(project_id)
if not any(l.status in ("queued", "processing") for l in result.languages):
break
time.sleep(5)| Status | Meaning |
|---|---|
| Created; source fetch + preparation enqueued |
| Preparation (transcription) running |
| Source transcript available; add/generate languages. Projects stay |
| Preparation failed (e.g. source couldn't be fetched or decoded) |
| Status | Meaning |
|---|---|
| Waiting on the project becoming |
| The dub is being generated |
| Finished; |
| Previously completed, but the transcript changed; keeps the last output until regenerated |
| Generation failed |
readyqueuedreadymodel_idvoice_settings{"cloning_strength": 7}readyoutputs.lossless_audio