DEV Community

Aquila
Aquila

Posted on AI-assisted

Why your YouTube transcript scraper returns the wrong language (and how to fix it)

I was building a YouTube transcript scraper for an AI pipeline and ran a simple test: 50 random videos (podcasts, tutorials, TED talks, news, music, Hindi speeches, a Japanese vlog).

37 of them had captions. And 9 of those 37 came back in the wrong language:

  • 8 English videos returned captions in Arabic, Chinese or Albanian
  • 1 Hindi video returned the English dub instead of the original Hindi

That's roughly 1 in 4 transcripts. If you're feeding transcripts to an LLM, a RAG index or a summarizer, that's a silent bug: nothing crashes, you just get garbage.

Why it happens

Most scrapers (and a lot of tutorials) do something like this:

tracks = get_caption_tracks(video_id)
transcript = download(tracks[0])  # first track in the list
Enter fullscreen mode Exit fullscreen mode

The problem: YouTube's caption list is not ordered by the original language. A popular English video can have 40+ community translations, and the first one in the list can be anything.

Two other traps:

  • The "default" track changes with the viewer. The caption YouTube marks as default depends on the language of whoever is asking, so a server in another country can get a different default than you do in your browser.
  • Dubbed videos. Videos with multi-language audio have several audio tracks. If you pick the wrong one, you transcribe the dub, not the original.

How to find the original language

What worked for me, in order:

  1. Dubbed videos: the original audio track has its own flag in the player data. Read it.
  2. Everything else: use the language of the auto-generated (speech recognition) track. YouTube runs speech recognition in the language that is actually spoken, so that track's language is a very reliable signal.
  3. Then pick the best captions in that language: human-made captions first, auto-generated only if there are no human ones.

If you're using the open-source youtube-transcript-api library, step 2 looks roughly like this:

from youtube_transcript_api import YouTubeTranscriptApi

ytt = YouTubeTranscriptApi()
tracks = ytt.list("VIDEO_ID")

# The auto-generated track is in the spoken language
asr = [t for t in tracks if t.is_generated]
original = asr[0].language_code if asr else None

# Prefer human captions in that language, fall back to auto-generated
try:
    transcript = tracks.find_manually_created_transcript([original])
except Exception:
    transcript = tracks.find_generated_transcript([original])

text = " ".join(s.text for s in transcript.fetch())
Enter fullscreen mode Exit fullscreen mode

One more thing that will bite you in production: YouTube blocks most cloud IPs. In my test, requests from datacenter proxies succeeded 2% of the time; residential proxies, 100%. Code that works on your laptop can fail on a server with "Sign in to confirm you're not a bot".

If you don't want to maintain this yourself

I packaged all of the above into an Apify Actor: YouTube Transcript API.

  • Original spoken language by default (or any language you ask for)
  • Input: video URL, playlist, channel or search term
  • Output: plain text, timestamped text, SRT and Markdown, plus title, channel, duration and language
  • Residential proxies and retries included
  • $3 per 1,000 transcripts, charged only when a transcript is delivered. Videos without captions are free.

From Python:

from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("massa182/youtube-transcript").call(
    run_input={"sources": ["https://www.youtube.com/@TED"], "maxVideosPerSource": 10}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["language"], item["wordCount"])
Enter fullscreen mode Exit fullscreen mode

It also works from n8n, Make, Zapier and as an MCP tool for AI agents.


Have you run into the wrong-language problem? I'm curious how others are handling dubbed videos and channels with lots of translations. Let me know in the comments.

Top comments (0)