YouTube Transcript API Rate Limit: What It Is and How to Handle 429s

Why APIs return 429 Too Many Requests, what RFC 6585 and the Retry-After header actually specify, how rate limits differ from daily quota, and how to implement correct retry and backoff logic.

00:08:00 · SEP 13, 2026

Quick answer

A 429 means you're sending requests faster than your plan's requests-per-minute ceiling allows - it is unrelated to credits or daily quota. If the response includes a Retry-After header, wait exactly that long. If it doesn't, use exponential backoff with jitter, and separately cap how many requests you have in flight at once.

Rate limit vs. quota

These are two different constraints that get confused often:

  • Quota - total requests allowed over a longer window (e.g. a day). Running out means waiting for a reset, sometimes many hours away.
  • Rate limit - requests allowed per short window (e.g. a minute). Hitting it means slowing down for seconds to a minute, not hours.

Under the hood, most APIs implement rate limiting with either a token bucket (you accumulate request "tokens" at a steady rate and spend one per request, allowing short bursts) or a fixed/sliding window counter (a hard cap per calendar minute, resetting on the boundary). Which one a given API uses changes how bursty your traffic can safely be - a token bucket tolerates a short spike better than a fixed window does.

The HTTP standard: RFC 6585 and Retry-After

429 Too Many Requests isn't provider-specific folklore - it was formally defined in RFC 6585 (April 2012) as a standard HTTP status code. Per RFC 9110, a compliant server may attach a Retry-After header to a 429 (or 503) response, in one of two forms:

  • Delay-seconds form - an integer, e.g. Retry-After: 120, meaning wait 120 seconds.
  • HTTP-date form - an absolute timestamp, e.g. Retry-After: Wed, 21 Oct 2026 07:28:00 GMT.

When present, this header is authoritative - the server is telling you exactly when it'll accept requests again. Don't layer your own exponential backoff on top of it; that only delays your recovery further. Only fall back to backoff when the header is absent.

GetYouTubeTranscript's rate limits

PlanRate limit
Free60 req/min
Monthly ($5/mo)200 req/min
Annual ($4.50/mo)300 req/min

How this is actually enforced

This is a fixed 1-minute window per API key, not a rolling window or a token bucket - the counter resets on the clock minute boundary. It does not currently send a Retry-After header, so treat any 429 from this API as "wait up to ~60 seconds and retry with backoff," using the code pattern below rather than parsing a header that won't be there.

Handling 429s correctly

The correct order of operations: check for Retry-After first, and only fall back to exponential backoff with jitter if it's missing. Jitter (randomizing the wait slightly) matters because when many clients hit a limit simultaneously and all retry on an identical schedule, they synchronize and create a "thundering herd" that immediately re-trips the same limit.

Node.js:

async function getTranscriptWithRetry(videoId, apiKey, maxRetries = 4) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const res = await fetch(
      `https://getyoutubetranscript.com/api/v1/transcript?v=${videoId}`,
      { headers: { Authorization: `Bearer ${apiKey}` } }
    );
    if (res.status !== 429) return res.json();

    const retryAfter = res.headers.get('retry-after');
    const waitMs = retryAfter
      ? Number(retryAfter) * 1000
      : 500 * 2 ** attempt + Math.random() * 250; // exponential backoff + jitter
    await new Promise((r) => setTimeout(r, waitMs));
  }
  throw new Error('Rate limited after retries');
}

Python:

import os, time, random, requests

def get_transcript_with_retry(video_id, api_key, max_retries=4):
    url = "https://getyoutubetranscript.com/api/v1/transcript"
    for attempt in range(max_retries + 1):
        res = requests.get(url, params={"v": video_id}, headers={"Authorization": f"Bearer {api_key}"})
        if res.status_code != 429:
            return res.json()

        retry_after = res.headers.get("Retry-After")
        wait = float(retry_after) if retry_after else (0.5 * 2 ** attempt + random.uniform(0, 0.25))
        time.sleep(wait)
    raise RuntimeError("Rate limited after retries")

Rate vs. concurrency - a distinct problem

A request-per-minute ceiling and an in-flight concurrency ceiling are not the same thing. Firing 50 requests simultaneously with Promise.all can trip a 429 even if your total for the minute is well under budget, because the server (or a proxy in front of it) may also cap simultaneous connections. When batch-processing many videos, cap concurrency independently of your rate-limit backoff:

import pLimit from 'p-limit';

const limit = pLimit(5); // at most 5 requests in flight at once
const results = await Promise.all(
  videoIds.map((id) => limit(() => getTranscriptWithRetry(id, apiKey)))
);

For sustained high-volume batches, upgrading plan tier raises the req/min ceiling directly - see pricing in the API docs, or start with 100 free credits from the dashboard.

Rate limit FAQs

Q01

What is the difference between a rate limit and a quota?

A quota caps total usage over a period (e.g. per day). A rate limit caps how many requests you can make per unit of time (e.g. per minute), independent of your total daily usage - you can hit a rate limit while still well under your daily quota. See our YouTube API quota guide for the quota side of this.

Q02

What does a 429 response mean?

429 Too Many Requests was formally defined in RFC 6585 in 2012. It means you've exceeded the requests-per-window limit for your plan - it's a signal to slow down and retry, not that your request was invalid or that you're out of credits.

Q03

What is the Retry-After header, and should I always trust it?

Per RFC 9110, a server may include a Retry-After header on a 429 or 503 response, in one of two forms: an integer number of seconds (Retry-After: 120) or an absolute HTTP-date. If it's present, honor it exactly rather than layering your own backoff on top - the server has given you an authoritative answer about when to retry.

Q04

What's GetYouTubeTranscript's rate limit, and does it send a Retry-After header?

60 requests/minute on the free plan, 200 req/min on the monthly plan, and 300 req/min on the annual plan, enforced as a fixed 1-minute window per API key (not a rolling window). It does not currently send a Retry-After header on 429s, so implement your own backoff (see the code below) rather than expecting one - because the window is fixed rather than rolling, the wait is at most the remainder of the current minute.

Q05

Does a 429 consume a credit?

No - a rate-limited request is never charged. Only successful requests consume credits.

Q06

Should I open multiple API keys to get more throughput?

No - this typically violates a provider's fair-use terms, and on GetYouTubeTranscript specifically, rate limiting is enforced per API key already, but credits and account standing are tracked at the account level regardless of how many keys you generate. If you need more throughput, upgrade plan tier instead, which directly raises the req/min ceiling.

Q07

Why do my requests fail even though I'm under the requests-per-minute limit?

That's usually a concurrency problem, not a rate problem - firing 50 requests in parallel can overwhelm a server even if your total for the minute is within budget. Use a concurrency limiter (like p-limit in Node or a semaphore in Python) to cap how many requests are in flight at once, separately from how many you send per minute.

Related