Bulk YouTube transcript downloader: what to use, and what the limits really are
Downloading one transcript is a solved problem. Downloading four hundred is a different job, and it is where most tools quietly fall over. This page is about what changes at volume — with the actual numbers, not marketing ones.
The 30-second version
- Start here: the VidWords bulk extractor takes a playlist link, a channel
@handle, a pasted list of URLs, or a CSV upload. - Finding the videos is free. You see the resolved list and the exact credit cost before anything is spent.
- The real caps: a playlist or channel resolves up to 500 videos in one go. A pasted or uploaded list resolves up to 200 when signed in, 25 when signed out.
- Price: one credit per transcript actually delivered. A free account includes 25 transcripts a month; without an account it is 3 a month.
- You get one file for the whole batch — combined TXT, CSV, or JSON.
What "bulk" actually has to get right
Any tool can loop. The things that separate a usable bulk downloader from a frustrating one only show up once the list is long enough that you cannot watch it:
- Failures have to stay visible. In a batch of 200 videos, some will have captions disabled and some will be private or region-locked. A tool that silently drops them hands you a file that looks complete and is not — and you will not notice until your analysis is wrong. Failed videos should stay in the results with a reason attached.
- You must see the cost before you commit. Resolving a list and paying for it are two different actions, and they should be two different clicks.
- Order has to survive. A course playlist in shuffled order is a different dataset from a course playlist in sequence.
- Duplicates have to go. Pasted lists are assembled by hand and always contain the same video twice. Paying twice for it is a small insult that adds up.
- One file out, not N files. A zip of 200 text files is a worse deliverable than one structured file you can load in a single line.
- Language has to be a choice. Picking "whatever track came first" gives you a corpus in four languages and no column telling you which is which.
If you are evaluating any bulk tool — this one included — those six are the checklist. Run a deliberately messy list of ten videos with a duplicate, a private video and one with captions disabled, and see what comes back.
The four ways to give it a list
Playlist
Paste the playlist URL or its id. The playlist's own order is preserved where YouTube provides it, which matters for anything sequential — a course, a conference track, a serialised series.
Channel
Paste an @handle or a channel URL and it resolves the channel's videos. This is the route for podcast archives, conference channels and creator back-catalogues. The dedicated walkthrough for this, with the channel-vs-playlist decision spelled out, is bulk transcripts for a whole channel or playlist.
A pasted list of links
One URL or video id per line. This is the route for a hand-assembled set — the 40 videos you actually care about rather than everything a channel ever published. Duplicates are removed before anything is charged.
CSV upload
Upload a CSV and every YouTube URL or video id found in any column is picked up. This is the one that saves the most time in practice, because your list usually already exists in a spreadsheet with other columns you want to keep — search exports, editorial calendars, a coding frame from a research project. You do not have to reshape it first.
The limits, stated plainly
- Playlist or channel: up to 500 videos resolved at a time. Longer sources come back marked as truncated rather than silently cut, so you know to run the remainder as a second batch.
- Pasted list or CSV: up to 200 videos per request when signed in; 25 when signed out. Signing out is not a way to get more.
- Cost: one credit per transcript delivered. Resolving the list costs nothing, and a video that fails costs nothing.
- Monthly allowance: 25 transcripts a month on a free account, 3 a month with no account at all. Paid plans raise the monthly number — the current figures are on the pricing page.
- Language: pick a preferred caption language before the batch runs. It falls back sensibly when a given video does not have that track.
- Running out mid-batch: if the balance is exhausted partway, the run stops rather than continuing to fail silently, and everything already retrieved stays downloadable.
A note on that 500: it is the number of videos that can be resolved in one request, not a monthly ceiling. Extraction is metered separately in credits, so resolving a 500-video channel is free and tells you exactly what the batch would cost before you decide.
What you actually get back
Three combined downloads, each shaped for a different destination:
- Combined
.txt— every transcript as continuous prose, each preceded by a header line with the video title and itsyoutu.belink. No timestamps. This is the one to paste into an LLM, read, or search withgrep. - Combined
.csv— columnsvideo_id,title,start,duration,text, one row per caption segment. This is the shape qualitative analysis software and spreadsheets want, and it keeps timing, so you can trace any line back to its moment in the video. - Combined
.json— an array of objects carryingid,title,author,languageand the fullsegmentsarray. This is the one for code and retrieval pipelines: it is the only export that preserves the per-video language code alongside the text.
Choose by destination, not by preference. A CSV of segments is unpleasant to read and ideal to analyse; the combined TXT is the reverse. If you need subtitle files — .srt or .vtt — those are single-video exports rather than batch ones; see downloading subtitles as SRT or VTT.
Doing it yourself, honestly assessed
The DIY route is yt-dlp or the youtube-transcript-api Python library in a loop. For a one-off pull of a few dozen videos from your own machine, that is a genuinely good answer and it is free. Use it.
What changes at volume is not the code — the loop is ten lines — it is everything around it:
- You will get IP-blocked. This is the dominant failure at scale, and it arrives sooner the more videos you pull. The library's own README states that YouTube "has started blocking most IPs that are known to belong to cloud providers", so the moment you move the job to a server it gets much worse. The full mechanism and the fixes that actually work are in the
RequestBlocked/IpBlockedguide. - You have to build resumability. A 400-video loop that dies at 300 and starts over is worse than useless. You need to persist per-video outcomes, including failures, before you need anything else.
- You have to build the channel and playlist listing too. Getting from an
@handleto a list of video ids is a separate job from fetching a transcript. - Concurrency needs a limit. Unbounded parallelism is the fastest way to get an address blocked. Something small and fixed — a handful of workers — is the right shape.
The honest split: self-host for a one-off pull from your own machine; use a hosted tool when the job repeats, runs on a server, or someone is waiting for it.
Bulk over the API
If the batch is part of a pipeline rather than something you do in a browser, the same work is one POST. Send video ids — up to 50 per call — and get structured transcripts back:
import requests
resp = requests.post(
"https://vidwords.com/api/transcripts",
headers={"Authorization": f"Basic {API_TOKEN}"},
json={"ids": ["dQw4w9WgXcQ", "9bZkp7q19f0"], "lang": "en"},
timeout=60,
)
resp.raise_for_status()
for video in resp.json()["results"]:
if "error" in video:
print(video["id"], "->", video["error"]) # per video, not per batch
continue
print(video["title"], video["language"], len(video["segments"]), "segments")
Batching is for latency, not for price: 50 videos in one request costs the same as 50 single requests. Resolving a channel to its video ids has its own endpoint, available on Starter and above. Everything is documented in the API reference, and ready-made no-code pipelines are in the n8n and Make templates.
What people build with a batch
- Research corpora — a channel or topic set exported as CSV, then coded in NVivo or Atlas.ti with timestamps intact for citation. See transcripts for research.
- Course notes — a lecture playlist as one searchable document instead of forty tabs.
- Retrieval and RAG — the JSON export chunked by segment, with the timestamp kept as metadata so an answer can link back to the moment.
- Competitive and content analysis — a competitor's back-catalogue as text, to find what they cover and what they never mention.
- Repurposing — a back-catalogue mined for the ten videos worth turning into articles. See turning videos into blog posts.
Before you run a big batch
- Resolve first, extract second. Look at the list. Channel handles resolve to more than people expect, and the count is right there before you spend.
- Test with five videos. Check the export shape is what your next tool wants before you buy 400 of them.
- Set the language deliberately. A mixed-language corpus assembled by accident is painful to fix afterwards.
- Keep the failures. The list of what did not work is part of your dataset, not noise — especially for research, where an unexplained gap is a methodological problem.
FAQ
Can I download transcripts for a whole channel without signing in?
You can resolve and preview a channel's videos signed out, but extraction draws on a monthly allowance — 3 a month with no account, 25 with a free one — so any real batch needs an account.
What happens to videos with no captions?
They come back marked as failed with a reason, they stay visible in the results, and they cost nothing. What to do about them is covered in why a transcript can be missing.
Does it work on private or members-only videos?
No. Only public videos with an accessible caption track. Private, deleted, age-restricted and region-blocked videos return a specific error rather than a transcript.
Is there a limit on how long each video can be?
Price does not scale with length: a three-hour video costs the same single credit as a three-minute one. There is an upper bound on transcript size rather than duration — an extremely long caption track, of the kind produced by a multi-hour livestream, is refused with a transcript_too_large error rather than processed.