YouTube Transcript Scraper
Pricing
from $6.50 / 1,000 transcript scrapeds
YouTube Transcript Scraper
Extract YouTube transcripts with millisecond timestamps. Give it a video, a channel, a playlist or a search keyword and get raw caption segments plus merged paragraphs, ready for RAG, search and analysis. Incremental mode skips videos you already have, so a scheduled run does not bill you twice.
Pricing
from $6.50 / 1,000 transcript scrapeds
Rating
0.0
(0)
Developer
Mehmet
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
Give this Actor a YouTube video, Shorts, channel or playlist link — or just a search keyword —
and it returns the spoken content as structured, timestamped text: the raw caption lines
exactly as YouTube serves them, plus merged paragraphs ready for embedding. No browser
automation, no cookies, no yt-dlp binary to maintain.
This Actor is an independent, third-party tool. It is not affiliated with, endorsed by, or sponsored by YouTube or Google LLC. YouTube and the YouTube logo are trademarks of Google LLC.
What makes this different
Most transcript scrapers charge you again for every video, every run. This one remembers what it already fetched.
Incremental mode is on by default. A video that was scraped in an earlier run is skipped and not charged. If you track channels on a schedule, this is where the actual bill is decided:
| Tracking 20 channels daily, 30 videos each | Transcripts billed per month |
|---|---|
| A scraper without deduplication | 18,000 |
| This Actor, incremental mode on | 660 |
That is 27× fewer billed units for the same coverage, assuming each channel publishes around three new videos a month. The ratio is the point: it holds whatever the two unit prices happen to be.
This applies to recurring runs. For a single one-off bulk scrape where every video is new, a cheaper per-unit actor will cost you less. Pick the tool that matches your job.
Three more things you get here:
- Paragraphs, not just caption fragments. Raw captions arrive as 2-second
snippets.
chunkSecondsmerges them into timestamped paragraphs that are ready to embed. SetchunkBytochapterand the split follows the video's own chapters when it has them. - Human-written captions preferred.
preferManualpicks the human transcript over the auto-generated one when both exist. Auto captions have no punctuation and need cleaning before they are useful. - Translate the transcript. Set
translateToto a language code and the transcript comes back in that language, using YouTube's own translation — no extra request, no extra charge. Every video supports a different set of translation languages; if yours doesn't offer the one you asked for, you still get the original transcript plus a warning listing what it does support, andtranslatedToon the record tells you at a glance whether the translation actually happened.
Check the cost before you spend it
Turn on Preview only and the actor lists every video it would scrape, how many were already fetched in an earlier run, and how many would actually be charged — without fetching a single transcript.
Preview makes no transcript charges. The Apify actor start event is still billed, because the platform charges it before this actor runs. There is no way for any actor to suppress it.
Judging transcript quality in bulk
Every record carries a transcriptQuality block so you can filter before you
ingest:
| Field | Use it to |
|---|---|
coverageRatio | Drop videos where captions cover only part of the video |
wordCount, wordsPerMinute | Spot near-empty or broken transcripts |
hasPunctuation | Decide which transcripts need cleaning first |
isAutoGenerated | Prefer human-written text when you have a choice |
Output formats
outputFormat adds a ready-to-use string to each record: text, srt or
vtt. Segments, paragraphs and metadata are always included as well — you
never have to choose between a subtitle file and structured data.
Chapters
When a video's description contains a proper chapter list, chapters is filled
in and chunkBy: chapter splits paragraphs on those boundaries. Many videos do
not have one; in our sample only about a quarter did. When there is no chapter
list the actor falls back to fixed-length paragraphs.
What does YouTube Transcript Scraper do?
Paste any mix of links into YouTube URLs and get back one dataset record per video: title,
channel, and thumbnail, plus duration, view count, publish date, and the transcript when
Include transcript is on. Video and Shorts links are scraped directly; channel and playlist
links (@handle, /channel/UC..., or list=...) are expanded into their videos automatically,
up to a configurable cap. No link handy? Use Search keywords instead and the Actor searches
YouTube for you — no URL needed. Every record carries inputUrl, so you always know which
source produced it, even when several sources are mixed in one run.
Transcripts come in two forms. segments are the caption lines exactly as YouTube's track
returns them. chunks merge those lines into paragraph-length blocks, split at sentence
boundaries for human-written captions and at pause gaps for auto-generated ones. Every chunk
and segment carries a millisecond startMs.
Click Start to see it run against two known-good example videos — no setup required.
Sample output
Most of this record is copied from a real run of this Actor (Run mG13RBc8ty3X2ltoN, dataset
k4Jj0ETl2bDe7h5cw). To respect copyright, most segments and all chunks text are
collapsed below. Six fields — inputUrl, description, keywords, chapters,
transcriptQuality and translatedTo — were added to the schema after that run and are shown
here with illustrative example values rather than that run's actual data; transcriptFormatted
is genuinely null below because outputFormat defaults to json, and translatedTo is
genuinely null because no translation was requested.
{"videoId": "arj7oStGLkU","url": "https://www.youtube.com/watch?v=arj7oStGLkU","inputUrl": "https://www.youtube.com/watch?v=arj7oStGLkU","title": "Inside the Mind of a Master Procrastinator | Tim Urban | TED","channelName": "TED","channelUrl": "https://www.youtube.com/@TED","thumbnailUrl": "https://i.ytimg.com/vi/arj7oStGLkU/hqdefault.jpg","durationSeconds": 844,"viewCount": 61678070,"publishedAt": "2016-04-06T16:59:35.000Z","description": "/* the video's own description text, truncated */","keywords": ["TED", "TEDTalk", "..." /* illustrative, truncated */],"language": "en","isAutoGenerated": false,"availableLanguages": ["ar", "hy", "bg", "..." /* 49 total, truncated */],"segments": [{ "startMs": 12645, "durationMs": 1370, "text": "So in college," }// 314 more segments — truncated for this README],"chunks": [{ "startMs": 12645, "endMs": 50900, "text": "/* 608-char merged paragraph, truncated */", "language": "en", "isAutoGenerated": false }// 21 more chunks — truncated for this README],"nonSpeechEvents": [],"chapters": [],"transcriptAvailable": true,"transcriptQuality": {"coverageRatio": 0.97,"wordCount": 2180,"wordsPerMinute": 155,"hasPunctuation": true},"transcriptFormatted": null,"scrapedAt": "2026-08-10T19:15:12.912Z","translatedTo": null,"contentHash": "ba594315dc2da412ed55e0ae1e6610be77895fa6e08e6c1bf63c966d924d5de1"}
The real record has 315 segments and 22 chunks for this 14-minute talk. nonSpeechEvents
is empty here; on a music video it holds entries like [Music], kept separate from spoken
text. chapters is empty above because this video has none — see the Chapters section above.
How to use YouTube Transcript Scraper
- Click Start to run it with the two example videos, or replace YouTube URLs with your
own — video links, Shorts links,
youtu.beshort links, bare video IDs, channel links (@handleor/channel/UC...), or playlist links all work in the same field. - No link on hand? Add terms to Search keywords instead and the Actor finds and scrapes the top results for you.
- Pulling a channel or playlist? Set Max videos per source to cap how many it expands to.
- Not sure what a run will cost? Turn on Preview only first — see "Check the cost before you spend it" above.
- Leave Incremental mode on and schedule the run — each later run skips videos already fetched, so a daily schedule only pays for what's new.
- Read results from the dataset, the API, or push them into Google Sheets, Slack, Zapier, Make or n8n through the standard Apify integrations.
Input configuration
| Field | What it does | Default |
|---|---|---|
| YouTube URLs | Any mix of video, Shorts, channel or playlist links. Channel and playlist links are expanded into their videos automatically | 2 example videos |
| Search keywords | Search YouTube for each keyword and scrape transcripts from the top results — no URL needed | Empty |
| Preview only (no transcript charges) | List what would be scraped and how many videos would be charged, without fetching a single transcript | Off |
| Preferred languages | Language codes in priority order (en, de, tr, ...). If none match, the first available track is returned rather than skipped — check language on the record | ["en"] |
| Prefer human-written captions | Choose manual captions over auto-generated when both exist | On |
| Translate transcript to | Language code to translate the transcript into (es, de, ...), using YouTube's own translation at no extra charge. Falls back to the original transcript with a warning if the video doesn't offer that language — check translatedTo on the record | Off (no translation) |
| Include transcript | Off skips duration, view count and publish date; title, channel and thumbnail return, at the lower price | On |
| Transcript format | Adds a ready-to-use text, srt or vtt string to each record. Segments and paragraphs are always included as well | JSON only |
| Paragraph length (seconds) | Target length of each merged chunk; raw segments always kept too | 40 (5–600) |
| Paragraph boundaries | Split paragraphs on the video's own chapters when it has them, otherwise fixed length | Fixed length |
| Include Shorts | When expanding a channel, also include Shorts. Shorts links given directly are always scraped | Off |
| Max videos per source | Upper bound on videos pulled per channel, playlist or search | 30 (1–200) |
| Max pages per source | How many result pages to fetch per channel, playlist or search | 10 (1–20) |
| Incremental mode | Skip videos already fetched in a previous run | On |
Video URLs, Channel URLs and Max videos per channel are deprecated but still accepted, so existing runs keep working — new runs should use YouTube URLs and Max videos per source instead.
Pricing
This Actor uses Apify's Pay-Per-Event model. Two events fire independently:
| Event | Fires when |
|---|---|
video-metadata | A video record is delivered — even with no captions |
transcript-scraped | A transcript was actually extracted and included |
A video with no captions, a deleted video, or one that stays blocked after retries never
triggers transcript-scraped. A caption-less video still returns a metadata-only record,
charged at the metadata rate only. A deleted, private, or permanently blocked video returns no
record at all and is not charged for either event — you only pay the transcript rate for
transcripts you actually receive. Turn Include transcript off to fetch metadata only, at
the lower single-event rate. Exact per-event prices are on this Actor's Pricing tab in Apify
Console.
Limits, stated plainly
Not every video has a transcript, and we do not invent one.
- No captions at all — the video still returns a metadata record, charged at the metadata
rate only.
transcript-scrapeddoes not fire. - Deleted, private, or permanently blocked — no record at all, and no charge for either event.
- Auto-generated captions carry YouTube's own errors. Proper nouns, technical terms and overlapping speech are where they break down. The record tells you whether the track was auto-generated or human-written, so you can filter on it.
- Translation is YouTube's, not ours. If the video does not offer the language you asked
for, you get the original transcript plus a warning — check
translatedToon the record rather than assuming the translation happened. - Shorts and long videos behave the same way, but a video that stays rate-limited after retries is reported as such instead of being silently dropped.
Output & integrations
Every record follows one schema: videoId, url, inputUrl, title, channelName,
channelUrl, thumbnailUrl, durationSeconds, viewCount, publishedAt, description,
keywords, language, isAutoGenerated, availableLanguages, segments, chunks,
nonSpeechEvents, chapters, transcriptAvailable, transcriptQuality,
transcriptFormatted, scrapedAt, translatedTo, contentHash.
segments and chunks exist side by side on purpose. segments are the unmodified caption
lines, for your own paragraphing or subtitle format. chunks are pre-merged into paragraphs
sized by Paragraph length, ready for search-index or RAG pipelines without extra work.
Both carry millisecond timestamps, so any chunk or segment links back to url plus its
startMs to jump into the video.
inputUrl records which entry in YouTube URLs or Search keywords produced this video —
useful when one run mixes several sources. chapters holds the video's own chapter list when it
has one (see "Chapters" above) and is empty otherwise. transcriptQuality is the quality block
described in "Judging transcript quality in bulk" above. transcriptFormatted holds the
ready-to-use string requested via Transcript format, and is null when that setting is
left at its json default.
isAutoGenerated tells you whether captions came from YouTube's speech model or a human —
useful for quality filtering, since auto captions are noisier on accented or technical speech.
translatedTo holds the language code the transcript was actually translated into when
Translate transcript to succeeded, and is null when no translation was requested or the
video didn't offer the one you asked for — language always keeps carrying the source
track's language, so the two fields together answer "was this translated, and from what."
contentHash fingerprints every field except scrapedAt (the fetch timestamp), inputUrl
(provenance, not content) and transcriptFormatted (derived from segments, not independent
content) — useful for detecting changes between your own runs without diffing every field.
A translated transcript is genuinely different content, so translatedTo is included in the
hash: translating a previously-scraped video produces a new contentHash.
inputUrl and transcriptFormatted were excluded after earlier versions of this Actor already
shipped, so records produced before this version will hash differently even when nothing about
the video changed — expect one full sweep of "changed" records the first time you run this
version.
Incremental mode works by video ID, and only for runs where Include transcript is on: once a video has produced a transcript record, it's skipped — and not re-charged — on a later run. Metadata-only runs (Include transcript off) are never recorded this way, so the same videos are billed again on every run.
Export as JSON, CSV, Excel or XML, or read the dataset through the Apify API. Works with the standard Apify integrations: Google Sheets, Slack, Zapier, Make, n8n, and webhooks.
Frequently asked questions
Is this Actor affiliated with YouTube? No. This is an independent, unofficial tool, not affiliated with, endorsed by, or connected to YouTube or Google LLC. All product names and trademarks belong to their respective owners.
Why do some videos return no transcript? Two outcomes return no transcript: no captions in any language (metadata rate only), or a deleted, private, or blocked video after three retries (nothing charged). Captions that don't match your Preferred languages aren't skipped — the Actor falls back to the first available track, charged at the transcript rate.
Are auto-generated captions accurate?
It varies — auto captions handle clear speech well but struggle with fast talkers, technical
terms, or heavy accents. Check isAutoGenerated on the record to filter or clean up as needed.
This Actor prefers human-written captions by default, via Prefer human-written captions.
Can I get a whole channel?
Yes. Paste the channel's @handle or /channel/UC... URL into YouTube URLs and set Max
videos per source (up to 200). The Actor pages through the upload list and processes every
video the same way as a single one — same metadata, transcript logic, and incremental skip.
Playlists and search results work the same way. If a source has more videos than your cap, the
run finishes normally and its RUN-SUMMARY output notes the truncation.