YouTube Transcript & Subtitles Scraper
Pricing
from $2.10 / 1,000 transcripts
YouTube Transcript & Subtitles Scraper
Paste YouTube video URLs or IDs, channels, playlists or searches, in bulk. Get each transcript as plain text with timestamps, title, channel and date. At no extra cost: views, likes, tags, chapters, SRT and VTT subtitles, LLM text, RAG chunks by chapter. $3 per 1,000, videos without captions free.
Pricing
from $2.10 / 1,000 transcripts
Rating
0.0
(0)
Developer
Gautham Krishna
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
Get the transcript of any YouTube video as clean text, ready for an LLM, a RAG pipeline or a spreadsheet. Paste video URLs or IDs, a channel, a playlist or a search, pick a language, and get one row per video with the full transcript, timestamps and video details. Turn on SRT, VTT, plain-text, LLM-ready Markdown or RAG chunks split by YouTube chapters, at no extra cost.
You pay $3 per 1,000 transcripts ($0.003 each), and less on Apify Store discount tiers (Bronze, Silver, Gold), down to $2.10 per 1,000 on Gold. Videos that fail or have no captions are never charged.
At a glance
| Topic | Details |
|---|---|
| Input | YouTube video URLs or IDs (watch, youtu.be, Shorts, embed and live links), channels, playlists and search queries |
| Output | One JSON row per video: transcript as one plain-text string, segments with start times, plus title, channel, duration and language. Optional: views, likes, comments, tags, chapters, and SRT, VTT, plain-text, LLM-ready and RAG chunk formats |
| Price | $0.003 per transcript ($3 per 1,000), or $2.70 per 1,000 on Bronze, $2.40 on Silver and $2.10 on Gold. No start fee. Videos without captions and failed videos are free |
| Tested | Final test run on 16 Oct 2026 with every option on: 56 video links, 4 channels and playlists and 3 searches gave 88 videos, and all 87 that exist returned a transcript with every format, in 73 seconds |
| Limits | Reads YouTube's own captions and does not run speech-to-text, so a video with no captions returns a free no_transcript row. No cap on videos per run, 10 fetched in parallel by default |
Call it from Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("heyitsgautham/youtube-transcript-scraper").call(run_input={"videos": ["https://youtu.be/jNQXAC9IVRw"], "includeTimestamps": False})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row["status"], row.get("title"), row.get("transcript"))
Channels, playlists and search
Besides videos, two optional inputs add videos in bulk.
| Input | What it takes |
|---|---|
channelsAndPlaylists | Channel links in any form (@handle, /channel/UC..., /c/name, /user/name), playlist links with list=..., and bare @handles, UC... channel IDs or PL... playlist IDs. Channels go newest first |
searchQueries | YouTube searches, each giving its top videos in YouTube's order |
maxVideosPerSource | How many videos to take from each channel, playlist or search. Default 100, 0 means all, up to 20,000 |
includeShorts | Channels only. Off: regular videos and past live streams. On: every upload |
Rows from these sources also carry sourceType (channel, playlist or search), sourceId, sourceTitle and position, and input holds the channel, playlist or query you gave.
A video met twice in one run, in videos, in two sources or twice in one playlist, is fetched and charged once, for the first input that reaches it.
Inputs count in order, videos first, then channelsAndPlaylists, then searchQueries.
Each later copy is a free duplicate row whose duplicateOf names that first input.
Listing a channel, a playlist or a search is free, and you pay only for transcripts.
A channel or playlist that does not exist comes back as one free not_found row.
A channel or playlist link put in videos comes back as a free invalid_input row whose message points to channelsAndPlaylists.
What you get per video
| Field | What it holds |
|---|---|
status | ok, no_transcript, unavailable, invalid_input, duplicate or error |
title, channel, channelId, durationSeconds | Video details from the same request, at no extra cost |
publishedAt | Exact publish time in UTC, such as 2009-10-25T06:57:33Z. Empty in the rare case YouTube leaves it out |
language | Language of the returned transcript |
isAutoGenerated | true when the captions came from YouTube's speech recognition |
requestedLanguageFound | false when the video has no captions in your language, so you got the original ones |
transcript | The full transcript as one string |
wordCount | Words in the transcript |
segments | [{ "start": 12.4, "duration": 3.1, "text": "..." }], when timestamps are on |
Video details and output formats
Both are off by default and cost nothing extra. They ride in the same row, so a transcript is still one charge.
includeVideoDetails: true adds:
| Field | What it holds |
|---|---|
viewCount, likeCount | Exact counts at run time. likeCount can be empty when YouTube leaves it out |
commentCount | Exact comment count. Empty when comments are turned off, as on NASA's videos |
category | YouTube category, such as Education |
description | The video description. Emails and phone numbers in it are replaced with [email removed] and [phone removed] |
tags | The uploader's tags |
thumbnailUrl | The largest thumbnail YouTube returns |
chapters | [{ "title", "start", "end", "url" }] from the description's timestamps, by YouTube's rule: the list starts at 0:00 and has at least three rising entries. Each url opens the video at that chapter |
outputFormats takes any of these:
| Value | Adds | What it holds |
|---|---|---|
text | plainText | The captions as paragraphs, one per line, split at pauses of 2 seconds or more and after about 120 words |
llm | llmText | Markdown for an LLM: title, channel, date, URL, duration and caption type on top, a heading per chapter, a [m:ss] stamp per paragraph, and sound cues such as [Music] removed |
srt | srt | The SubRip subtitle file as text |
vtt | vtt | The WebVTT subtitle file as text |
chunks | chunks | RAG chunks: one per YouTube chapter, with long chapters split evenly, or even pieces when the video has no chapters. Each has index, chapter, start, end, wordCount, text and a url that opens the video at that second |
chunkSizeWords sets the chunk size, 300 words by default.
Chunks are cut between caption lines, so one can run a little over.
In the final test the largest of 1,938 chunks held 319 words.
34 of the 87 videos had chapters.
Input
{"videos": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ","https://youtu.be/jNQXAC9IVRw","https://www.youtube.com/shorts/aqz-KE-bpKQ","M7lc1UVf-VE"],"language": "en","includeTimestamps": true}
The scraper accepts watch, youtu.be, Shorts, embed and live links, plus bare 11-character IDs.
How language works
- Human-made captions in your language come first.
- Then YouTube's auto-generated captions in your language.
- If neither exists, you get the video's original captions, and the row shows
requestedLanguageFound: false.
Output example
This is real output for the input above, from a run on 15 Oct 2026.
The segments array is cut to two entries here.
{"input": "https://youtu.be/jNQXAC9IVRw","videoId": "jNQXAC9IVRw","url": "https://www.youtube.com/watch?v=jNQXAC9IVRw","status": "ok","publishedAt": "2005-04-24T03:31:52Z","title": "Me at the zoo","channel": "jawed","channelId": "UC4QobU6STFB0P71PMvOGN5A","durationSeconds": 19,"language": "en","requestedLanguageFound": true,"isAutoGenerated": false,"transcript": "All right, so here we are, in front of the elephants the cool thing about these guys is that they have really... really really long trunks and that's cool (baaaaaaaaaaahhh!!) and that's pretty much all there is to say","wordCount": 39,"segments": [{ "start": 1.2, "duration": 2.16, "text": "All right, so here we are, in front of the elephants" },{ "start": 5.318, "duration": 2.656, "text": "the cool thing about these guys is that they have really..." }]}
Big Buck Bunny in the same input has no captions, so its row comes back as "status": "no_transcript" and costs nothing.
Output example with every option on
This row comes from the final test run on 16 Oct 2026, with searchQueries: ["how transformers work", ...], maxVideosPerSource: 5, includeVideoDetails: true and outputFormats: ["text", "llm", "srt", "vtt", "chunks"].
Long strings are cut and marked with ..., segments, srt, vtt and llmText are left out, and the arrays are cut.
The real row has 17 tags, 4 chapters and 4 chunks.
{"input": "how transformers work","sourceType": "search","sourceId": "how transformers work","sourceTitle": "how transformers work","position": 3,"videoId": "7RtBUEZbKmI","url": "https://www.youtube.com/watch?v=7RtBUEZbKmI","status": "ok","publishedAt": "2020-04-01T10:00:07Z","title": "GCSE Physics - How Transformers Work (2026/27 exams)","channel": "Cognito","channelId": "UCaGEe4KXZrjou9kQx6ezG2w","durationSeconds": 259,"language": "en","requestedLanguageFound": true,"isAutoGenerated": true,"transcript": "before we look at exactly how transformers work let's very quickly recap how they're used in the nat ...","wordCount": 578,"viewCount": 607042,"likeCount": 9232,"commentCount": 393,"category": "Education","description": "⭐️ Check out our website https://www.cognito.org/ ⭐️\n\n*** WHAT'S COVER ...","tags": ["transformers", "step-up", "step-down"],"thumbnailUrl": "https://i.ytimg.com/vi/7RtBUEZbKmI/sddefault.jpg","chapters": [{ "title": "Intro & Role in National Grid", "start": 0, "end": 67, "url": "https://www.youtube.com/watch?v=7RtBUEZbKmI&t=0s" },{ "title": "Transformer Structure", "start": 67, "end": 84, "url": "https://www.youtube.com/watch?v=7RtBUEZbKmI&t=67s" }],"plainText": "before we look at exactly how transformers work let's very quickly recap how they're used in the nat ...","chunks": [{"index": 0,"chapter": "Intro & Role in National Grid","start": 0,"end": 65.52,"wordCount": 145,"text": "before we look at exactly how transformers work let's very quickly recap how they're used ...","url": "https://www.youtube.com/watch?v=7RtBUEZbKmI&t=0s"}]}
The start of the same row's llmText:
# GCSE Physics - How Transformers Work (2026/27 exams)Channel: CognitoPublished: 2020-04-01T10:00:07ZURL: https://www.youtube.com/watch?v=7RtBUEZbKmIDuration: 4:19Captions: en, auto-generated## Intro & Role in National Grid [0:00][0:04] before we look at exactly how transformers work let's very quickly recap how they're used in the national grid ...
And of its srt:
100:00:04,799 --> 00:00:06,319before we look at exactly how200:00:06,319 --> 00:00:07,759transformers work
Use it from AI agents
The scraper works as a tool through the Apify MCP server in Claude, Cursor, VS Code and other MCP clients. Agents can pass a list of video URLs, a channel or a search and get back plain text they can summarise, quote or index, or chapter chunks with links they can cite. Each call charges only for the transcripts it returns.
You can also call it through the Apify API or the Python and JavaScript clients, and schedule it or connect it to Make, Zapier and n8n.
Pricing
Prices are per 1,000 transcripts.
| Event | No discount | Bronze | Silver | Gold |
|---|---|---|---|---|
| Transcript returned | $3 | $2.70 | $2.40 | $2.10 |
| Video unavailable, no captions, invalid input or failed fetch | Free | Free | Free | Free |
| Listing a channel, playlist or search, video details and output formats | Free | Free | Free | Free |
Bronze, Silver and Gold are Apify Store discount tiers, and Apify's Pricing tab shows them as Starter, Scale and Business. Apify decides which tier an account is on.
Set a maximum cost per run in the run options. The scraper stops once that limit is reached.
FAQ
Why does a video show no_transcript?
The uploader turned captions off and YouTube made no auto-generated ones.
That row isn't charged.
Does it work for Shorts and live streams? Yes, if the video has captions. Live streams get captions after they end.
Does it use the official YouTube API? No. It reads the same caption data the YouTube app shows. Only use transcripts in ways that respect the rights of the video owners.
What about videos with no captions at all? Speech-to-text for those is on the roadmap. Open an issue on the Issues tab if you need it.