For a video you own or manage, use the official YouTube Data API caption download, which requires OAuth authorization. For other public videos, the unofficial youtube-transcript-api package can read manually created and auto-generated captions when they exist, but it is not a service contract and its requests can fail or be blocked. Neither route gives you permission to get around YouTube’s restrictions. An LLM pipeline therefore has to treat missing or blocked captions as ordinary outcomes, keep timestamps and caption provenance, and check important conclusions against the video itself.
Decide the route by authorization first
The code you write matters less than two questions: who controls the video, and whether you have permission to process its captions. Work through these in order.
As an Amazon Associate I earn from qualifying purchases.
- Do you manage the video’s channel? If yes, use the Data API caption download described below. It is the only route in this list that YouTube itself documents as an authorized operation.
- Does the owner or rights holder give you a caption file? If yes, use that file and record where it came from.
- Are public captions available, and is your use permitted? If yes, a prototype can use
youtube-transcript-api, with the error handling described below. Check the terms that apply to your use before running it at volume. - Are there no accessible captions, but you are authorized to process the audio? Use local speech recognition on that audio and label the output as machine transcription.
- None of the above? Stop and seek permission. Changing your network identity or retrying until a block lifts is not a fallback.
Whether a particular use is permitted depends on your jurisdiction and the specifics of the use. The points here summarize published platform rules and are not legal advice.
| Route | Best fit | Main constraint | What to compare |
|---|---|---|---|
YouTube Data API captions.download |
Caption tracks for a video the caller is authorized to manage or access | OAuth scopes and permission. Not a universal endpoint for every public video. | Authorization, caption track ID, requested format, language, error handling |
youtube-transcript-api |
Prototypes and personal scripts where its supported retrieval path works | Unofficial; can break or be blocked. Not a compliance workaround. | Caption availability, language priority, timestamps, error handling, maintenance |
yt-dlp and related tools |
Broader media workflows that include subtitle handling | Tool capability does not confer rights or exempt use from platform terms | Subtitle availability, formats, scope of media handling, update cadence |
| Managed transcript provider | Production teams that prefer a vendor-managed service | Provider-specific terms, data handling, reliability and pricing need review | Supported cases, provenance of text, retention, rate limits, fallback and ASR behavior, contractual permissions |
| Local ASR on authorized audio | Videos with no accessible captions where you have rights to process the audio | Compute cost, transcription error, language and accent quality, audio access | Word error risk, timestamp accuracy, language support, cost, consent and rights |
Compare the routes on authorization, the source of the words (creator captions, YouTube auto-captions, translation, or new ASR output), languages, timestamp fidelity, blocking and reliability, scale, cost, privacy and retention, and fallback behavior. Treat any vendor claim that a service is “unblocked” as unverified until you have confirmed it for your own videos and volume.
#1 Best Overall
The official route: captions.download
The Data API works on caption tracks attached to a video, not on arbitrary URLs. The flow is to authorize with OAuth, list the caption tracks for a video with captions.list, and then download one track by its ID in a format such as SRT or VTT. The authenticated account must have permission over that video’s captions. If it does not, expect an authorization error rather than a transcript. Console labels below reflect the interface as of October 2026 and may change.
- In the Google Cloud console, select or create a project, then open APIs & Services > Library and enable the YouTube Data API v3.
- Open APIs & Services > OAuth consent screen and configure it for your application.
- Open APIs & Services > Credentials, choose Create credentials > OAuth client ID, and obtain user credentials through the standard installed-application flow.
- Request the scope named on the
captions.downloadreference page, and authorize with the account that manages the video’s channel. - List the tracks, then download the one you need.
from googleapiclient.discovery import build
youtube = build("youtube", "v3", credentials=creds)
tracks = youtube.captions().list(part="snippet", videoId=VIDEO_ID).execute()
for item in tracks.get("items", []):
snippet = item["snippet"]
print(item["id"], snippet["language"], snippet["trackKind"])
if not tracks.get("items"):
print("No caption track is available through this account.")
else:
caption_id = tracks["items"][0]["id"]
srt_bytes = youtube.captions().download(id=caption_id, tfmt="srt").execute()
The trackKind field tells you whether a track is an uploaded caption track or an ASR (machine-generated) track, so store it with the text. An empty items list means no track is available through that account, which is a different outcome from an authorization error.
The unofficial route: youtube-transcript-api
The project describes fetching manually created and auto-generated subtitles without an API key or a headless browser. That is why it is popular for prototypes. The trade-off is that it depends on caption access that YouTube does not offer as a documented contract for this purpose. A change on YouTube’s side can break it, and a block can stop it, so do not promise uptime to anyone who depends on the output.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsRank #2
from youtube_transcript_api import YouTubeTranscriptApi
ytt = YouTubeTranscriptApi()
track_list = ytt.list(video_id)
track = track_list.find_transcript(["en", "ja"]) # priority order
print(track.language_code, "auto-generated" if track.is_generated else "human-created")
for snippet in track.fetch():
print(snippet.start, snippet.text)
Language selection should always be explicit. The list you pass is a priority order, and a fallback to a language you did not intend will silently change what your model reads. Record language_code and is_generated with every transcript.
Handle each outcome as its own state
Captions being absent, a video being unavailable, and a request being blocked are three different situations with three different responses. Collapsing them into one generic failure makes batch jobs retry the wrong things.
from youtube_transcript_api import (
YouTubeTranscriptApi,
TranscriptsDisabled,
NoTranscriptFound,
VideoUnavailable,
IpBlocked,
RequestBlocked,
)
def get_segments(video_id, languages=("en",)):
ytt = YouTubeTranscriptApi()
try:
track = ytt.list(video_id).find_transcript(list(languages))
segments = [
{"start": s.start, "duration": s.duration, "text": s.text}
for s in track.fetch()
]
return {
"status": "ok",
"language": track.language_code,
"auto": track.is_generated,
"segments": segments,
}
except TranscriptsDisabled:
return {"status": "captions_disabled"}
except NoTranscriptFound:
return {"status": "no_track_in_language"}
except VideoUnavailable:
return {"status": "video_unavailable"}
except (IpBlocked, RequestBlocked):
return {"status": "blocked"}
- captions_disabled: final for that video. Do not retry. Route it to the owner-file or ASR path if you are authorized.
- no_track_in_language: record the languages that were tried. Try another language only if your application can use it.
- video_unavailable: the video may be removed, private or otherwise unavailable. Log and skip.
- blocked: stop the batch. Do not loop, and do not retry in parallel.
When requests are blocked
A block means YouTube is restricting automated access from the client it sees. Your script cannot establish from the outside exactly why a given request was refused, and the library’s own description of its method means it cannot promise that requests will succeed. A block is therefore a signal to change the route, not a problem to engineer around.
YouTube’s developer policy guidance is explicit on this point: “Your service can’t be specifically designed to allow you or your users to get around restrictions YouTube places on their channel” (Google for Developers, “Complying with YouTube’s Developer Policies”). The API terms also state that YouTube “may suspend or terminate your access to, or use of, any aspect of the YouTube API Services (including any credentials assigned to you or your API Client(s)), impose additional requirements and restrictions, or terminate the Agreement between you and YouTube, for any violation of the Agreement by you, your API Client(s) or those acting on your behalf” (YouTube API Services Terms of Service, section 3.1).
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →In practice, that rules out rotating proxies or network identities to get past a block, spoofing client identity, and running parallel retries across accounts. These are not compliant ways to avoid a block, even when a tool makes them easy to configure. The recovery sequence is:
- Stop the batch at the first blocked response.
- Record the affected video IDs and the time of the first block.
- Move those videos to an owner-supplied caption file, the Data API route if you manage the video, or authorized local ASR.
- Resume only the remaining jobs that still use an authorized route, at a pace a human has chosen.
Keep timestamps and source provenance from the start
Flattening transcripts into one string is the most common early mistake. Once timestamps are gone, a model’s answer cannot point back to the moment in the video it came from. Keep each segment as a record with the fields below.
- video_id: normalized from the input. Accept
watch?v=URLs,youtu.beshort links, and/shorts/and/embed/paths, then store only the ID. - start and duration: seconds from the beginning of the video, as returned by the caption source.
- text: the segment text, unmodified.
- language: the language code you requested and the language actually returned.
- source: one of
creator_caption,auto_caption,translated,owner_file, orasr. Never merge these silently. If a claim depends on machine-generated text, the source label should travel with it into the answer.
When captions are missing: owner files and local ASR
Owner-supplied caption files
Ask the owner for an SRT or VTT file rather than a plain text export, because the timing data is what makes citations possible. Check that the file matches the video version you are processing, since edited videos can drift from an older caption file.
Local speech recognition on audio you may process
Local ASR is a fallback for videos with no accessible captions, and only for audio you are entitled to use. Its output has its own error profile. Names, numbers, dates, drug or product names, and technical terms are the most likely to be wrong, so compare those against the original recording before you rely on them. Keep the segment timestamps the model emits, and label the whole transcript as asr.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Feed long transcripts to an LLM without losing the evidence
Split transcripts on segment boundaries, not at arbitrary character offsets, and overlap by a small number of segments so a sentence that spans a boundary is not cut in half. The function below is a starting point. Tune the size to your model’s context window and to the density of the speech.
Best Value
def chunk_segments(segments, max_chars=6000, overlap=2):
chunks, current, size, pending = [], [], 0, False
for seg in segments:
current.append(seg)
size += len(seg["text"])
pending = True
if size >= max_chars:
chunks.append(current)
current = current[-overlap:] if overlap else []
size = sum(len(s["text"]) for s in current)
pending = False
if pending:
chunks.append(current)
return chunks
def to_prompt_text(chunk, video_id):
lines = [f"Video: {video_id}"]
for seg in chunk:
minutes, seconds = divmod(int(seg["start"]), 60)
lines.append(f"[{minutes:02d}:{seconds:02d}] {seg['text']}")
return "n".join(lines)
Put the timestamps inside the text the model sees, and instruct it to cite them. A prompt skeleton that works with this format:
Answer using only the transcript excerpt below.
For each claim, give the timestamp where it is stated and quote no more than 20 words.
If the excerpt does not support a claim, say so.
Retrieval over segments can help locate candidate passages, but a top-k search can skip context that a conclusion depends on. It is not equivalent to reading the whole transcript. For a summary that will inform a decision, send the full transcript where it fits, or use a staged summary that keeps timestamps at every level.
What compression can change
A 2026 arXiv preprint on Japanese medical YouTube videos studied how transcript compression affected LLM-based misinformation classification. It found that summary and retrieval-augmented inputs made some institutional and technical language more prominent, while reducing affective, social, temporal, cognitive and conversational cues. That is a result for one language, one domain and one task. It does not show that every summarization task fails. It does show that a compressor’s choices are not neutral, so a summary cannot be assumed to keep every signal a downstream classifier relies on.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Check the output before anyone acts on it
For summaries and claims that will inform a decision, the model’s answer is a lead to verify rather than a finding. Build the checks into the pipeline:
Quick Recap
- Require a timestamp and a short quote for every factual claim, and reject answers that omit them.
- Open the cited moment of the video, or the owner’s transcript, and confirm the claim. Do this for names, figures and any statement that changes what someone will do.
- Where a claim rests on
auto_captionorasrtext, confirm it against the audio before publishing it as fact. - Log the status of every video (ok, disabled, unavailable, blocked, no track) so you can report coverage honestly.
- Review the terms and the authorization for each source before scaling the job.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




