Answers
youtube-transcript-api says my IP is blocked. How do I get YouTube transcripts from a server?
Short answer
Stop fetching captions from YouTube with your server's own IP: call the YouTube transcript endpoint (/v1/youtube/videos/transcript/get) and okdata does the fetching. Each transcript costs $0.004, a video without captions returns not_found and costs nothing, and you need no residential proxies.
The pattern is always the same. A video summariser works on your laptop, you deploy it to AWS, Railway or a Colab notebook, and the first request fails with RequestBlocked or IpBlocked. YouTube refuses caption requests from many cloud IP ranges, and the library cannot change where your server sits. People in the project's issue tracker report blocks even after buying rotating proxies.
The way out is to stop asking YouTube from that IP at all. Your server calls an HTTPS API with a key; the API returns the transcript.
The endpoint
YouTube video transcript takes the 11-character video ID (id) and an optional preferred language (lang). It returns the full text plus timed segments, each with start, end and text in seconds.
| Volume | Calls | Cost |
|---|---|---|
| 1 video | 1 | $0.004 |
| 100 videos | 100 | $0.40 |
| 1,000 videos | 1000 | $4.00 |
Those are ceilings: videos without captions come back as not_found and are not charged.
A drop-in replacement for fetch()
import os, requests
def fetch_transcript(video_id, lang=None):
params = {"id": video_id, **({"lang": lang} if lang else {})}
body = requests.get(
"https://api.okdata.online/v1/youtube/videos/transcript/get",
headers={"Authorization": f"Bearer {os.environ['OKDATA_API_KEY']}"},
params=params, timeout=60,
).json()
if body["code"] == "not_found":
return None # the video has no captions; nothing was charged
if body["code"] != "ok":
raise RuntimeError(f"{body['code']}: {body['message']}")
return body["data"]["item"]
t = fetch_transcript("dQw4w9WgXcQ", lang="en")
print(t["lang"], len(t["segments"]), t["text"][:200])
If your code expects youtube-transcript-api's shape, duration is end - start.
Things that still bite
- Pass the ID, not the link. From
https://www.youtube.com/watch?v=dQw4w9WgXcQ, senddQw4w9WgXcQ. - A burst of calls can hit your key's rate limit. A
rate_limitedanswer is free; waitRetry-Afterseconds and resend. Codes are listed under errors. - When a call times out, retry with the same
Idempotency-Key; a finished result is replayed without a second charge. - Only public videos with captions work. There is no speech-to-text here.
When another route is better
- Keep youtube-transcript-api if you already pay for a residential proxy pool that works for you; at very high volume that can cost less.
- For a few dozen videos, running the library from a home connection usually works.
- For your own channel, the official YouTube Data API can download your caption files, because you have edit rights.
- For videos with no captions at all, run Whisper on audio you are allowed to download.
More batch patterns are on the video transcript solution page.
Updated