AI Dubbing with the ElevenLabs API: How to Translate and Dub Video Programmatically
Last updated:
Affiliate link — we may earn a small commission.
Add dubbing to your application with the ElevenLabs API
Translate and dub content into 100+ languages while preserving voice identity. Usage-based billing, no minimum.
Localization at scale requires more than subtitles. If your application serves global audiences and voice quality matters — marketing content, education, corporate communications, creator tools — you need dubbing: translated audio in the original speaker's voice.
The ElevenLabs Dubbing API makes this a single API integration. Submit a video or audio URL, specify target languages, and the API returns dubbed output with the original speaker's voice preserved across every language.
This guide covers the full Dubbing API integration.
How the Dubbing API Works
The pipeline runs in four steps automatically:
- Transcription — Scribe transcribes the source audio with word-level timing and speaker identification
- Translation — the transcript is translated into each target language, adapting phrasing for natural delivery
- Voice cloning — the original speaker's voice is cloned from the source audio
- Generation — dubbed audio is synthesised in each target language using the cloned voice, synchronized to the original timing
The result preserves voice identity across all language versions. For multi-speaker content, the API identifies and clones each speaker separately.
Dubbing API: Basic Request
The Dubbing API is asynchronous — you submit a job, then poll for results.
import requests
import time
ELEVENLABS_API_KEY = "your_api_key"
def create_dubbing_job(
source_url: str,
target_languages: list[str],
source_language: str = "en"
) -> str:
"""Submit a dubbing job. Returns dubbing_id."""
url = "https://api.elevenlabs.io/v1/dubbing"
headers = {"xi-api-key": ELEVENLABS_API_KEY}
data = {
"source_url": source_url,
"target_lang": target_languages,
"source_lang": source_language,
"num_speakers": 0, # 0 = auto-detect
"watermark": False,
"highest_resolution": True
}
response = requests.post(url, headers=headers, data=data)
response.raise_for_status()
return response.json()["dubbing_id"]
For a YouTube video:
dubbing_id = create_dubbing_job(
source_url="https://www.youtube.com/watch?v=example",
target_languages=["fr", "de", "es", "ja"],
source_language="en"
)
print(f"Dubbing job created: {dubbing_id}")
Polling for Job Status
The API processes jobs asynchronously. Poll the status endpoint until the job completes:
def wait_for_dubbing(dubbing_id: str, poll_interval: int = 15) -> dict:
"""Poll until the dubbing job completes. Returns the final status."""
url = f"https://api.elevenlabs.io/v1/dubbing/{dubbing_id}"
headers = {"xi-api-key": ELEVENLABS_API_KEY}
while True:
response = requests.get(url, headers=headers)
response.raise_for_status()
status_data = response.json()
status = status_data.get("status")
print(f"Status: {status}")
if status == "dubbed":
return status_data
elif status in ("failed", "error"):
raise RuntimeError(f"Dubbing failed: {status_data}")
time.sleep(poll_interval)
Downloading Dubbed Audio
Once the job completes, download the dubbed audio for each target language:
def download_dubbed_audio(
dubbing_id: str,
language_code: str,
output_path: str
) -> str:
"""Download the dubbed audio for a specific language."""
url = f"https://api.elevenlabs.io/v1/dubbing/{dubbing_id}/audio/{language_code}"
headers = {"xi-api-key": ELEVENLABS_API_KEY}
response = requests.get(url, headers=headers, stream=True)
response.raise_for_status()
with open(output_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
return output_path
def download_all_languages(dubbing_id: str, languages: list[str], output_dir: str) -> dict:
"""Download dubbed audio for all target languages."""
import os
os.makedirs(output_dir, exist_ok=True)
results = {}
for lang in languages:
output_path = os.path.join(output_dir, f"dubbed_{lang}.mp3")
download_dubbed_audio(dubbing_id, lang, output_path)
results[lang] = output_path
print(f"Downloaded: {lang} → {output_path}")
return results
Get your ElevenLabs API key
Full Workflow: Video to Multi-Language Dub
def dub_video(
source_url: str,
target_languages: list[str],
output_dir: str,
source_language: str = "en"
) -> dict:
"""Complete workflow: submit, wait, download."""
print(f"Submitting dubbing job for {len(target_languages)} languages...")
dubbing_id = create_dubbing_job(source_url, target_languages, source_language)
print(f"Job ID: {dubbing_id}. Waiting for completion...")
status = wait_for_dubbing(dubbing_id)
print("Downloading dubbed audio...")
files = download_all_languages(dubbing_id, target_languages, output_dir)
return {
"dubbing_id": dubbing_id,
"status": status,
"files": files
}
# Usage
result = dub_video(
source_url="https://www.youtube.com/watch?v=example",
target_languages=["fr", "de", "es", "pt", "ja"],
output_dir="./dubbed_output"
)
Uploading Files Directly
For content that is not publicly accessible via URL, upload the file directly:
def create_dubbing_job_from_file(
file_path: str,
target_languages: list[str],
source_language: str = "en"
) -> str:
url = "https://api.elevenlabs.io/v1/dubbing"
headers = {"xi-api-key": ELEVENLABS_API_KEY}
with open(file_path, "rb") as f:
file_name = file_path.split("/")[-1]
content_type = "video/mp4" if file_path.endswith(".mp4") else "audio/mpeg"
files = {"file": (file_name, f, content_type)}
data = {
"target_lang": target_languages,
"source_lang": source_language,
"num_speakers": 0
}
response = requests.post(url, headers=headers, files=files, data=data)
response.raise_for_status()
return response.json()["dubbing_id"]
Retrieving the Translated Transcript
The API also returns the translated transcript for each language — useful for generating subtitles or closed captions alongside the dubbed audio:
def get_dubbed_transcript(dubbing_id: str, language_code: str) -> dict:
"""Get the translated transcript for a specific language."""
url = f"https://api.elevenlabs.io/v1/dubbing/{dubbing_id}/transcript/{language_code}"
headers = {"xi-api-key": ELEVENLABS_API_KEY}
params = {"format_type": "srt"} # or "webvtt"
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
return response.text # returns SRT or WebVTT formatted string
# Generate subtitles alongside dubbed audio
srt_content = get_dubbed_transcript(dubbing_id, "fr")
with open("subtitles_fr.srt", "w") as f:
f.write(srt_content)
Add dubbing to your app — usage-based billing
Use Cases for the Dubbing API
Content platforms — automatically dub creator uploads into multiple languages at ingestion time. Expand content reach without requiring creators to produce separate language versions.
E-learning and training — localize course content for regional markets. Learners hear the instructor's voice in their language rather than a foreign speaker reading a translation.
Marketing and brand content — preserve brand spokesperson voice and delivery across all language versions of a campaign. Consistent speaker identity regardless of the viewer's language.
Corporate communications — dub executive communications, town halls, and training videos for international offices without separate recording sessions.
Documentary and long-form video — dub completed content into target language markets. The API handles full-length content — not just short clips.
Voice Quality Considerations
Source audio quality directly affects clone fidelity. For best results:
- Use the cleanest audio available — background music or noise reduces clone quality
- For content with background music, provide a vocal-only stem if possible, then re-mix dubbed audio over the original music track
- Multi-speaker content is handled automatically, but clear speaker separation in the source audio improves accuracy
Frequently Asked Questions
What is the ElevenLabs Dubbing API? Translates audio and video into 100+ languages while preserving the original speaker's voice using automatic cloning.
Can I pass a YouTube URL directly?
Yes — include the URL as source_url. No need to download and re-upload.
How does it preserve the speaker's voice? The API automatically clones the speaker's voice from the source audio, then generates dubbed speech using that clone in each target language.
What formats does it accept? MP4, MOV, MP3, WAV, and URL inputs (YouTube and other direct URLs).
How do I get the subtitles alongside the dubbed audio?
Use the transcript endpoint with format_type=srt or format_type=webvtt to retrieve formatted subtitles for each target language.
Free: AI Voice Tool Comparison Guide
Which tool wins for your use case, ElevenLabs pricing decoded, and a quick-reference comparison table — sent straight to your inbox. No spam. Unsubscribe anytime.
Add dubbing to your application with the ElevenLabs API
Translate and dub content into 100+ languages while preserving voice identity. Usage-based billing, no minimum.
Frequently Asked Questions
Last updated: