Download YouTube video transcripts as Markdown files — from a single video, a playlist, or an entire channel. It runs as a permanently available local service with a browser UI, and keeps a watch list of channels you can update with one click.
LLMs are trained on old data and will only find data that it believes is relevant. Having transcripts from trusted channels gives you real-time data to reference. Gives you an offline copy to work with as you see fit.
- Always available — runs as a background service under Local Server Manager and starts with Windows
- Browser UI — open it in a tab; no desktop app to launch
- Whole channels, playlists, or single videos — paste any YouTube URL (or a bare video ID) and it works out what to fetch
- Markdown output — each video becomes a tidy
.mdfile with title, channel, date, and the full transcript - On-demand watcher — update a single watched channel, or all of them, with one click; nothing runs automatically
- Automatic enrolment — download a channel once and it joins the watch list on its own
- Never competes with itself — one job at a time; manual downloads are blocked while the watcher is updating
- Rate-limit friendly — configurable delay between requests (default 61 seconds) with a live countdown
Requires Python 3.10+.
git clone https://github.com/waynegeorge/YouTube-transcript-downloader.git
cd YouTube-transcript-downloader
pip install -e .yt-transcript-serverThen open http://127.0.0.1:8733.
| Option | Description |
|---|---|
--port |
Port to listen on (default: 8733, or the PORT env var) |
--host |
Interface to bind (default: 127.0.0.1) |
--config, -c |
Path to the channels config (default: ./channels.yaml) |
--output, -o |
Transcript output directory (default: ./output) |
--state |
Where watcher state is persisted (default: ./state/watcher.json) |
--verbose, -v |
Enable debug logging |
The service is designed to run under Local Server Manager. Add this entry to its servers.json, then restart the manager:
Register the manager itself to launch at login and the downloader comes up with your machine. Open in browser goes straight to the UI, and GET /health returns 200 for a quick check.
| Tab | What it does |
|---|---|
| Download | Paste a URL and start a job; live log, progress bar and countdown |
| Watcher | Last run and result, and an Update all channels button |
| Channels | Add, edit, update, enable/disable or remove watched channels, with transcript counts; handles link to the channel on YouTube |
| Settings | Request delay, videos checked per channel, and language |
If you start a channel or playlist without setting a limit, the UI asks how many videos to take before it begins.
The watcher checks watched channels for videos you don't already have and downloads their transcripts. Nothing runs automatically — press Update next to a channel in the Channels tab to check just that one, or Update all channels on the Watcher tab for a full sweep.
A full sweep can take a while — 61 seconds between requests adds up — so if you stop one mid-way, the next sweep resumes after the last channel it finished rather than starting from the top.
See WATCHER.md for configuration details.
YouTube rate-limits aggressively, so the service runs a single job at a time. Starting a download while a watcher update is running is refused with a clear message — wait for it, or stop it from the Watcher tab.
The CLI still works for one-off jobs, independently of the service.
yt-transcript-dl <url> [options]| Option | Description |
|---|---|
--output, -o |
Output directory (default: ./output) |
--language, -l |
Preferred transcript language (default: en) |
--limit |
Maximum number of videos to process |
--start |
Start from the Nth video in the list (1-indexed) |
--sleep |
Delay in seconds between requests (default: 61) |
--skip-existing |
Skip videos that already have a transcript file |
--log-file |
Write log output to a file as well as the console |
--verbose, -v |
Enable debug logging |
Examples:
# Download every transcript from a channel, skipping ones you already have
yt-transcript-dl https://www.youtube.com/@SomeChannel --skip-existing
# Grab the 50 most recent videos from a playlist
yt-transcript-dl "https://www.youtube.com/playlist?list=PL..." --limit 50
# A single video
yt-transcript-dl https://www.youtube.com/watch?v=dQw4w9WgXcQTo check every watched channel once without the service running:
yt-transcript-watchtools/recapture_channels.py rebuilds watch-list entries for output folders that aren't in channels.yaml yet. It reads a video ID from each folder's filenames and resolves the channel handle via yt-dlp.
# See what it would add
python tools/recapture_channels.py --report channels-report.json
# Append the resolved entries to channels.yaml
python tools/recapture_channels.py --from-report channels-report.json --applypip install -e ".[dev]"
pytest
{ "id": "yt-transcript", "name": "YouTube Transcript Downloader", "command": "python -u -m yt_transcript_dl.service", "cwd": "B:/repos/YouTube-transcript-downloader", "port": 8733, "autostart": true, "env": { "PYTHONUNBUFFERED": "1" } }