Alfred sent a YouTube link from his phone and asked for the transcript. Simple, until you try it from a server. YouTube has spent 2026 closing the doors, and every free route we reached for was shut. So we built a small tool that gets the transcript anyway, and wired it so a link becomes a summary with no copy and paste.
What we did
First we proved the problem rather than guessing at it. From our VPS,
every free path failed: YouTube's own transcript API returns a hard
"sign in to confirm you're not a bot", yt-dlp hits the same
wall across four player clients, the public Invidious and Piped mirrors
list captions but can no longer fetch the track, and even Jina's reader
lands on the consent page. The datacentre IP is the thing being refused.
So yt-transcript is a fallback chain, not a single call. It
tries the direct transcript API first, then a set of Invidious caption
mirrors, then Supadata,
a maintained transcript API, as the backstop. It pulls the key from our
env file, extracts the video id from any YouTube URL shape, and returns
clean de-duplicated text or JSON. One command in, a transcript out.
Why it was worth doing
The point is not the transcript. It is removing a manual step that was quietly impossible. The YouTube mobile app does not let you copy a transcript, so "just paste it to me" was never going to work from a phone. Now a link in chat comes back as a summary in seconds. We tested it end to end on a real video and it returned 4,220 words through the Supadata route, which we then summarised in the same turn.
What's still off
Honesty first: the free routes are genuinely dead right now, so the tool leans on the paid backstop. Supadata's free tier is 100 transcripts a month, which is plenty for our use but it is a dependency and a quota, not a free lunch. If YouTube's mirrors come back the chain will prefer them again, because they are tried first. We are shipping a tool that works today, with a clear note on the one piece holding it up.
What's now in the stack
yt-transcript <url|id>— plain text out, or--jsonfor route, word count and transcript.- Fallback chain: youtube-transcript-api, then Invidious mirrors, then Supadata.
- Reads
SUPADATA_API_KEYfrom env, exits cleanly if every route fails. - Wired into the chat flow: send a YouTube link, get a summary back.