Two routes get you every transcript from a YouTube channel. The free route is yt-dlp plus, optionally, the youtube-transcript-api Python library: you list the channel's video IDs, loop over them, and handle the videos that fail. The hosted route is YouTube Video Transcript, where you hand over a channel URL and get back a ZIP with one transcript file per video, named by video title. This guide covers both and starts with yt-dlp, because for a channel of a few dozen videos pulled from a home connection, yt-dlp costs nothing and works.
Which route should you use, yt-dlp or a hosted tool?
Use yt-dlp when the channel is small and the script runs on your own machine. Use a hosted tool when the channel runs into the hundreds or thousands of videos, or when the code has to run on a server. The dividing line is the IP address the requests come from, not the size of the channel and not your budget: YouTube blocks cloud provider IP ranges, and a home connection is the one place the free route is not fighting that.
| Route | What you run | What it costs | Where it stops |
|---|---|---|---|
| yt-dlp and youtube-transcript-api | One shell command, then a Python loop | $0, plus proxies if you need them | Requests from a VPS or cloud function get blocked |
| YouTube Video Transcript web app | Paste the URL, select videos, pick a format | 30 transcripts a month free, then $9/mo for 1,000 | One button per channel, up to 5,000 long-form videos per job |
| YouTube Video Transcript API | One POST carrying the channel URL | Paid plans only, from $9/mo | 500 videos per job on Starter, 10,000 on Business |
How do you download a channel's transcripts with yt-dlp?
Two commands do it. yt-dlp --flat-playlist lists every video ID on the channel, and then either yt-dlp --write-subs or the youtube-transcript-api Python library pulls the captions for each ID. Neither needs a YouTube API key, because both read the public caption tracks YouTube already serves. You need yt-dlp installed from pip or your package manager. For the Python option you also need Python 3 and the youtube-transcript-api package. ffmpeg is optional and only converts subtitle files between formats.
Step 1: how do you list every video in a channel?
yt-dlp treats a channel's /videos tab as a playlist. The --flat-playlist flag lists entries without visiting each video, so it stays fast on large channels. Print the IDs to a file:
yt-dlp --flat-playlist --print id \
"https://www.youtube.com/@CHANNEL/videos" > ids.txtThat writes one video ID per line to ids.txt. Swap @CHANNEL for the handle, or use a /channel/UC... URL if the channel has no handle. A few variations help in practice. To capture titles alongside the IDs, change the template to --print "%(id)s %(title)s". To cap a test run to the first 50 videos, add --playlist-end 50. And if the content you want lives in a specific playlist rather than the whole channel, point yt-dlp at the playlist URL instead, which preserves the creator's intended order.
Step 2, option A: how do you download subtitles with yt-dlp?
yt-dlp writes subtitles for an entire channel in one command and needs no ID list, because it enumerates the channel itself. Use --skip-download so it grabs only the captions:
yt-dlp --skip-download \
--write-subs --write-auto-subs \
--sub-langs en --convert-subs srt \
-o "%(id)s.%(ext)s" \
"https://www.youtube.com/@CHANNEL/videos"--write-subs pulls human captions and --write-auto-subs adds YouTube's auto-generated ones when there is no human track. yt-dlp's native caption output is .vtt; --convert-subs srt converts to SRT and needs ffmpeg installed. Drop that flag if VTT is what you wanted in the first place. The -o template names files by video ID, which keeps them unique but unreadable; switch to -o "%(title)s [%(id)s].%(ext)s" for human-readable names with the ID kept for deduplication.
For non-English channels, set --sub-langs to the language code you want, for example --sub-langs es, or --sub-langs "en,es" for both. yt-dlp writes one file per language per video, so a video carrying both a human and an auto English track produces two files. The auto track gets an .en language tag in the filename, so check the filenames if you only want the human caption.
Step 2, option B: how do you pull transcripts with Python?
Use the youtube-transcript-api library when you want structured JSON rather than subtitle files. Install it first:
pip install youtube-transcript-apiThen loop over the IDs from step 1 and save each transcript as JSON. The library returns timestamped segments, which you serialize however your pipeline needs:
import json
from youtube_transcript_api import YouTubeTranscriptApi
ytt_api = YouTubeTranscriptApi()
with open("ids.txt") as f:
video_ids = [line.strip() for line in f if line.strip()]
for video_id in video_ids:
try:
fetched = ytt_api.fetch(video_id, languages=["en"])
with open(f"{video_id}.json", "w") as out:
json.dump(fetched.to_raw_data(), out, ensure_ascii=False, indent=2)
except Exception as error:
print(f"skipped {video_id}: {error}")Each segment carries text, start, and duration, and to_raw_data() hands you a plain list of dictionaries ready for json.dump. The try / except matters: it skips videos that have no transcript instead of crashing the whole run.
Two refinements help on real channels. The languages argument is a priority list rather than a hard filter, so passing languages=["en", "en-US", "es"] returns the first track that exists instead of failing when one exact code is missing. And if you want plain text rather than timestamped segments, join them with " ".join(s.text for s in fetched), which gives you one string per video for summarization or full-text search.
Which format should you save: TXT, JSON, or SRT?
Pick the format by what happens to the file next, not by which is easiest to produce. Subtitle formats keep the timing, JSON keeps the timing as structured data, and TXT throws the timing away and leaves the words.
| Format | Keeps timing | Use it for | Produced by |
|---|---|---|---|
| SRT and VTT | Yes, as subtitle cues | Re-uploading captions, feeding a video editor | yt-dlp natively (VTT), or SRT via ffmpeg |
| JSON | Yes, as structured fields | Search, chunking, anything a program reads | youtube-transcript-api, or a hosted export |
| TXT | No | Summarization, full-text search, pasting into an LLM | Joining segments, or a hosted export |
What breaks when the channel is large?
The script above works on a channel of thirty videos and then surprises you on a channel of three thousand. Five failures account for almost all of it:
- Some videos have no captions at all. Shorts, music videos, and many older uploads return nothing, which is why the example above catches exceptions rather than letting one missing track end the run.
- Auto-captions go missing per language and per region. A track that exists for one viewer can be absent for another, so a single language filter quietly drops videos that a priority list would have caught.
- Age-gated and members-only uploads return nothing, because they need authentication that a plain library call does not carry. They fail the same way a caption-less video does.
- Thousands of back-to-back requests get throttled. A short delay between calls keeps the run under the threshold.
- Cloud and datacenter IPs get blocked, and this is the one people actually hit. The youtube-transcript-api README carries a section on working around IP bans and tells you to route requests through a proxy when the code runs on a cloud provider. Run the same script from AWS, a cloud function, or a VPS and it can start failing within a few hundred requests. The fix is residential proxies that you set up, rotate, and pay for.
As a rough rule, a channel under a hundred videos pulled from a home connection rarely triggers blocks, so the free route just works. Past a few hundred videos, or from any cloud host, the blocks start, and that is where people either stand up a proxy pool or switch to a hosted tool. One safeguard is worth building either way: write each transcript as you go and skip any video whose output file already exists, so a crash or a mid-run block lets you resume instead of starting from zero. The script is short. Making it survive a few thousand videos is the actual work, and that work is the real price of the free route.
How do you download a channel in the web app without code?
Paste the channel URL into YouTube Video Transcript and the channel appears with its banner, subscriber count, a row of its playlists, and the first page of videos. Signing in with Google adds the exact long-form video count and a Download N videos button, where N is that count. Choose a format, press it, and the app collects every video in the channel for you and runs the job in the background. What comes back is a ZIP with one transcript file per video, each named by the video's title. To take a subset instead, tick videos or press Select all on the loaded page, then Download N selected.
Two limits are worth knowing before you press it. A whole-channel job covers at most 5,000 videos, and it is sized to what you can pay for, so with 800 transcripts left on a 2,000-video channel the button reads Download 800 from 2,000 videos and takes the newest 800. The count is long-form uploads only; Shorts are not included. For more than 5,000 in one job, the API covered in the next section goes to 10,000 on Business.
The format picker in the web app offers TXT, SRT, JSON, CSV, and Markdown, and the API adds DOCX, for six formats in total. VTT is not one of them. If your workflow specifically needs WebVTT files, yt-dlp writes them natively and is the better tool for that job. What you do not have to solve is the IP blocking that ends the free route on a cloud host: there is nothing to configure, and no proxy bill.
The largest single job YouTube Video Transcript has handled pulled 3,713 videos from one channel, and 16,279 transcripts have gone through the service so far, at a median of 2.0s per transcript. Figures as of September 2026.
How do you download an entire channel in one API call?
One POST to /api/v1/jobs carrying a channel URL covers every video on that channel. The API walks the channel itself, so you never enumerate video IDs, and it answers with a job ID you poll until the status reads completed. The bulk job endpoint requires a paid plan; a free key can still call GET /api/v1/transcript/:videoId for single videos.
KEY=yvt_live_...
HOST=https://api.youtubevideotranscript.io
# Submit the whole channel
JOB=$(curl -sS -H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"url": "https://www.youtube.com/@channelname", "format": "txt"}' \
"$HOST/api/v1/jobs")
JOB_ID=$(echo "$JOB" | jq -r .job_id)
# Poll, then download the ZIP
curl -sS -H "Authorization: Bearer $KEY" "$HOST/api/v1/jobs/$JOB_ID"
curl -OJ -H "Authorization: Bearer $KEY" "$HOST/api/v1/jobs/$JOB_ID/export"The Idempotency-Key header is required on job submission, so a retried POST returns the original job rather than charging you twice for the same channel. Each plan caps how many videos one job may cover, and a channel above the cap is rejected with a 413 telling you to split the job or upgrade rather than silently truncating the channel:
| Plan | Videos per bulk job | Concurrent bulk jobs |
|---|---|---|
| Free | Bulk jobs not available | 0 |
| Starter | 500 | 1 |
| Pro | 2,000 | 2 |
| Business | 10,000 | 3 |
The same endpoint accepts a video_ids array instead of a URL if you already enumerated the channel yourself, and the format field takes any of the six export formats. Full request and response shapes are on the bulk jobs documentation page, and the overview lives on the Transcript API page.
What does it cost to download a whole channel?
One video costs one transcript, so a 640-video channel costs 640 transcripts whichever route you take through the product. The first 30 each month are free with a Google sign-in and no card, which is enough to run a real test on a real channel before deciding anything.
| Plan | Price | Transcripts | Per transcript |
|---|---|---|---|
| Free | $0 | 30 a month | $0 |
| Starter | $9/mo | 1,000/mo | 0.9¢ |
| Pro | $19/mo | 5,000/mo | 0.38¢ |
| Business | $49/mo | 20,000/mo | 0.25¢ |
A few details decide whether those prices work for a channel-sized job. Videos with no captions available are not charged, so the Shorts and music videos that break a DIY loop do not cost you anything here either. Unused transcripts do not roll over into the next billing period, so a plan sized for one big channel dump every few months is the wrong shape; buy for the month you are actually in. And a finished job stays downloadable for 100 days, so pull the ZIP somewhere durable rather than treating the job history as storage.
Both routes read the same underlying caption tracks, so neither produces a transcript for a video whose captions are disabled, and no captions-based tool can. A channel that never enabled captions has nothing to download, and a tool that promises otherwise is transcribing the audio, which is a different and slower product.
What should you do with the transcripts once you have them?
The next step depends on the goal. For an AI or LLM dataset, the chunk, embed, and vector database pipeline is covered in our guide to the best YouTube transcript tools for AI and LLM datasets. For bulk export across formats and how the paid tools compare on price, see the comparison of YouTube transcript downloaders. And if you are wiring this into your own product rather than running it by hand, the comparison of YouTube transcript APIs covers the endpoints and the pricing models.
If the channel is small and you already live in a terminal, run yt-dlp and keep your money. If it is not, paste the channel URL into YouTube Video Transcript, sign in with Google, select the videos, and pick TXT, SRT, JSON, CSV, or Markdown. You get a ZIP with one file per video, named by title. The first 30 transcripts a month cost nothing and need no card, and after that it is $9 a month for 1,000.
Related articles
Turn a YouTube lecture playlist into searchable study notes
YouTube Video Transcript downloads lecture transcripts in bulk. Build searchable notes with a course index, review questions, and links to the original lessons.
Read more →
Turn your YouTube archive into articles and newsletters
YouTube Video Transcript exports your archive in bulk. Find stories and explanations in old videos, then reuse them in articles and newsletters with source links.
Read more →
How to download YouTube comments and replies to CSV or JSON
YouTube Video Transcript collects comments and replies into CSV and JSON for research. Export a video, playlist, or channel with a budget you choose.
Read more →