Skip to content

TranscriptFor developers, automation

YouTube transcript script works locally, fails deployed

Why a YouTube transcript script gets blocked once it runs on a server, and how to handle every CleanScript error in production: retry, skip or fix.

2 min readBy CleanScriptMarkdown

On this page
  1. Three kinds of failure
  2. The SDKs retry for you
  3. Production checklist

A transcript script that works on your laptop and fails on a server is usually being blocked. YouTube blocks most IP addresses that belong to cloud providers, so youtube-transcript-api raises RequestBlocked or IpBlocked once you deploy. The library's README says so and recommends rotating residential proxies.

The official YouTube Data API won't help with other people's videos: downloading a caption track requires permission to edit the video.

So you run proxies yourself or call a hosted API; youtube-transcript-api alternatives compares them. With CleanScript, your server never calls YouTube. What's left is handling the answers.

Three kinds of failure #

Kind Codes What to do
Try again later rate_limited (429), source_unavailable (503), processing_failed (503), timeout (504) Wait for Retry-After, then retry.
Nothing to get video_unavailable (404), no_captions, language_unavailable, video_too_long (422) Retrying won't help. Skip it and log why.
Fix the request invalid_url, unsupported_platform, invalid_request (400), unauthorized (401), insufficient_credits (402) Fix the input, the key or the balance.

No failed request uses credits. Every error has the same shape:

JSON
{
  "error": {
    "code": "video_unavailable",
    "message": "This video is private.",
    "param": "url",
    "details": { "reason": "private" }
  },
  "request_id": "5f0c7d1e-0b7a-4a39-9c1e-3c1f2b8f6a10"
}

Branch on code, never on message. Keep request_id in your logs; if something looks wrong, send it to us and we can find the request. The full list is in Credits & limits.

The SDKs retry for you #

The Python and TypeScript clients retry 429, 503 and network errors twice with backoff, honouring Retry-After. Each transcript and extract call carries an idempotency key, so a retry is never charged twice. When retries run out, you get a typed error:

Python
from cleanscript_ai import CleanScript, CleanScriptError, InsufficientCreditsError, VideoUnavailableError

client = CleanScript(max_retries=4)

def get_text(url):
    try:
        return client.transcript(url).text
    except VideoUnavailableError as error:
        print("skip:", url, error.details)  # reason: private, removed, age_restricted, live or unavailable
        return None
    except InsufficientCreditsError as error:
        raise SystemExit(f"Out of credits: {error.details['top_up_url']}")
    except CleanScriptError as error:
        if error.code in {"no_captions", "language_unavailable", "video_too_long"}:
            print("skip:", url, error.code)
            return None
        raise

The other subclasses are AuthenticationError, RateLimitError and ConnectionFailedError; everything else is a CleanScriptError with a code.

Production checklist #

  • Keep the key in a secret store and read it from CLEANSCRIPT_API_KEY.
  • Run a few requests at a time. Your limit per minute is in GET /v1/account, which is free.
  • Log request_id and the X-Credits-Remaining header with each job.
  • Retry only the first kind of failure. Record the second and move on.
  • Stop the queue on insufficient_credits instead of failing every item.
  • The same request within 6 hours is free, so re-running a half-finished batch costs only what's new.

No-code tools follow the same rules: see transcripts in n8n, Make and Zapier.

Sources

  1. jdepoix/youtube-transcript-api, README: Working around IP bans
  2. Captions: download | YouTube Data API

Spot something wrong? Tell us.