Guides · YouTube Transcript Scraper · Published July 4, 2026

Why the YouTube Data API won't give you transcripts (and what actually works)

The captions.download endpoint requires OAuth from the video's owner, so the official YouTube Data API cannot download transcripts for arbitrary public videos. Why that is, and which alternatives work.

By slvDev · Updated and technically verified July 11, 2026


The short answer: the YouTube Data API technically has caption endpoints, but captions.download requires OAuth authorization from the channel that owns the video. An API key is not enough. That means the official API can export captions from your own uploads, and cannot download transcripts for arbitrary public videos, which is what almost everyone asking this question wants. Below is exactly where the wall is, and what works instead.

What the Data API actually offers for captions

The API surface looks promising at first: two endpoints, both OAuth-gated.

  • captions.list returns metadata about a video's caption tracks (language, type, last updated). Google's docs require OAuth scopes even for this call; an API key alone is not enough. And even authorized, it only tells you a transcript exists. It does not give you the text.
  • captions.download returns the actual caption track file. This is the one you want, and it is the one you can't have: per Google's own documentation, the API supports downloading a caption track only if the request is authorized by the owner of (or a party with edit permission on) the video it belongs to. Requests for videos you don't own fail with a permissions error, not a quota error.

So the pattern that seems obvious (enumerate videos, call captions.download on each) only ever works for a channel you can authenticate as. If you are building creator tooling for channel owners, the official API is the right choice and this article ends here for you. For everyone else, it is a dead end by design.

The quota makes it worse, not better

Even in the cases where the official route works, the default quota is 10,000 units per project per day, and caption operations are priced steeply against it: per Google's quota cost table, a captions.list call costs 50 units and a captions.downloadcall costs 200. That is 200 list calls or 50 downloads and your day's quota is gone. Quota increases require an application and review. For anything shaped like "process thousands of videos," the arithmetic fails before the permissions do.

What people try next (and how it goes)

  • The unofficial timedtext endpoint.YouTube's player fetches captions from an internal endpoint, and you can imitate it. It works until it changes without notice, demands proof-of-origin tokens, or blocks your IP range. Fine for a weekend script; a maintenance treadmill in production.
  • Open-source libraries (like Python's youtube-transcript-api) wrap that same internal surface with a nicer API. Excellent for prototypes and low volume from residential IPs; use them for that. Deployed to the cloud, they inherit the IP-blocking problem: the library's own README documents that YouTube blocks requests from cloud-provider IPs and recommends rotating residential proxies for production use. Full code and trade-offs in our Python transcript guide.
  • Headless browsers. Loading the watch page in Playwright and scraping the transcript panel works, at a far higher compute cost per video, and the anti-bot fight comes to you anyway.
  • Speech-to-text on the audio. Downloading audio and running Whisper sidesteps captions entirely, at meaningful GPU cost per video, minutes of latency, and its own audio-download fragility. Worth it only when videos have no captions at all.

What works for arbitrary public videos at scale

The remaining option is a managed extractor: a service whose whole job is keeping the caption path working (proxies, retries, format changes) and selling the result per delivered transcript. That is what our YouTube Transcript Scraper is: send up to 50 video IDs, get time-coded JSON back, $3.00 per 1,000 delivered transcripts on your existing Apify account. No Google Cloud project, no OAuth consent screen, no quota application.

The design decision that matters for pipelines is the failure contract: a video with no captions, an unplayable ID, or an upstream stall comes back as a success: false row with a stable machine-readable code (NO_CAPTIONS, PLAYABILITY, DEADLINE_EXCEEDED) in the same dataset, free, without failing the run. One bad video never costs you the batch.

import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("apihq/youtube-transcript-scraper").call(
    run_input={"videoIds": ["jNQXAC9IVRw", "dQw4w9WgXcQ"]}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item["success"]:
        print(item["video_id"], len(item["transcript"]), "segments")
    else:
        print(item["video_id"], "->", item["code"])   # not billed

The limits, whatever route you pick

  • Every caption-based method, official or not, reads tracks that already exist. A video with no captions returns nothing everywhere; only speech-to-text can fill that gap.
  • Auto-generated (ASR) tracks carry YouTube's recognition errors. For most search, RAG, and analysis workloads they are plenty; for legal-grade accuracy they are not.
  • Private, members-only, and age-gated videos are out of reach for every method that doesn't own the video.

The decision in one table

You are…Use
Exporting captions from your own channelYouTube Data API (captions.download with owner OAuth)
Prototyping locally, low volumeyoutube-transcript-api, free
Running an unattended pipeline on arbitrary public videosA managed pay-per-result extractor like the YouTube Transcript Scraper
Processing videos that have no captions at allSpeech-to-text (Whisper or similar) on the audio

A fuller dimension-by-dimension version of this decision — with every Data API claim linked to Google's documentation — is in the captions-endpoints comparison.


Deploying this?

Run one input on the YouTube Transcript Scraper. It comes back as either a billed transcript row or an unbilled, typed failure row — the contract this guide builds on.

A one-item first run costs under a cent, on your existing Apify account.