# YouTube Transcripts on AWS Lambda (RequestBlocked Fix)

Source: https://transcript-yt.com/blog/youtube-transcript-api-aws-lambda · Updated 2026-11-10 · TranscriptYT

> youtube-transcript-api fails on AWS Lambda, EC2, and ECS because YouTube blocks AWS IP ranges; a NAT gateway or Elastic IP is still an AWS IP. Use a residential proxy or call a transcript API from the Lambda.

A Lambda function that fetches YouTube transcripts usually works in local testing and fails once deployed, with RequestBlocked or IpBlocked from youtube-transcript-api, or "Sign in to confirm you're not a bot" from yt-dlp. YouTube blocks caption requests from AWS's published IP ranges, so every Lambda, EC2 instance, Fargate task, and App Runner service is affected.

## Why it breaks only when deployed

YouTube trusts residential IPs and distrusts datacenter ones. AWS publishes its ranges, so blocking them is easy; a NAT gateway, Elastic IP, or VPC endpoint changes nothing because the address is still AWS's. Moving to another region or account doesn't help either.

## Option 1: proxy the library

Package youtube-transcript-api in the deployment zip or a layer and give it a rotating residential proxy. Budget for per-GB proxy fees and for retries when an exit is flagged.

```
import os
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api.proxies import GenericProxyConfig

ytt = YouTubeTranscriptApi(proxy_config=GenericProxyConfig(
    http_url=os.environ["PROXY_URL"], https_url=os.environ["PROXY_URL"],
))

def handler(event, context):
    return ytt.fetch(event["video_id"]).to_raw_data()
```

## Option 2: call a transcript API

The handler makes one HTTPS request to the [TranscriptYT API](https://transcript-yt.com/api). No layer is needed (urllib ships with Python), cold starts stay small, and videos without captions are transcribed with AI. Set the function timeout to 5 minutes if you expect long caption-less videos.

```
import json, os, urllib.parse, urllib.request

def handler(event, context):
    q = urllib.parse.urlencode({"url": event["video_id"], "format": "json"})
    req = urllib.request.Request(
        f"https://transcript-yt.com/v1/transcript?{q}",
        headers={"Authorization": f"Bearer {os.environ['TRANSCRIPTYT_KEY']}"},
    )
    with urllib.request.urlopen(req, timeout=280) as res:
        data = json.load(res)
    return {"title": data["title"], "text": data["text"]}
```

## Node.js Lambdas

npm transcript packages scrape the same YouTube endpoints and are blocked the same way. In Node 18+ use fetch; the [JavaScript guide](https://transcript-yt.com/blog/youtube-transcript-api-javascript-node) has the full client.

```
export const handler = async (event) => {
  const res = await fetch(
    `https://transcript-yt.com/v1/transcript?url=${event.videoId}`,
    { headers: { Authorization: `Bearer ${process.env.TRANSCRIPTYT_KEY}` } },
  );
  return res.json();
};
```

## FAQ

### Why is youtube-transcript-api blocked on AWS Lambda?

Lambda's outbound traffic comes from AWS IP ranges, which YouTube treats as automated traffic and blocks for caption requests. The library works locally because your home IP is residential.

### Will a NAT gateway or Elastic IP fix it?

No. A NAT gateway gives you a fixed address, but it is still an AWS address in the same blocked ranges.

### Can I use a residential proxy from Lambda?

Yes. Pass a GenericProxyConfig with your proxy URL to YouTubeTranscriptApi. Keep credentials in Secrets Manager or environment variables and expect some retries.

### What is the simplest way to get transcripts on Lambda?

Call a hosted transcript API with an HTTPS request. Lambda never contacts YouTube, so there is nothing to block, and you need no extra layers or dependencies beyond an HTTP client.
