Get YouTube Transcripts in 125+ Languages: A Guide
David Boulen · 7/1/2026 · 10 min read
Get YouTube Transcripts in 125+ Languages: A Guide
If you're building a multilingual content tool, feeding transcripts into an LLM, or serving users across different locales, you need more than just English captions. YouTube hosts video in dozens of languages and offers auto-translated tracks for hundreds more — but actually getting those transcripts programmatically is more complicated than it looks.
This guide covers everything: how YouTube's caption system works under the hood, how to request transcripts in a specific language with one parameter, how fallback behavior works, and how to confirm which language you actually got back.

How YouTube Handles Multilingual and Translated Captions
YouTube maintains several types of caption tracks per video, and understanding the difference matters when you're pulling transcripts programmatically.
Manually created captions are uploaded directly by the video creator. These are the most accurate and often the most complete — think professional channels, news outlets, and educational content. A creator might upload English and Spanish versions of the same transcript.
Auto-generated captions are YouTube's speech-to-text output. YouTube produces auto-captions for content in roughly 60+ languages including English, Spanish, Portuguese, French, German, Japanese, Korean, and Hindi. According to YouTube's own help documentation, auto-caption accuracy varies by audio quality and speaker clarity — the gap between auto-generated output and human-verified transcription can matter for accessibility workflows (the 3Play Media 2024 State of Captioning report found 90% of organizations caption at least some content, with accuracy standards ranging widely by use case).
Auto-translated tracks are YouTube's machine translation layer. Even if a video only has English captions, YouTube can serve translated versions in many additional languages. This is the mechanism that pushes the practical language coverage well beyond the ~60 auto-caption languages.
When you call the transcript API, you're navigating this three-tier system. A well-structured request will prefer manually created tracks when available, fall through to auto-generated if not, and ultimately land on auto-translated as a last resort.
Requesting a Transcript in a Specific Language
The /api/v2/transcript endpoint accepts a lang parameter that takes a BCP-47 language code. This is the same format YouTube itself uses for its caption tracks.
Basic pattern:
GET https://getyoutubetranscriber.com/api/v2/transcript
?video_url=<VIDEO_ID>
&lang=<BCP-47-CODE>
curl
# French transcript
curl "https://getyoutubetranscriber.com/api/v2/transcript?video_url=dQw4w9WgXcQ&lang=fr" \
-H "Authorization: Bearer YOUR_API_KEY"
# Brazilian Portuguese
curl "https://getyoutubetranscriber.com/api/v2/transcript?video_url=dQw4w9WgXcQ&lang=pt-BR" \
-H "Authorization: Bearer YOUR_API_KEY"
# Simplified Chinese
curl "https://getyoutubetranscriber.com/api/v2/transcript?video_url=dQw4w9WgXcQ&lang=zh-Hans" \
-H "Authorization: Bearer YOUR_API_KEY"
Python
import httpx
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://getyoutubetranscriber.com/api/v2/transcript"
def get_transcript(video_id: str, lang: str = None) -> dict:
params = {"video_url": video_id}
if lang:
params["lang"] = lang
response = httpx.get(
BASE_URL,
params=params,
headers={"Authorization": f"Bearer {API_KEY}"},
)
response.raise_for_status()
return response.json()
# Get Spanish transcript
data = get_transcript("dQw4w9WgXcQ", lang="es")
print(f"Language returned: {data['language']}")
for segment in data["transcript"][:3]:
print(f"[{segment['start']:.1f}s] {segment['text']}")
Node.js
const API_KEY = "YOUR_API_KEY";
async function getTranscript(videoId, lang = null) {
const url = new URL("https://getyoutubetranscriber.com/api/v2/transcript");
url.searchParams.set("video_url", videoId);
if (lang) url.searchParams.set("lang", lang);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json();
}
// Get Japanese transcript
const data = await getTranscript("dQw4w9WgXcQ", "ja");
console.log(`Language returned: ${data.language}`);
data.transcript.slice(0, 3).forEach(({ start, text }) => {
console.log(`[${start.toFixed(1)}s] ${text}`);
});
Go
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
)
const apiKey = "YOUR_API_KEY"
const baseURL = "https://getyoutubetranscriber.com/api/v2/transcript"
type TranscriptResponse struct {
VideoID string `json:"video_id"`
Language string `json:"language"`
Transcript []struct {
Text string `json:"text"`
Start float64 `json:"start"`
Duration float64 `json:"duration"`
} `json:"transcript"`
}
func getTranscript(videoID, lang string) (*TranscriptResponse, error) {
params := url.Values{"video_url": {videoID}}
if lang != "" {
params.Set("lang", lang)
}
req, _ := http.NewRequest("GET", baseURL+"?"+params.Encode(), nil)
req.Header.Set("Authorization", "Bearer "+apiKey)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result TranscriptResponse
json.NewDecoder(resp.Body).Decode(&result)
return &result, nil
}
func main() {
data, err := getTranscript("dQw4w9WgXcQ", "de") // German
if err != nil {
panic(err)
}
fmt.Printf("Language returned: %s\n", data.Language)
for _, seg := range data.Transcript[:3] {
fmt.Printf("[%.1fs] %s\n", seg.Start, seg.Text)
}
}
Example JSON Response
A successful request returns the transcript segments alongside a language field confirming which track was served:
{
"video_id": "dQw4w9WgXcQ",
"language": "fr",
"transcript": [
{ "text": "Nous nous connaissons depuis si longtemps", "start": 17.6, "duration": 4.2 },
{ "text": "Votre cœur fait mal et vous savez pourquoi", "start": 21.8, "duration": 3.9 },
{ "text": "Je voulais te le dire mais je n'ai pas eu le cœur", "start": 25.7, "duration": 4.1 }
]
}
Language code format: Use standard BCP-47 codes. Two-letter codes (
fr,es,de,ja,ko) cover most cases. For regional variants use the extended form:pt-BRfor Brazilian Portuguese,zh-Hansfor Simplified Chinese,zh-Hantfor Traditional Chinese,en-GBfor British English.
Falling Back to Auto-Translated Tracks
What happens when you request lang=ar but the video only has English captions? Rather than returning an error, the API falls back to YouTube's auto-translation layer and returns an Arabic-language transcript generated from the original captions.
This is useful but worth understanding precisely:
- Exact track match: If the video has a manually created or auto-generated Arabic caption track, that's returned directly.
- Auto-translation fallback: If no Arabic track exists, the API requests YouTube's auto-translated version, which runs the original captions through machine translation.
- Language confirmation: The
languagefield in the response reflects what was actually served. If you requestedarbut got auto-translated output, you'll still seear— the key signal is whether the content came from a human-created track or machine translation, which you'd need to infer from your knowledge of the video.
For production pipelines where caption quality matters — accessibility, legal transcription, regulated content — you should validate whether the video has a human-created track before relying on auto-translated output. For use cases like LLM training data, summarization, or search indexing, auto-translated tracks are often good enough to be useful.
Fetching a transcript with fallback handling in Python:
def get_transcript_with_fallback(video_id: str, preferred_lang: str, fallback_lang: str = "en"):
"""
Try preferred language first. If translation quality is critical,
check the returned language against what was requested.
"""
data = get_transcript(video_id, lang=preferred_lang)
returned_lang = data.get("language", "")
if not returned_lang.startswith(preferred_lang.split("-")[0]):
# The API returned a different language — fall back to English
print(f"Requested {preferred_lang}, got {returned_lang}. Falling back to {fallback_lang}.")
data = get_transcript(video_id, lang=fallback_lang)
return data
Detecting Available Languages Per Video
The /api/v2/transcript endpoint doesn't expose a separate "list available languages" call — you discover what's available by attempting to fetch the transcript and inspecting the language field in the response.
A practical pattern for localization pipelines: fetch the transcript in each of your target languages and record what comes back. For batch workflows, combine this with the bulk endpoint.
Bulk Fetching Transcripts Across Languages
The /api/v2/transcripts-bulk endpoint accepts up to 50 video IDs per POST request — but if you need the same video in multiple languages, you'll send one request per language. Here's a pattern that fetches a single video across several target locales:
import httpx
import asyncio
API_KEY = "YOUR_API_KEY"
BULK_URL = "https://getyoutubetranscriber.com/api/v2/transcripts-bulk"
TARGET_LANGUAGES = ["en", "es", "fr", "de", "ja", "pt-BR", "zh-Hans", "ar"]
async def fetch_multilingual_transcripts(video_id: str) -> dict[str, dict]:
async with httpx.AsyncClient() as client:
tasks = []
for lang in TARGET_LANGUAGES:
tasks.append(
client.get(
"https://getyoutubetranscriber.com/api/v2/transcript",
params={"video_url": video_id, "lang": lang},
headers={"Authorization": f"Bearer {API_KEY}"},
)
)
responses = await asyncio.gather(*tasks, return_exceptions=True)
results = {}
for lang, resp in zip(TARGET_LANGUAGES, responses):
if isinstance(resp, Exception):
results[lang] = {"error": str(resp)}
elif resp.status_code == 200:
data = resp.json()
results[lang] = {
"language": data["language"],
"segment_count": len(data["transcript"]),
"sample": data["transcript"][0]["text"] if data["transcript"] else "",
}
else:
results[lang] = {"error": f"HTTP {resp.status_code}"}
return results
# Run it
video_id = "dQw4w9WgXcQ"
transcripts = asyncio.run(fetch_multilingual_transcripts(video_id))
for lang, info in transcripts.items():
print(f"{lang}: {info}")
Sample output:
en: {'language': 'en', 'segment_count': 112, 'sample': "We've known each other for so long"}
es: {'language': 'es', 'segment_count': 109, 'sample': 'Nos conocemos hace tanto tiempo'}
fr: {'language': 'fr', 'segment_count': 108, 'sample': 'Nous nous connaissons depuis si longtemps'}
ja: {'language': 'ja', 'segment_count': 95, 'sample': '私たちはとても長い間知り合いです'}
This approach gives you a practical language availability map for any video without a separate API call.

Use Cases for Localization Teams
The 125+ language coverage unlocks workflows that would be painful to build on raw YouTube APIs or open-source libraries.
Subtitle and Caption Generation
Caption files for accessibility and compliance are the most direct use case. Pull the transcript in the viewer's language, format the segments into SRT or VTT, and serve them alongside embedded video. The start and duration fields on each segment map directly to subtitle timing.
def transcript_to_srt(transcript: list[dict]) -> str:
lines = []
for i, seg in enumerate(transcript, 1):
start = seg["start"]
end = start + seg["duration"]
def fmt(seconds):
h, remainder = divmod(seconds, 3600)
m, s = divmod(remainder, 60)
ms = int((s % 1) * 1000)
return f"{int(h):02}:{int(m):02}:{int(s):02},{ms:03}"
lines.append(f"{i}\n{fmt(start)} --> {fmt(end)}\n{seg['text']}\n")
return "\n".join(lines)
data = get_transcript("VIDEO_ID", lang="ko")
srt = transcript_to_srt(data["transcript"])
with open("subtitles_ko.srt", "w", encoding="utf-8") as f:
f.write(srt)
Multilingual LLM Pipelines
If you're building a RAG system or fine-tuning dataset, you often want transcript data in the same language as your users' queries. Rather than translating after the fact, pull the transcript directly in the target language — you get cleaner text without an extra translation step. For more on assembling transcript datasets for AI training, see Building Transcript Datasets for LLM Fine-Tuning.
Channel-Level Localization Monitoring
For teams tracking multilingual YouTube channels — news outlets, international brands, educational publishers — you can combine the channel-videos endpoint with per-language transcript fetching to maintain a multilingual content index. The Monitor a YouTube Channel for New Videos via API guide covers the channel polling pattern; add lang parameters to transcript calls once you have new video IDs.
Content Repurposing at Scale
According to Business Research Insights, the video localization market reached an estimated $1.87 billion in 2024, driven by platforms and content teams localizing video assets into new markets. If you're running a content repurposing pipeline — turning YouTube videos into blog posts, summaries, or social content — pulling the transcript in the reader's language is faster and cheaper than translating after extraction.
A practical setup: detect user locale, pass lang=<user_locale> to the transcript call, then pass the result to your LLM for summarization. One API call, one credit, localized output.
def summarize_video_for_locale(video_id: str, locale: str, openai_client) -> str:
transcript_data = get_transcript(video_id, lang=locale)
full_text = " ".join(seg["text"] for seg in transcript_data["transcript"])
response = openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": f"Summarize the following transcript in {locale} in 3 bullet points."},
{"role": "user", "content": full_text[:8000]},
]
)
return response.choices[0].message.content
Accessibility and Compliance Workflows
The 80/20 reality of captions: studies consistently find that a large majority of caption users are not hearing-impaired — they're watching in noisy environments, quiet offices, or in a non-native language. For teams with accessibility or regulatory requirements (particularly in the EU under the European Accessibility Act), being able to pull clean caption text programmatically across languages matters as much for compliance auditing as for user experience.
Practical Gotchas
A few things to watch for when building with multilingual transcripts:
- Right-to-left languages: Arabic (
ar), Hebrew (he), and Persian (fa) return text in RTL order. If you're rendering this in a UI, make sure your layout handlesdir="rtl"correctly. - Segment count varies by language: Translated tracks often have different segment boundaries than the original. Don't assume segment count or timing will match between languages even for the same video.
- Language code specificity:
ptreturns generic Portuguese;pt-BRrequests Brazilian Portuguese specifically. If you're building for a Brazilian audience, the more specific code gets you more relevant output. - Videos with no captions: Some videos have no caption tracks at all. These return an error rather than an empty transcript. Handle this with a try/except or status-code check, and consider this when designing retry logic.
- Rate limits: High-volume multilingual fetching (e.g., 8 languages × 1,000 videos = 8,000 calls) should respect rate limits. Check the rate limits documentation and batch requests accordingly.
Getting Started
YouTube Transcriber starts with 100 free credits and no credit card required. For transcript requests, that's 100 multilingual transcript calls to explore the language support before committing.
The full parameter reference for the lang parameter — including all supported BCP-47 codes and examples for edge-case languages — is in the API documentation. If you're new to transcript fetching in general, Get YouTube Transcripts in Python: The Complete Guide covers the basics before you layer in language selection.
Start with the languages your users actually need, confirm the language field in responses, and build your fallback logic around the cases where exact tracks don't exist. That's the pattern that holds up in production.