YouTube transcript API: get transcripts without the official API
How to get the transcript of any public YouTube video as JSON, with timestamps and language selection, without OAuth or quota units. Code in cURL, Node.js and Python, plus tips for LLM pipelines.
By the Scrape Everything team · · 4 min read
Transcripts turn video into text you can search, summarize, translate and feed into language models. For many teams building AI features, YouTube is the largest source of spoken content they want to work with. The catch: getting transcripts programmatically through official channels is surprisingly awkward.
This post explains why, what a transcript API returns, and how to fetch transcripts of public videos with one request using the YouTube Transcript API.
Why the official YouTube Data API is not enough
The YouTube Data API has a captions resource, but it is built for channel owners managing their own captions. Downloading caption tracks requires OAuth authorization, and in practice you can only download captions for videos you have permission to edit. For a video on someone else's channel, which is what research, summarization and RAG use cases need, the official route usually does not work.
The Data API also uses a daily quota measured in units, with different costs per operation. That is fine for metadata lookups at small scale, but it adds planning overhead when your workload grows. Check Google's current documentation for the exact quota rules, as they change over time.
What a transcript endpoint returns
Most YouTube videos have captions: either uploaded by the creator or generated automatically by YouTube's speech recognition. The transcript endpoint reads these public caption tracks and returns them in a structured form:
text: the whole transcript joined into plain text, ready to send to an LLM.segments: an array of{ start, duration, text }items, so you can link back to the exact moment in the video.languageandlanguage_name: the caption track that was used.is_auto_generated: whether the track is YouTube's automatic speech recognition or creator-provided captions.available_languages: every caption track on the video, so you can request a specific one.
Fetching a transcript
Send the video URL. Any common form works: watch?v= links, youtu.be short links, Shorts, live and embed URLs, or the bare 11-character video ID.
curl -X POST https://api.scrapeeverything.com/v1/youtube/transcript \
-H "Authorization: Bearer $SCRAPEEVERYTHING_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.youtube.com/watch?v=VIDEO_ID"}'{
"success": true,
"data": {
"video_id": "VIDEO_ID",
"language": "en",
"language_name": "English",
"is_auto_generated": false,
"available_languages": [
{ "code": "en", "name": "English", "is_auto_generated": false },
{ "code": "de", "name": "German", "is_auto_generated": true }
],
"segment_count": 412,
"text": "Welcome back to the channel. Today we are looking at ...",
"segments": [
{ "start": 0.0, "duration": 3.2, "text": "Welcome back to the channel." }
]
},
"meta": { "credits_charged": 1, "cached": false }
}By default you get the video's original language. Pass lang (for example en, de, pt-BR or es-419) to choose another track from available_languages.
Node.js: transcript to summary
A common pipeline fetches the transcript, splits it into chunks that fit your model's context window and summarizes each chunk. The transcript part is a single call:
async function getTranscript(url, lang) {
const res = await fetch("https://api.scrapeeverything.com/v1/youtube/transcript", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SCRAPEEVERYTHING_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ url, ...(lang ? { lang } : {}), cache_days: 14 }),
signal: AbortSignal.timeout(90_000),
});
const body = await res.json();
if (!body.success) throw new Error(`${body.code}: ${body.message}`);
return body.data;
}
const { text, segments } = await getTranscript("https://youtu.be/VIDEO_ID");
// Chunk by segments so every chunk keeps its start time for citations
const chunks = [];
let current = { start: 0, text: "" };
for (const s of segments) {
if (current.text.length > 6000) {
chunks.push(current);
current = { start: s.start, text: "" };
}
current.text += s.text + " ";
}
chunks.push(current);
console.log(chunks.length, "chunks ready for your LLM");Transcripts of a published video rarely change, so cache_days: 14 is a safe default: if you or your users request the same video again within two weeks, the repeat request costs 0 credits.
Python: build a searchable index
import os
import requests
def get_transcript(url: str, lang: str | None = None) -> dict:
body = {"url": url, "cache_days": 14}
if lang:
body["lang"] = lang
res = requests.post(
"https://api.scrapeeverything.com/v1/youtube/transcript",
headers={"Authorization": f"Bearer {os.environ['SCRAPEEVERYTHING_API_KEY']}"},
json=body,
timeout=90,
)
payload = res.json()
if not payload["success"]:
raise RuntimeError(f"{payload['code']}: {payload['message']}")
return payload["data"]
data = get_transcript("https://www.youtube.com/watch?v=VIDEO_ID")
for seg in data["segments"][:5]:
minutes, seconds = divmod(int(seg["start"]), 60)
print(f"[{minutes:02d}:{seconds:02d}] {seg['text']}")Store each segment with its start time and the video ID. When a search hit comes back, you can link to https://www.youtube.com/watch?v=VIDEO_ID&t=123s and jump straight to the moment.
Transcripts for a whole channel
To process a channel, combine two endpoints: the YouTube videos endpoint lists a channel's latest uploads (up to 30 per request), then the transcript endpoint runs once per video. For topic research across channels, the YouTube search endpoint finds videos by keyword.
- Call
/v1/youtube/videoswith the channel handle to get video IDs. - Queue the IDs and fetch transcripts with a few parallel workers.
- Skip videos that return no captions and log them separately.
Auto-generated vs creator captions
Auto-generated captions are good enough for summarization, topic detection and search, but they contain recognition errors, especially with names, technical terms and accents. They usually also lack punctuation. If accuracy matters (quotes, subtitles, legal review), prefer tracks where is_auto_generated is false, and show users that a transcript is machine-generated when it is.
Edge cases to handle
- No captions. Some videos have no caption track at all, for example very new uploads where automatic captions are not ready yet, music videos, or videos where the creator turned captions off. Treat this as a normal outcome, log the video ID and move on; retrying immediately will not help, but trying again a day later sometimes does for fresh uploads.
- Wrong language. If you request a
langthe video does not have, checkavailable_languagesand pick the closest match, such aseninstead ofen-GB. - Live streams and premieres. Captions for live content usually appear only after the stream has ended and been processed.
- Age-restricted or removed videos. These return an error code instead of data. Removed videos will not come back, so mark them as gone.
- Very long videos. Multi-hour streams produce very long transcripts. Chunk by segment start times, as in the Node.js example, rather than by character count alone, so each chunk stays linked to a point in the video.
Whatever the outcome, store the meta.request_id of each call. If a result looks wrong, that ID lets support trace exactly what happened.
What it costs
A transcript request costs 1 credit, regardless of video length. Failed requests (for example when YouTube blocks a request) are refunded automatically. With the Builder pack, 1,000 transcripts cost about $1.56; with the Scale pack, about $0.90. New accounts get 100 free credits. Current numbers are on the pricing page.
Beyond YouTube
Short-form video has transcripts too. The TikTok Transcript API returns timestamped captions of TikTok videos in the same shape, so one pipeline can handle both.
A note on rights
Transcripts are the creator's content. Using them to analyze, search or summarize is a very different thing from republishing them. Keep copyright in mind when you display transcript text to your users, and read our overview of the legal questions (not legal advice).