yt-transcript
Fetch transcripts from YouTube videos. Version 0.2.0. This file is generated by yt-transcript describe --skill; edit the manifest, not the copy.
Check the CLI is there
Run yt-transcript describe first. If the command is not found, install it:
uv tool install git+https://github.com/sleeplessv/youtube-transcript
# no uv on this machine
pip install git+https://github.com/sleeplessv/youtube-transcript
Both need network access to GitHub. If neither install works, say so and stop; there is no offline path to a transcript.
How it behaves
- stdout carries the payload and nothing else. Progress and errors go to stderr, so
> file is always safe.
- Text output is the default. Pass --json for a machine-readable envelope.
- Language selection is strict: asking for a language you cannot have is an error, never a silent substitution.
- Every error names the command that will get you unstuck. Read the hint before guessing.
Commands
fetch
Fetch the transcript of one video in one language.
video: YouTube URL (watch, youtu.be, shorts, embed, live) or bare 11-character video ID.
-l, --language: Language code to fetch. Defaults to 'en'. Fails if that exact language has no track.
-o, --output: Write to this file instead of stdout.
--no-timestamps: Text output only: drop the [MM:SS] prefixes.
--clean: Text output only: strip residual HTML tags and collapse whitespace.
--json: Emit JSON on stdout instead of human-readable text.
--proxy: Route requests through an HTTP/SOCKS proxy. Use this when you hit the blocked error.
Output fields:
video_id: string
language: string, the human-readable name of the track that answered
language_code: string, e.g. 'en'
kind: one of manual, generated, translated
snippet_count: integer
duration_seconds: float, end of the last snippet
text: string, the whole transcript with whitespace collapsed
snippets: array of {text, start, duration}; start and duration are seconds
yt-transcript fetch 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
yt-transcript fetch dQw4w9WgXcQ --json > transcript.json
yt-transcript fetch dQw4w9WgXcQ --clean --no-timestamps
yt-transcript fetch dQw4w9WgXcQ -l de
languages
List every track on a video and what it can be translated into. Run this first when fetch reports language_unavailable.
video: YouTube URL (watch, youtu.be, shorts, embed, live) or bare 11-character video ID.
--json: Emit JSON on stdout instead of human-readable text.
--proxy: Route requests through an HTTP/SOCKS proxy. Use this when you hit the blocked error.
Output fields:
video_id: string
tracks: array of {language_code, language, kind, translatable}
translation_targets: array of language codes YouTube will translate into (--json only; text output shows a count)
yt-transcript languages dQw4w9WgXcQ
yt-transcript languages dQw4w9WgXcQ --json
translate
Machine-translate an existing track into another language.
video: YouTube URL (watch, youtu.be, shorts, embed, live) or bare 11-character video ID.
--to: Target language code. Required.
--from: Source track to translate from. Defaults to 'en'.
-o, --output: Write to this file instead of stdout.
--no-timestamps: Text output only: drop the [MM:SS] prefixes.
--clean: Text output only: strip residual HTML tags and collapse whitespace.
--json: Emit JSON on stdout instead of human-readable text.
--proxy: Route requests through an HTTP/SOCKS proxy. Use this when you hit the blocked error.
Output fields:
video_id: string
language: string, the human-readable name of the track that answered
language_code: string, e.g. 'en'
kind: always 'translated'
snippet_count: integer
duration_seconds: float, end of the last snippet
text: string, the whole transcript with whitespace collapsed
snippets: array of {text, start, duration}; start and duration are seconds
yt-transcript translate dQw4w9WgXcQ --to es
yt-transcript translate dQw4w9WgXcQ --from de --to fr --json
describe
Print this manifest as JSON, or agent instructions as Markdown.
--skill: Print Markdown instructions for an agent instead of JSON.
yt-transcript describe
yt-transcript describe --skill > .claude/skills/yt-transcript/SKILL.md
When a command fails
The exit code says what went wrong and the message on stderr says what to do next. Read it before you retry with different arguments.
0: success
1: unknown: an unrecognised failure. The message is passed through from the underlying library.
2: invalid_input: the argument was not a usable URL or video ID.
3: video_unavailable: private, deleted, age-restricted, or otherwise unplayable.
4: transcripts_disabled: the uploader turned captions off. Nothing will fix this.
5: language_unavailable: no track in that language. Run languages next.
6: not_translatable: that track cannot be translated, or not into that target. Run languages next.
7: blocked: YouTube is refusing this IP. Retry from a residential connection or pass --proxy.
1---2name: yt-transcript3description: Fetch the transcript of a YouTube video from the command line. Use when a prompt carries a YouTube URL or an 11-character video ID and asks for the transcript, the captions, what was said in the video, a summary of the video, a caption track in a particular language, or a translated transcript.4---56# yt-transcript78Fetch transcripts from YouTube videos. Version 0.2.0. This file is generated by `yt-transcript describe --skill`; edit the manifest, not the copy.910## Check the CLI is there1112Run `yt-transcript describe` first. If the command is not found, install it:1314```bash15uv tool install git+https://github.com/sleeplessv/youtube-transcript1617# no uv on this machine18pip install git+https://github.com/sleeplessv/youtube-transcript19```2021Both need network access to GitHub. If neither install works, say so and stop; there is no offline path to a transcript.2223## How it behaves2425- stdout carries the payload and nothing else. Progress and errors go to stderr, so `> file` is always safe.26- Text output is the default. Pass --json for a machine-readable envelope.27- Language selection is strict: asking for a language you cannot have is an error, never a silent substitution.28- Every error names the command that will get you unstuck. Read the hint before guessing.2930## Commands3132### `fetch`3334Fetch the transcript of one video in one language.3536- `video`: YouTube URL (watch, youtu.be, shorts, embed, live) or bare 11-character video ID.37- `-l, --language`: Language code to fetch. Defaults to 'en'. Fails if that exact language has no track.38- `-o, --output`: Write to this file instead of stdout.39- `--no-timestamps`: Text output only: drop the [MM:SS] prefixes.40- `--clean`: Text output only: strip residual HTML tags and collapse whitespace.41- `--json`: Emit JSON on stdout instead of human-readable text.42- `--proxy`: Route requests through an HTTP/SOCKS proxy. Use this when you hit the `blocked` error.4344Output fields:4546- `video_id`: string47- `language`: string, the human-readable name of the track that answered48- `language_code`: string, e.g. 'en'49- `kind`: one of manual, generated, translated50- `snippet_count`: integer51- `duration_seconds`: float, end of the last snippet52- `text`: string, the whole transcript with whitespace collapsed53- `snippets`: array of {text, start, duration}; start and duration are seconds5455```bash56yt-transcript fetch 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'57yt-transcript fetch dQw4w9WgXcQ --json > transcript.json58yt-transcript fetch dQw4w9WgXcQ --clean --no-timestamps59yt-transcript fetch dQw4w9WgXcQ -l de60```6162### `languages`6364List every track on a video and what it can be translated into. Run this first when fetch reports language_unavailable.6566- `video`: YouTube URL (watch, youtu.be, shorts, embed, live) or bare 11-character video ID.67- `--json`: Emit JSON on stdout instead of human-readable text.68- `--proxy`: Route requests through an HTTP/SOCKS proxy. Use this when you hit the `blocked` error.6970Output fields:7172- `video_id`: string73- `tracks`: array of {language_code, language, kind, translatable}74- `translation_targets`: array of language codes YouTube will translate into (--json only; text output shows a count)7576```bash77yt-transcript languages dQw4w9WgXcQ78yt-transcript languages dQw4w9WgXcQ --json79```8081### `translate`8283Machine-translate an existing track into another language.8485- `video`: YouTube URL (watch, youtu.be, shorts, embed, live) or bare 11-character video ID.86- `--to`: Target language code. Required.87- `--from`: Source track to translate from. Defaults to 'en'.88- `-o, --output`: Write to this file instead of stdout.89- `--no-timestamps`: Text output only: drop the [MM:SS] prefixes.90- `--clean`: Text output only: strip residual HTML tags and collapse whitespace.91- `--json`: Emit JSON on stdout instead of human-readable text.92- `--proxy`: Route requests through an HTTP/SOCKS proxy. Use this when you hit the `blocked` error.9394Output fields:9596- `video_id`: string97- `language`: string, the human-readable name of the track that answered98- `language_code`: string, e.g. 'en'99- `kind`: always 'translated'100- `snippet_count`: integer101- `duration_seconds`: float, end of the last snippet102- `text`: string, the whole transcript with whitespace collapsed103- `snippets`: array of {text, start, duration}; start and duration are seconds104105```bash106yt-transcript translate dQw4w9WgXcQ --to es107yt-transcript translate dQw4w9WgXcQ --from de --to fr --json108```109110### `describe`111112Print this manifest as JSON, or agent instructions as Markdown.113114- `--skill`: Print Markdown instructions for an agent instead of JSON.115116```bash117yt-transcript describe118yt-transcript describe --skill > .claude/skills/yt-transcript/SKILL.md119```120121## When a command fails122123The exit code says what went wrong and the message on stderr says what to do next. Read it before you retry with different arguments.124125- `0`: success126- `1`: unknown: an unrecognised failure. The message is passed through from the underlying library.127- `2`: invalid_input: the argument was not a usable URL or video ID.128- `3`: video_unavailable: private, deleted, age-restricted, or otherwise unplayable.129- `4`: transcripts_disabled: the uploader turned captions off. Nothing will fix this.130- `5`: language_unavailable: no track in that language. Run `languages` next.131- `6`: not_translatable: that track cannot be translated, or not into that target. Run `languages` next.132- `7`: blocked: YouTube is refusing this IP. Retry from a residential connection or pass --proxy.133