There are three practical ways to retrieve YouTube transcripts in Python:
- Use
youtube-transcript-apifor a local, open-source path. - Use the official YouTube Data API for captions on videos you manage.
- Use a managed API such as Stophy for public-video transcripts in deployed applications.
The code is short in all three cases. The difference is authorization, cloud networking, maintenance, and what happens when a video has no accessible caption track.
Updated July 2026. This guide was checked against the current library README, Google documentation, and Stophy code. It does not claim a controlled latency or reliability benchmark.
Quick comparison
| Path | API key | Third-party public videos | Cloud deployment | Main tradeoff |
|---|---|---|---|---|
youtube-transcript-api | No | Yes, when captions are accessible | May need rotating residential proxies | You own upstream changes and blocking |
| YouTube Data API v3 | Google key and OAuth | Not as a general transcript service | Official Google infrastructure | Caption download requires permission to edit the video |
| Stophy | Stophy API key | Yes, when captions are accessible | Hosted API | Paid credits; YouTube only |
If you only need a laptop script, start with the open-source library. If you manage the source channel, use Google's captions API. If you need public transcripts from a deployed agent or service, test a managed API against your workload.
What a transcript response should contain
A useful transcript result has more than one text string. Keep these fields:
- the full joined text for summarization;
- timestamped segments for citations and retrieval;
- the language code;
- whether the track was manual or auto-generated;
- available tracks or a clear error when captions do not exist.
No caption-based method can promise a transcript for every video. Private, deleted, restricted, unavailable, or uncaptioned videos can fail.
Way 1: youtube-transcript-api
youtube-transcript-api is an MIT-licensed Python library. It does not require a Google API key or a headless browser.
Install it:
$ pip install youtube-transcript-apiFetch a transcript by video ID:
from youtube_transcript_api import YouTubeTranscriptApi
# "Mastering Claude Code in 30 minutes" by Anthropic
transcript = YouTubeTranscriptApi().fetch("6eBSHbLKuN0")
for snippet in transcript:
print(f"{snippet.start:.1f}s {snippet.text}")Pass a preference-ordered language list:
transcript = YouTubeTranscriptApi().fetch(
"6eBSHbLKuN0",
languages=["de", "en"],
)List the available tracks before selecting one:
api = YouTubeTranscriptApi()
tracks = api.list("6eBSHbLKuN0")
for track in tracks:
print(track.language_code, track.is_generated, track.is_translatable)Translate a track when YouTube offers the target language:
english = tracks.find_transcript(["en"])
german = english.translate("de").fetch()The library also includes formatters for JSON, text, WebVTT, SRT, and CSV.
Deployment limits
The project README documents two limits that matter in production.
First, YouTube blocks many IP addresses associated with cloud providers. A deployment can raise RequestBlocked or IpBlocked even when the same code works from a residential connection. The library supports Webshare and generic proxy configuration, and recommends rotating residential proxies for this case.
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api.proxies import WebshareProxyConfig
api = YouTubeTranscriptApi(
proxy_config=WebshareProxyConfig(
proxy_username="YOUR_USERNAME",
proxy_password="YOUR_PASSWORD",
)
)
transcript = api.fetch("6eBSHbLKuN0")Second, cookie authentication for age-restricted videos is currently unavailable because upstream changes broke the implementation.
The library uses an undocumented interface called by YouTube's web client. That keeps setup simple, but YouTube can change the interface without the guarantees of an official API.
Choose this path when local control matters and you are prepared to own proxies, retries, monitoring, and upgrades.
Way 2: the official YouTube Data API
Google's API has two relevant methods:
captions.listlists caption-track metadata. It costs 50 units and does not return caption text.captions.downloaddownloads a caption file. It costs 200 units and requires OAuth plus permission to edit the video.
That makes the official path suitable for channels and videos you manage. It is not a general transcript endpoint for arbitrary public videos.
Install the Google client packages:
$ pip install google-api-python-client google-auth-oauthlibA complete OAuth flow depends on whether you are building a local application, web application, or service that stores user tokens. After you have an authorized YouTube client, the caption workflow is:
# youtube is an authorized googleapiclient YouTube service.
tracks = youtube.captions().list(
part="id,snippet",
videoId="6eBSHbLKuN0",
).execute()
caption_id = tracks["items"][0]["id"]
request = youtube.captions().download(
id=caption_id,
tfmt="vtt",
)
with open("captions.vtt", "wb") as output:
output.write(request.execute())Do not use an API key alone for this example. Both caption methods require authorization scopes, and the download requires sufficient permission on the video.
In the current quota model, search.list has a separate default bucket of 100 calls per day. Most other methods share 10,000 units per day. Caption listing and download therefore consume the shared pool.
Choose this path when you own or administer the videos and need Google's supported caption-management workflow.
Way 3: Stophy
Stophy is a managed YouTube API. Its Python SDK returns full text and timestamped segments from public videos without requiring the caller to own the source video.
Install the SDK:
$ pip install stophySet the API key outside source control:
$ export STOPHY_API_KEY="st_YOUR_API_KEY"Fetch a transcript:
import os
from stophy import Stophy
stophy = Stophy(os.environ["STOPHY_API_KEY"])
result = stophy.video(
type="transcript",
video_url="https://www.youtube.com/watch?v=6eBSHbLKuN0",
)
print(result["data"]["text"])
for segment in result["data"]["segments"]:
print(f"{segment['start']:.1f}s {segment['text']}")Request a language with the lang argument:
result = stophy.video(
type="transcript",
video_url="https://www.youtube.com/watch?v=6eBSHbLKuN0",
lang="de",
)
print(result["data"]["language"])
print(result.get("warning"))If the requested language has no native track, Stophy can return a machine translation of the default track and includes a top-level warning. Inspect the response instead of assuming the result is a native caption.
The equivalent HTTP request is:
$ curl -X POST https://api.stophy.dev/v1/video \
-H "Authorization: Bearer $STOPHY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"videoUrl": "https://www.youtube.com/watch?v=6eBSHbLKuN0",
"type": "transcript"
}'The same client covers related agent workflows:
# Search
results = stophy.search(
q="claude code tutorial",
sort_by="popularity",
)
# Channel videos
channel = stophy.channel(
channel_url="https://www.youtube.com/@mkbhd",
tab="video",
)
# Comments
comments = stophy.video(
type="comments",
video_url="https://www.youtube.com/watch?v=6eBSHbLKuN0",
)
# Live chat or replay when available
chat = stophy.video(
type="livechat",
video_url="https://www.youtube.com/watch?v=LIVE_ID",
)The SDK requires Python 3.9 or later. Every successful call uses the same response envelope: success, requestId, cacheState, creditsUsed, creditsRemaining, optional warning, and data.
New accounts receive 100 credits without a card. Paid packs are $9 for 3,000 credits, $25 for 10,000, $70 for 50,000, and $200 for 200,000. Credits do not expire. Failed requests are refunded.
Limits
Stophy only covers YouTube. It does not generate a transcript from video audio when no accessible caption track exists. A hosted API also adds network latency and vendor dependence compared with a local library.
Choose this path when your deployed application needs public-video transcripts and you do not want proxy configuration in the application.
Handle failures explicitly
Whichever path you choose, treat missing transcripts as expected data rather than an exceptional surprise.
from typing import Optional
def transcript_text(result: dict) -> Optional[str]:
data = result.get("data") or {}
text = data.get("text")
return text if isinstance(text, str) and text.strip() else NoneAt minimum, distinguish:
- invalid video IDs or URLs;
- private, deleted, restricted, or unavailable videos;
- captions disabled or no caption track;
- requested language unavailable;
- rate limits or quota exhaustion;
- proxy or IP blocking on self-managed scrapers;
- authentication and credit errors on managed APIs.
Do not retry every failure. A missing caption track is not transient. A rate limit may be. Preserve the provider's error code and request ID so you can tell the difference.
Batch a playlist without losing progress
For a playlist workflow, retrieve the video list first and checkpoint after every transcript. This avoids restarting the whole job after one unavailable video.
from pathlib import Path
import json
from stophy import StophyError
playlist = stophy.playlist(
playlist_url="https://www.youtube.com/playlist?list=PLAYLIST_ID",
)
output = Path("transcripts.jsonl")
with output.open("a", encoding="utf-8") as file:
for video in playlist["data"]["items"]:
try:
result = stophy.video(
type="transcript",
video_url=video["videoUrl"],
)
record = {
"videoId": video["id"],
"transcript": result.get("data"),
"warning": result.get("warning"),
}
except StophyError as error:
record = {
"videoId": video["id"],
"error": error.code,
"requestId": error.request_id,
}
file.write(json.dumps(record) + "\n")For large playlists, follow continuationToken pagination and add bounded concurrency. Check the credit balance before the job and keep the request ID for each result.
Which path should you choose?
- Use
youtube-transcript-apifor local scripts, experiments, or self-managed systems where you accept proxy work. - Use Google's captions API for videos you manage and official caption-file operations.
- Use Stophy for public-video transcript retrieval from a deployed application or agent that also needs YouTube discovery and context.
Do not migrate only because an open-source request failed once. First confirm whether the cause is an unavailable caption, a language mismatch, an IP block, or an upstream change. The fix depends on the failure.
Frequently asked questions
Is youtube-transcript-api free?
Yes. The library is MIT-licensed and has no API fee. A deployed workload may still pay for compute and rotating residential proxies when YouTube blocks the server's IP.
Why does it work locally but fail on a cloud VM?
The library documents that YouTube blocks many known cloud-provider IPs. Confirm the exact exception. RequestBlocked or IpBlocked points to the network path; a missing-transcript exception points to the video or language instead.
Does the YouTube Data API provide third-party transcripts?
Not as a general public endpoint. captions.download requires OAuth and permission to edit the video. Use it for videos you manage.
Can I retrieve translated captions?
Yes, when translation is available. youtube-transcript-api exposes YouTube's translation support on a transcript track. Stophy accepts lang; if it returns a machine-translated default track instead of a native track, the response includes a warning.
Can I use Stophy in AWS Lambda or Google Cloud Functions?
Yes. The Python SDK calls the hosted HTTP API and requires Python 3.9 or later. Store the API key in the platform's secret manager or environment configuration, not in source code.
Does Stophy support YouTube Music and YouTube Kids?
Yes. They are separate Stophy API and MCP operations under /v1/music and /v1/kids. They are not variants of the transcript endpoint.
Can I fetch every transcript in a playlist?
Yes, but plan for pagination and unavailable captions. Retrieve playlist items, checkpoint each video, and record failures instead of stopping the whole job.
Try the managed path
Create a Stophy account with 100 free credits, then run the same videos and languages you tested with the open-source library.
Related guides: YouTube transcript API comparison, YouTube Data API alternatives, and YouTube MCP servers.
Bias disclosure: This tutorial was written by the team behind Stophy. The open-source and Google paths are valid choices for the workloads described above. Stophy is included for the public-video, managed-infrastructure case it was built to serve.