YouTube Transcript & Subtitles Scraper avatar

YouTube Transcript & Subtitles Scraper

Pricing

from $2.10 / 1,000 transcripts

Go to Apify Store
YouTube Transcript & Subtitles Scraper

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

Gautham Krishna

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

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

TopicDetails
InputYouTube video URLs or IDs (watch, youtu.be, Shorts, embed and live links), channels, playlists and search queries
OutputOne 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
TestedFinal 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
LimitsReads 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 ApifyClient
client = 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"))

Besides videos, two optional inputs add videos in bulk.

InputWhat it takes
channelsAndPlaylistsChannel 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
searchQueriesYouTube searches, each giving its top videos in YouTube's order
maxVideosPerSourceHow many videos to take from each channel, playlist or search. Default 100, 0 means all, up to 20,000
includeShortsChannels 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

FieldWhat it holds
statusok, no_transcript, unavailable, invalid_input, duplicate or error
title, channel, channelId, durationSecondsVideo details from the same request, at no extra cost
publishedAtExact publish time in UTC, such as 2009-10-25T06:57:33Z. Empty in the rare case YouTube leaves it out
languageLanguage of the returned transcript
isAutoGeneratedtrue when the captions came from YouTube's speech recognition
requestedLanguageFoundfalse when the video has no captions in your language, so you got the original ones
transcriptThe full transcript as one string
wordCountWords 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:

FieldWhat it holds
viewCount, likeCountExact counts at run time. likeCount can be empty when YouTube leaves it out
commentCountExact comment count. Empty when comments are turned off, as on NASA's videos
categoryYouTube category, such as Education
descriptionThe video description. Emails and phone numbers in it are replaced with [email removed] and [phone removed]
tagsThe uploader's tags
thumbnailUrlThe 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:

ValueAddsWhat it holds
textplainTextThe captions as paragraphs, one per line, split at pauses of 2 seconds or more and after about 120 words
llmllmTextMarkdown 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
srtsrtThe SubRip subtitle file as text
vttvttThe WebVTT subtitle file as text
chunkschunksRAG 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

  1. Human-made captions in your language come first.
  2. Then YouTube's auto-generated captions in your language.
  3. 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: Cognito
Published: 2020-04-01T10:00:07Z
URL: https://www.youtube.com/watch?v=7RtBUEZbKmI
Duration: 4:19
Captions: 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:

1
00:00:04,799 --> 00:00:06,319
before we look at exactly how
2
00:00:06,319 --> 00:00:07,759
transformers 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.

EventNo discountBronzeSilverGold
Transcript returned$3$2.70$2.40$2.10
Video unavailable, no captions, invalid input or failed fetchFreeFreeFreeFree
Listing a channel, playlist or search, video details and output formatsFreeFreeFreeFree

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.