Reliable YouTube transcript fetcher for Node.js — port of the popular Python youtube-transcript-api (2025 edition)
npm install youtube-captions-apiA reliable, self-contained Node.js/TypeScript port of the popular Python youtube-transcript-api (as of December 2025).
This is mostly an AI-generated port (created with assistance from Grok by xAI), faithfully replicating the Python library's core logic, error handling, consent handling, and reliability.
Fetches timed transcripts (manual or auto-generated) using YouTube's internal Innertube API — no official API key required.
> Warning: This uses undocumented endpoints. It may break if YouTube changes their internals.
- Instance-based API (new YouTubeTranscriptApi())
- fetch(videoIdOrUrl, { languages }) → timed segments with start/duration
- Language priority (prefers manual captions over auto-generated)
- Consent cookie handling
- Proxy support for production/cloud use
- Full concatenated text via .getText()
- Debug logging of transcript URL
- Minimal dependencies (only undici)
``bash`
npm install youtube-captions-api
`ts
import YouTubeTranscriptApi from 'youtube-captions-api';
(async () => {
try {
// Optional: use a residential proxy for cloud deployments (highly recommended)
// const api = new YouTubeTranscriptApi('http://user:pass@residential-ip:port');
const api = new YouTubeTranscriptApi();
const transcript = await api.fetch('dQw4w9WgXcQ', {
languages: ['en'], // priority list – falls back automatically
});
// First timed segment
console.log(transcript.snippets[0]);
// → { text: "We're no strangers to love", start: 12.5, duration: 3.2 }
// Full concatenated text
console.log(transcript.getText());
// Metadata
console.log('Language:', transcript.language_code);
console.log('Auto-generated:', transcript.is_generated);
console.log('Segments count:', transcript.snippets.length);
} catch (err) {
console.error(err instanceof Error ? err.message : err);
}
})();
`
See server.js in the repo for a ready-to-run API endpoint:
``
GET /transcript?id=dQw4w9WgXcQ
→ { video_id, text, language, timed_segments: [{ timestamp, seconds, text }, ...] }
Run:
`bash`
npm run build
node server.js
Test: http://localhost:3000/transcript?id=dQw4w9WgXcQ`
- Works reliably locally on residential IPs.
- In cloud/server environments, YouTube frequently blocks datacenter IPs → use rotating residential proxies (e.g., Webshare, Bright Data, Oxylabs).
- Simply pass the proxy URL to the constructor when deploying.
MIT
Inspired by the excellent Python original — huge thanks to jdepoix!