YouTube Video to Markdown: Three Routes Compared
You can turn a YouTube video into a Markdown file three ways, and they fail differently. The transcript panel gives you timestamped lines and no metadata, yt-dlp gives you the caption track you ask for, and a browser extension writes the metadata header the other two leave out.
TL;DR
Three routes get a YouTube video into Markdown. The transcript panel is fastest for one video and carries no metadata. yt-dlp is the route for batches and for picking the original-language track. A browser extension is the route when the file has to open with the title, channel, URL, publish date, runtime, view count, caption language, and word count.
Try it on your own script
Paste your draft below. You get your hook, structure, and pacing scores, a script-level attention-risk map, and the single biggest issue quoted from your own lines. Free, no login.
Free · No login · See a sample audit first if you prefer.
Key Takeaways
- You can turn a YouTube video into a Markdown file three ways, and they fail differently
- The transcript panel is fastest for one video you will edit by hand, and it carries no metadata
- yt-dlp is the route for many files, or when you need the original-language track
- A browser extension is the route when the file must carry the video metadata as well as the script
- The same video ships two English caption tracks: a creator-uploaded track with 286 cues and 3,357 words, and the automatic en-orig track with 500 cues and 3,368 words
- The caption payload from YouTube carries only wireMagic, pens, wsWinStyles, wpWinPositions, and events at the top level, so no route built on captions alone can recover the title or the publish date
Key Statistics
- •yt-dlp 2026.08.19 wrote a 361,161-byte JSON3 file for the automatic original-language track of 3Blue1Brown's aircAruvnKk and a 46,010-byte file for the creator-uploaded English track, measured on 19 September 2026.
- •The same video ships two English caption tracks: a creator-uploaded track with 286 cues and 3,357 words, and the automatic en-orig track with 500 cues and 3,368 words, measured on 19 September 2026.
- •The manual track ends with the name Lisha while the automatic track ends with Alicia, measured on the same video on 19 September 2026.
- •The caption payload from YouTube carries only wireMagic, pens, wsWinStyles, wpWinPositions, and events at the top level, so no route built on captions alone can recover the title or the publish date.
- •A 3,357-word transcript is 18,469 characters, which Prepublish's own cost estimator divides by 4 for roughly 4,617 tokens.
In This Guide
YouTube Video to Markdown: Three Routes Compared
You can turn a YouTube video into a Markdown file three ways. The transcript panel is fastest for one video you will edit by hand. yt-dlp is the route for many files, or when you need the original-language track. A browser extension is the route when the file must carry the video metadata as well as the script.
What a markdown bundle needs, and why
A caption dump is a wall of speech. A bundle is that speech plus the facts that make it findable. This is the field list, using real values from the example further down.
| Field | Real value from the example | What it does for you later |
|---|---|---|
| Title | But what is a neural network? | Deep learning chapter 1 | Becomes the H1, and names the file after slugging |
| Channel | 3Blue1Brown | Groups ten files from one creator without opening a single URL |
| Channel URL | https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw | Survives a channel rename and lets a tool re-resolve the channel |
| Video URL | https://www.youtube.com/watch?v=aircAruvnKk | The only field that makes the file checkable |
| Published | 2017-10-05 | Orders a corpus by time and separates a 2017 explainer from a 2026 one |
| Runtime | 18:40 | Gives the speech rate a denominator |
| Views | 24,362,907 | Distinguishes a widely seen video from an obscure one |
| Captions | English (manual) | States the language and whether a machine wrote it |
| Words | 3,357 | Sizes the file before you paste it into anything with a context limit |
| Description | Full description text | The only field in the bundle the creator wrote as sentences |
| Tags | Comma-joined, dropped when empty | Adds terms the creator chose that the script may not contain |
The extension writes these in a fixed order and drops any line whose value is missing, so a partial pull still produces a clean file rather than the string undefined (prepublish-extension/src/lib/bundle.js).
What the file actually looks like
The block below is real output, generated on 19 September 2026 from the creator-uploaded English captions of aircAruvnKk. The header and the two section headings are verbatim.
# But what is a neural network? | Deep learning chapter 1
- Channel: 3Blue1Brown
- Channel URL: https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw
- Video URL: https://www.youtube.com/watch?v=aircAruvnKk
- Published: 2017-10-05
- Runtime: 18:40
- Views: 24,362,907
- Captions: English (manual)
- Words: 3,357
## Description
What are the neurons, why are there layers, and what is the math underlying it?
...
## Script
This is a 3. It's sloppily written and rendered at an extremely low resolution of 28x28 pixels, but your brain has no trouble recognizing it as a 3.
The script body is the caption text with cues joined into paragraphs. The bundle breaks a paragraph at a gap of 2.5 seconds or after 90 words, whichever arrives first, and it never invents punctuation (prepublish-extension/src/lib/transcript.js). The whole file is 22,294 bytes for an 18-minute video.
The metadata block costs 317 characters, about 79 tokens at the estimator described below. That is a rounding error against the script it describes, and it is the part that determines whether the file is still useful next year.
Route one: YouTube's own transcript panel
YouTube documents the panel in its own help article on video transcripts: open the description, click Show transcript, and click any line to jump the video to that moment (support.google.com/youtube/answer/15930243, read 19 September 2026). The article describes reading and navigating. It does not describe exporting, because there is no export.
Measured on 19 September 2026 in a real Chrome against aircAruvnKk, the panel rendered no rows until the video was actually playing. Before playback the panel container held a loading spinner and zero segment rows. Once the video ran, rows appeared, and each row's own text came out as two lines. The timestamp sat on the first line and the cue on the second, so a row copied as:
0:04
This is a 3.
Three things about that result make it awkward to reuse.
The timestamps are inside the text. Every cue arrives with a time attached, on its own line. A find-and-replace can strip a leading M:SS or H:MM:SS, but the operation has to run per line, and a line that legitimately begins with a number is easy to damage.
The panel shows the track YouTube chose, not the track you asked for. For aircAruvnKk the panel's final line reads All right thank you Lisha. That matches the creator-uploaded English track. The automatic en-orig track for the same video ends All right, thank you Alicia. Two renderings of the same audio disagree about a person's name, and the panel gives you no way to tell which one you copied.
There is no metadata at all. The JSON3 caption payload that all three routes read carries five top-level keys: wireMagic, pens, wsWinStyles, wpWinPositions, and events. Nothing in it names the video, the channel, the upload date, or the view count. A pasted transcript is an orphan the moment the tab closes.
One problem that gets reported and did not reproduce: rolling duplicates, where the same line appears twice in a row because captions are generated in a sliding window. Across 13 caption tracks downloaded from five videos for this article, 8,778 cues in total, exactly one consecutive duplicate appeared, and it was a repeated lyric line in a music video that was correct. Across the panel text for aircAruvnKk there were none. The parser in prepublish-extension/src/lib/transcript.js still drops consecutive duplicates, and its comment explains why: rolling-caption artifacts exist, so the guard is cheap insurance rather than a routine fix.
Route two: yt-dlp and a short cleanup script
Install yt-dlp, then ask for the track you actually want. The version used here printed 2026.08.19.
yt-dlp --skip-download --write-subs --write-auto-subs \
--sub-langs "en-orig,en" --sub-format json3 \
-o "%(id)s.%(ext)s" "https://www.youtube.com/watch?v=aircAruvnKk"
That command printed two Writing video subtitles to: lines and wrote both files: aircAruvnKk.en-orig.json3 at 361,161 bytes and aircAruvnKk.en.json3 at 46,010 bytes. The flags matter more than they look:
--write-subscovers creator-uploaded tracks,--write-auto-subscovers the machine-generated ones. You need both, because a video can have either, andaircAruvnKkhas both.en-origis the automatic track in the language the video is spoken in. In the same video's metadata,automatic_captionsheld 162 keys and exactly one ended in-orig.- The rest of that list is not tracks. 155 of the 162 keys carried
tlang=in their caption URL, which is how YouTube marks an auto-translation of a real track. Ask forfron an English video and you may get English speech machine-translated into French, labelledfr. - Drop
--skip-downloadand yt-dlp fetches the video as well, which you do not want for a transcript.
The JSON3 file is a stream of timed cues with a lot of noise. In the en-orig file, 1,000 events arrived and 499 of them were bare line-break markers with no words. The post-processing step is short:
// 1. Drop cues with no words, and consecutive repeats of the same line.
// 2. Join the rest into paragraphs: break at a 2.5 s gap or every 90 words.
// 3. Print the metadata header from --dump-json, then the description, then the script.
Run as node markdownize.mjs meta.json aircAruvnKk.en-orig.json3 > out.md, that produced a 22,327-byte file with the same header shape as the bundle above and a 3,368-word script. Two pipelines built independently, and the gap between their word counts is explained by nothing except the track each one read.
The limitation is maintenance. yt-dlp is the tool the platform actively pushes back on. The stable release 2026.8.19 was 30 days old on 18 September 2026 while nightly builds landed at a median gap of 1.5 days between PyPI releases. On Prepublish's own production host, a worker container running yt-dlp 2026.08.19 without the curl_cffi dependency returned metadata and 0 caption characters. The fallback client it selects for subtitles needs a token it cannot mint. The same image with curl_cffi 0.16.3 and a proxy returned 18,143 characters. If you keep a local pipeline, keep it current and check it after a failure, not after a silence.
Route three: the browser extension
The Prepublish extension reads the caption URL that YouTube's own player has already requested, then refetches it from your browser session. The track it returns is the one in the video's spoken language rather than an automatic translation of it. It exports a Markdown bundle and a JSON bundle, both carrying the metadata above, and its workspace adds plain .txt, .srt, and .vtt exports for the same script (prepublish-extension/docs/STORE-LISTING.md).
The JSON bundle is the one to reach for when a program consumes the file rather than a person. Every key is always present, and missing values arrive as '', 0, [], or false. A reader never has to distinguish absent from empty.
What to do with the file
Dropping the Markdown file into an Obsidian vault works without conversion, because the file is plain Markdown. The metadata block is a bullet list rather than YAML frontmatter, so it reads as the opening lines of the note instead of as properties.
For a language model, the arithmetic is the planning number. Prepublish's own cost estimator divides characters by 4 to approximate tokens (prepublish-be/internal/infrastructure/ai/breakdown_cost.go), which puts the 18,469-character script at roughly 4,617 tokens. Ten files of that length come to about 46,000 tokens of script plus 793 tokens of headers. That fits a long-context model in one pass and does not fit a small one, and knowing which case you are in is the difference between pasting a directory and pasting one file.
The header is what makes the ten files usable together. Ten documents beginning # and no more are ten anonymous blocks of speech; a reader has to open links to learn which channel each came from, in what order they were published, and whether the text below is human-written or machine-transcribed. With the header, a single prompt can ask for every 2017 video, or every manual track, or every transcript longer than 3,000 words, and get a correct answer without another tool call.
The limits of every route here
Captions are not a script. They are a transcript of what was said, complete with filler, restarts, and stumbles. The automatic track for aircAruvnKk contains very difficult to train at at some point and incredibly um deep uh neural networks. Three of its 500 cues contain a doubled adjacent word, and one of those, many many, is correct English, so the count is not an error rate. Expect cleanup on an automatic track and a much lighter pass on a creator-uploaded one.
Automatic speech recognition mis-hears names, numbers, and technical terms. The clearest example in this dataset is the name at the end of aircAruvnKk: the automatic track says Alicia, and the creator-uploaded track says Lisha. Any downstream use that depends on proper nouns, figures, or units should be checked against the video, not against the file.
The two English tracks are not the same length. The manual track is 286 cues and 3,357 words; the en-orig track is 500 cues and 3,368 words. The file does not say why, and the answer is not something the caption payload exposes. The practical reason to care is that the word count in your header changes depending on which track you picked, so quoting it as the video's word count is a claim about your extraction rather than about the video.
A video without captions cannot be converted this way. All three routes read a caption track YouTube already produced, so none of them invent one. Measured on 19 September 2026, yt-dlp reports that aqz-KE-bpKQ has no automatic captions and no subtitles, and a download attempt prints There are no subtitles for the requested languages and writes no file. Speech recognition on the audio is a different pipeline with a different accuracy profile, and it is outside what a caption-based workflow can promise.
Once the text exists as a file, the ordinary script tools apply. The word counter converts a count into a runtime at your own speaking pace, which is the fastest way to see whether a transcript is a 6-minute video or an 18-minute one before you read it. The public transcript page shows the same captions rendered for a browser, with the metadata attached. And the free tools index lists the rest of the checks that take text as input.
Frequently asked questions
What is the fastest way to turn a YouTube video into a markdown file?
The transcript panel, for one video. Open the description, click Show transcript, select the text, and paste it into a file. It is also the route with the least reusable result, because every line arrives with a timestamp attached and nothing tells a later reader which video the text came from. For more than a few videos, or for a file that should still make sense in six months, yt-dlp or a browser extension produces a better artifact for about the same effort.
Does YouTube let you download a transcript as a file?
No. YouTube's own help page for video transcripts describes opening the panel in the description and clicking a line to jump the video to that moment. It documents reading and navigating, not exporting. The panel has no download control, so the practical export is selecting the rendered text and pasting it. On the 18:40 video measured on 19 September 2026, that selection carried a timestamp on its own line before every cue.
How do I download only the original-language captions with yt-dlp?
Request en-orig alongside the plain language key: --sub-langs "en-orig,en" with both --write-subs and --write-auto-subs. In yt-dlp's metadata for 3Blue1Brown's aircAruvnKk, automatic_captions held 162 keys, exactly one ended in -orig, and 155 carried tlang= in their URLs. The tlang parameter marks an auto-translation of a real track rather than a track of its own, so a wildcard such as en.* can pull translated text.
Why did yt-dlp save a transcribed file in a language I did not ask for?
Because the key you matched was a translation, not a track. YouTube generates auto-translations on the fly by appending tlang to a real track's caption URL, and yt-dlp exposes those under composite keys. On aircAruvnKk, 155 of the 162 automatic_captions keys carried tlang= in their URL. An explicit en-orig request returned English text; the -orig suffix is what identifies the automatic track recorded in the language the video is spoken in.
How many tokens is a YouTube transcript?
About 1.4 tokens per spoken word at the estimate Prepublish uses. The creator-uploaded English track for aircAruvnKk is 3,357 words and 18,469 characters, and Prepublish's cost estimator divides characters by 4 (prepublish-be/internal/infrastructure/ai/breakdown_cost.go), which gives roughly 4,617 tokens. Ten transcripts of that length come to about 46,000 tokens of script, before any file header.
Can I convert a YouTube video that has no captions?
Not with any route in this guide, because all three read a caption track that YouTube already produced. Measured on 19 September 2026, yt-dlp reports aqz-KE-bpKQ has no automatic captions and no subtitles, and a download attempt prints that there are no subtitles for the requested languages and writes no file. Reaching a spoken-only video means running speech recognition yourself, which is a different job with a different accuracy profile.
Should the markdown file keep the timestamps?
Keep them only if you plan to cite moments or build a subtitle file. Prose is what most note-taking and language-model workflows want, and the extension's Markdown bundle joins cues into paragraphs that break at a gap of 2.5 seconds or 90 words. The same workspace also exports .srt and .vtt, so a timestamped copy is one click away without polluting the reading version.
What should the metadata header of a transcript file contain?
Title, channel, video URL, publish date, runtime, view count, caption language and source, and a word count. The header is what makes ten files comparable a year later: without it, ten transcripts are ten anonymised blocks of speech, and a reader has to open each URL to learn which video came from which channel and when. The header costs 317 characters on the example below, about 79 tokens.
Related Guides
Free tools to put this into practice
Hook Analyzer
Score your first 1-3 sentences
Title Analyzer
Writing rubric + 5 rewrites
Words to Minutes
Script length calculator
Word Counter
Count, reading time, duration
Want to see how this reads on real channels? Browse the channel breakdowns. Each one compares script patterns across a channel's own higher-viewed and lower-viewed uploads, quoted from the transcripts.
See where your next script leaks viewers
Paste your script, get your scores and the biggest leak for free. No login.