Python · Serverless · Troubleshooting
youtube-transcript-api Blocked on Vercel, Render, or Railway?
RequestBlocked and IpBlocked on Vercel Functions, Render, and Railway are the hosting IP, not your code. The static-outbound-IP add-ons are for allowlists. YouTube does not allowlist you.
· 3 min read · YTAPI
You deploy a small function, it calls youtube-transcript-api, and production is the first place it fails:
youtube_transcript_api._errors.IpBlocked:
Could not retrieve a transcript for the video ...
YouTube is blocking requests from your IP.or RequestBlocked, depending on whether YouTube answered with HTTP 429, a reCAPTCHA page, or the player message about confirming you are not a bot. IpBlocked is a subclass of RequestBlocked. The function is fine. The address it uses to reach YouTube is a hosting address, shared with every other customer on that platform.
AWS and Google Cloud have the same refusal. Vercel, Render, and Railway add a confusing extra step: each one will sell you a static outbound IP, and it still will not fetch the transcript.
What those static IPs are for
They exist so a database or a partner firewall can allowlist you.
- Vercel. Functions and builds leave from a dynamic range. Static IPs, on Pro and Enterprise, send that traffic through a shared NAT address you can copy into an allowlist. The address belongs to that hosting network.
- Render. Each service already egresses through the regional ranges shown under Connect → Outbound in the dashboard. Those ranges are how Render reaches the internet. They are hosting ranges.
- Railway. Static outbound IPs are a Pro feature, meant for allowlists. Railway's docs note that the address can be shared with other customers, and that it is not for inbound traffic.
YouTube is not waiting for your IP on an allowlist. A stable hosting address is still a hosting address. Paying for one makes logs easier to read. It does not move the request onto a consumer connection.
What you can do from the function
Call YouTube from somewhere else. A laptop or a small machine on a home connection, writing results to storage the function reads, works at low volume. The function stays on Vercel. The transcript fetch does not.
Proxy the YouTube call. The library accepts an HTTP proxy. The proxy has to exit through residential addresses. A datacenter proxy fails for the same reason the function fails. Setup and the tradeoffs (price per gigabyte, dead exits, uneven latency) are on the AWS page.
Skip cookies, for now. The error text talks about cookies. The current youtube-transcript-api release has cookie authentication turned off, and the README says so. Passing cookies.txt into a Vercel function will not take this path.
Call a transcript API over HTTPS. The function never opens a connection to YouTube. This is the version that fits a serverless timeout, because you are waiting on one HTTP response instead of a proxy chain.
import os
import requests
res = requests.post(
"https://api.ytapi.dev/v1/transcripts",
headers={"Authorization": f"Bearer {os.environ['YTAPI_KEY']}"},
json={"video_id": "dQw4w9WgXcQ", "format": "text"},
timeout=30,
)
if res.status_code == 404:
# captions_disabled, language_not_found, or video_unavailable. Not billed.
print(res.json()["error"]["code"])
else:
res.raise_for_status()
print(res.text)Set the timeout below the function's own limit. A missing caption is a 404 with a code, and it costs nothing. Language fallback and batching are in the Python guide.
FAQ
Does it work from Vercel's Edge runtime?
The library doesn't, since it's Python. A transcript API does: it's a single fetch call, which works in Edge functions, Node functions, and on Render or Railway alike.
What timeout should I set?
Below your platform's function limit, so you get an error you can handle instead of a killed function. Most transcripts come back in well under a second; the first request for a very long video can take several seconds.
Should I cache transcripts?
Yes. Captions rarely change after the first day or two, so store them by video ID in your database or KV store. It saves time on repeat requests, and credits too, because a request served from the provider's cache is still billed.