You wrote a few lines with youtube-transcript-api, it worked on your laptop, you deployed it to AWS, Google Cloud, Azure or a cheap VPS - and every call now fails with RequestBlocked or IpBlocked. Older versions of the library reported the same thing as TranscriptsDisabled, which sent many people hunting for a bug that wasn't there.
Your code is fine. The problem is where the request comes from.
Why it happens
YouTube refuses most requests that come from IP addresses known to belong to cloud providers. The library's own README says so: "YouTube has started blocking most IPs that are known to belong to cloud providers (like AWS, Google Cloud Platform, Azure, etc.)". A home connection looks like a viewer; a data center looks like a bot.
I measured it while building a transcript tool in October 2026:
- requests sent straight from a data center: every one refused;
- through data-center proxies: 58% refused;
- through rotating residential addresses with a retry from a new address: 599 of 600 answered in two runs of 300 recent videos each.
So the fix is always the same idea: the request has to leave from an address YouTube treats as a regular viewer. There are three ways to get there.
Option 1: run it from a residential connection
If you need a handful of transcripts, run the script on your own machine or a home server. No extra cost, no setup.
Watch out for VPNs: a VPN exit node can be a data-center address too, and then YouTube blocks it the same way.
This does not scale and does not work for anything that has to run in the cloud.
Option 2: residential proxies with the library
youtube-transcript-api supports proxies out of the box. With any provider of rotating residential proxies:
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api.proxies import GenericProxyConfig
ytt_api = YouTubeTranscriptApi(
proxy_config=GenericProxyConfig(
http_url="http://user:pass@my-custom-proxy.org:port",
https_url="https://user:pass@my-custom-proxy.org:port",
)
)
transcript = ytt_api.fetch("jNQXAC9IVRw")
The README also has a ready config for Webshare (WebshareProxyConfig).
Two things to know:
- buy rotating residential proxies. Static and data-center proxies get blocked, just later;
- even residential addresses are refused now and then, so add a retry that switches to a new address.
This is the right choice if you already pay for proxies or fetch transcripts at a very large scale.
Option 3: a hosted transcript API
If you would rather not manage proxies and retries, use a hosted service: you send video links, it returns transcripts. There are several.
Disclosure: I built one of them, on Apify - YouTube Transcript Scraper - Pay Only for Success. It does exactly the residential-address-plus-retry routine described above. What makes it different:
- you pay only for transcripts actually delivered: $0.004 each, $4 per 1,000. A video without captions, a deleted video or a broken link comes back as a row with the reason and costs nothing;
- on paid Apify plans it is cheaper: $3.50 per 1,000 on Starter, $3.00 on Scale, $2.50 on Business;
- plain text, timed segments or SRT;
- the original language of the video by default, or the languages you name;
- Apify's free plan gives a $5 monthly credit, which covers about 1,250 transcripts.
One request runs it and returns the rows:
curl -X POST "https://api.apify.com/v2/acts/dbolat88~youtube-transcript-pay-per-success/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"videoUrls": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"], "outputFormat": "text"}'
It does not transcribe audio: a video with no captions at all has nothing to return.
Which one to pick
| Your situation | Pick |
|---|---|
| A few videos, now and then | Option 1 |
| You already pay for residential proxies, or need huge volume | Option 2 |
| Code runs in the cloud and you don't want to maintain proxies | Option 3 |
Whichever you choose, the key point stays the same: the request must not come from a data-center address.
Top comments (0)