YouTube Channel Transcript Scraper - Whole Channel, One Input
Pricing
from $5.92 / 1,000 transcripts
YouTube Channel Transcript Scraper - Whole Channel, One Input
For RAG pipelines, LLM training sets and content research: give it @handle, a channel URL or a UC id and get transcripts for that channel's recent videos - no collecting video IDs with a second tool first. 180 videos across 12 channels measured on 2026-08-29. Export as JSON, CSV or Excel.
Pricing
from $5.92 / 1,000 transcripts
Rating
0.0
(0)
Developer
NeverEmpty
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
7 days ago
Last modified
Categories
Share
YouTube Channel Transcript Scraper
For feeding a channel's back catalogue to an LLM for summaries, Q&A or RAG, for searching what a creator actually said, and for subtitling and repurposing workflows: give it a channel — @veritasium, a channel URL, or a UC... channel ID — and get transcripts for that channel's recent videos, one row per video. Most transcript scrapers want a list of video IDs, which means a second tool before you can start; this one finds the videos itself.
Measured over 180 videos, not over one. The 15 most recent videos from each of 12 channels, on 2026-08-29: 163 (90.6%) returned a caption track, 15 (8.3%) had no caption track at all, and 2 (1.1%) were not playable. Of the 163, 124 (76.1%) were auto-generated and 43 (23.9%) were human captions — so a pipeline that assumes human captions is planning for a quarter of the real world.
And it tells you when the language is not the one you asked for. Measured on 2026-08-29, a video offering only a French auto-generated track returned 73 lines of French untranslated, and the same 73 lines in English with translateTo: "en" set — so a foreign-language track is visible in the row rather than silently landing in your dataset as if it were English.
No API key. Export as JSON, CSV or Excel.
What you get
One row per video:
| Field | |
|---|---|
channelInput / channelId / channelTitle | which channel this row came from |
videoId / url / title / publishedAt | the video |
text | the full transcript as one string |
segments | per-line text with start and duration (switch off with includeTimestamps: false) |
language | the language you actually received |
isAutoGenerated | true if these are machine-generated captions |
availableLanguages | every caption language the video offers |
segmentCount | number of caption lines |
ok | false on rows that could not be transcribed, with reason |
Read isAutoGenerated before you trust the text
I measured the 15 most recent videos from each of 12 channels — 180 videos — on 2026-08-29.
| Returned a caption track | 163 (90.6%) |
| ...of which the track was auto-generated | 124 (76.1%) |
| Human captions available | 43 (23.9%) |
| No caption track at all | 15 (8.3%) |
| Video not playable | 2 (1.1%) |
Whether a channel has human-written captions is close to binary. Six of the twelve channels had none at all across their last 15 uploads, while Marques Brownlee (12) and NASA (11) between them account for over half of the 43.
Machine captions and human captions arrive through the same field, with the same success status. isAutoGenerated is the only thing that tells them apart, so it is on every row — along with language and availableLanguages, so you can see what you actually received rather than assuming you got what you asked for.
Getting a language the video does not have
Set translateTo and you get the transcript in that language even when the video only offers another one.
{ "channels": ["@veritasium"], "languages": ["en"], "translateTo": "en" }
Measured on 2026-08-29: a video offering only a French auto-generated track returned 73 lines of French untranslated, and 73 lines of "There's that famous..." with translateTo: "en". A TED video offering only Bulgarian returned 759 lines either way.
This is a machine translation of a machine transcription — two lossy steps, from a source language that may not even be the one being spoken. It is a perfectly reasonable fallback to build. What is not reasonable is doing it silently, so every affected row carries:
| Field | |
|---|---|
isTranslated | true when this text went through translation |
translatedFrom | the language of the track that was actually transcribed |
sourceLanguage | same, present on every row so you can compare |
isAutoGenerated | whether that source track was machine transcription |
If the video already has your language, no translation happens and isTranslated is false — you are never charged the quality cost for nothing.
What it does not do
- It cannot reach a channel's back catalogue. YouTube's public channel feed returns at most 15 videos, so 15 per channel is the ceiling. Ask for more and it will tell you in the log rather than quietly returning 15.
- It does not translate unless you ask. Leave
translateToempty and a Bulgarian-only video gives you Bulgarian, labelled as Bulgarian. Translating without saying so is how a pipeline ends up confidently wrong, which is why the fields above exist. - It does not return blank rows. A private video, a members-only video, one with no captions, or one that was blocked comes back with
ok: falseand areasonin plain English.
Billing
You are charged per transcript that actually contains text. Rows that explain a failure are free. If you set a maximum total charge on the run and it is reached, the run stops and says so in the log and in the run status, rather than silently returning a partial result that looks complete.
Input
{"channels": ["@veritasium", "https://www.youtube.com/@mkbhd", "UCHnyfMqiRRG1u-2MsSQLbXA"],"maxVideosPerChannel": 15,"languages": ["en"],"includeTimestamps": true,"proxyMode": "auto","maxRetries": 3}
| Input | |
|---|---|
channels | Handles (@name), channel URLs, or UC... channel IDs. Required. |
maxVideosPerChannel | 1–15. YouTube's public feed caps at 15 per channel. |
languages | Preferred language codes in order. Human captions win over auto-generated ones. |
includeTimestamps | Include per-line segments with start and duration. |
proxyMode | auto tries datacenter proxies first, because their traffic is free, and falls back to residential only when YouTube blocks. Set residential directly if you run at volume. |
maxRetries | Attempts per video on a different IP before writing a row that says why it failed. |