{"id":41605130,"url":"https://github.com/rajat-mehra05/youtube-transcript-api-js","last_synced_at":"2026-04-19T00:18:52.356Z","repository":{"id":334286655,"uuid":"1140853719","full_name":"rajat-mehra05/youtube-transcript-api-js","owner":"rajat-mehra05","description":"A lightweight JavaScript API for retrieving transcripts and subtitles from YouTube videos. Works with both manual and auto-generated captions without requiring API keys or browser automation tools like Selenium.","archived":false,"fork":false,"pushed_at":"2026-03-22T15:09:31.000Z","size":519,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-23T04:54:49.853Z","etag":null,"topics":["captions","subtitles","transcript-api","translating-transcripts","youtube","youtube-api","youtube-captions","youtube-transcript","youtube-transcript-api"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/youtube-transcript-api-js","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rajat-mehra05.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-23T20:56:27.000Z","updated_at":"2026-03-22T15:09:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rajat-mehra05/youtube-transcript-api-js","commit_stats":null,"previous_names":["rajat-mehra05/youtube-transcript-api-js"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/rajat-mehra05/youtube-transcript-api-js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajat-mehra05%2Fyoutube-transcript-api-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajat-mehra05%2Fyoutube-transcript-api-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajat-mehra05%2Fyoutube-transcript-api-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajat-mehra05%2Fyoutube-transcript-api-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rajat-mehra05","download_url":"https://codeload.github.com/rajat-mehra05/youtube-transcript-api-js/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rajat-mehra05%2Fyoutube-transcript-api-js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31989341,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"ssl_error","status_checked_at":"2026-04-18T20:23:29.375Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["captions","subtitles","transcript-api","translating-transcripts","youtube","youtube-api","youtube-captions","youtube-transcript","youtube-transcript-api"],"created_at":"2026-01-24T11:07:10.646Z","updated_at":"2026-04-19T00:18:52.300Z","avatar_url":"https://github.com/rajat-mehra05.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# YouTube Transcript API\n\nA lightweight JavaScript/TypeScript library for retrieving transcripts and subtitles from YouTube videos. Supports manual and auto-generated captions, multiple languages, translation, and various output formats — no API keys or browser automation required.\n\n**Common use cases:** content analysis, accessibility tools, search indexing, language learning apps, video summarization, subtitle generation, and AI/NLP training data collection.\n\n## Installation\n\n```bash\nnpm install youtube-transcript-api-js\n```\n\nOr with yarn:\n\n```bash\nyarn add youtube-transcript-api-js\n```\n\n## Quick Start\n\n```typescript\nimport { YouTubeTranscriptApi } from 'youtube-transcript-api-js';\n\nconst api = new YouTubeTranscriptApi();\n\n// Fetch transcript for a video\nconst transcript = await api.fetch('dQw4w9WgXcQ');\n\nconsole.log(transcript.snippets);\n// Output: [{ text: '...', start: 0.0, duration: 1.5 }, ...]\n```\n\n## API Reference\n\n### YouTubeTranscriptApi\n\nThe main class for fetching transcripts.\n\n```typescript\nimport { YouTubeTranscriptApi } from 'youtube-transcript-api-js';\n\nconst api = new YouTubeTranscriptApi();\n```\n\n#### `fetch(videoId, languages?, preserveFormatting?)`\n\nFetches the transcript for a video.\n\n```typescript\n// Fetch with default language (English)\nconst transcript = await api.fetch('VIDEO_ID');\n\n// Fetch with specific languages (priority order)\nconst transcript = await api.fetch('VIDEO_ID', ['de', 'en']);\n\n// Preserve formatting (keeps HTML tags like \u003ci\u003e, \u003cb\u003e)\nconst transcript = await api.fetch('VIDEO_ID', ['en'], true);\n```\n\n**Parameters:**\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `videoId` | `string` | — | The YouTube video ID |\n| `languages` | `string[]` | `['en']` | Language codes in priority order |\n| `preserveFormatting` | `boolean` | `false` | Keep HTML formatting tags |\n\n**Returns:** `Promise\u003cFetchedTranscript\u003e`\n\n#### `list(videoId)`\n\nLists all available transcripts for a video.\n\n```typescript\nconst transcriptList = await api.list('VIDEO_ID');\n\n// Find a specific transcript\nconst transcript = transcriptList.findTranscript(['en', 'de']);\n\n// Get only auto-generated transcripts\nconst generated = transcriptList.findGeneratedTranscript(['en']);\n\n// Get only manually created transcripts\nconst manual = transcriptList.findManuallyCreatedTranscript(['en']);\n\n// Iterate over all transcripts\nfor (const transcript of transcriptList) {\n  console.log(`${transcript.languageCode}: ${transcript.language}`);\n}\n```\n\n#### Translating Transcripts\n\n```typescript\nconst transcriptList = await api.list('VIDEO_ID');\nconst transcript = transcriptList.findTranscript(['en']);\n\nif (transcript.isTranslatable) {\n  const translated = transcript.translate('de');\n  const fetched = await translated.fetch();\n  console.log(fetched.snippets);\n}\n```\n\n### Data Types\n\n```typescript\ninterface FetchedTranscript {\n  snippets: FetchedTranscriptSnippet[];\n  videoId: string;\n  language: string;\n  languageCode: string;\n  isGenerated: boolean;\n  toRawData(): Array\u003c{ text: string; start: number; duration: number }\u003e;\n}\n\ninterface FetchedTranscriptSnippet {\n  text: string;\n  start: number;\n  duration: number;\n}\n```\n\n## CLI Usage\n\n### Basic Commands\n\n```bash\n# Fetch transcript for a video\nyoutube-transcript-api VIDEO_ID\n\n# Fetch transcripts for multiple videos\nyoutube-transcript-api VIDEO_ID1 VIDEO_ID2 VIDEO_ID3\n\n# List available transcripts\nyoutube-transcript-api VIDEO_ID --list-transcripts\n```\n\n### Options\n\n| Option | Description | Example |\n|--------|-------------|---------|\n| `--list-transcripts` | List available transcript languages | `--list-transcripts` |\n| `--languages \u003ccodes...\u003e` | Language codes in priority order | `--languages de en` |\n| `--translate \u003ccode\u003e` | Translate to specified language | `--translate es` |\n| `--format \u003cformat\u003e` | Output format: `json`, `pretty`, `text`, `srt`, `webvtt`, `timestamped` | `--format srt` |\n| `--exclude-generated` | Exclude auto-generated transcripts | `--exclude-generated` |\n| `--exclude-manually-created` | Exclude manually created transcripts | `--exclude-manually-created` |\n| `--cookies \u003cfile\u003e` | Cookie file (Netscape/JSON) for authentication | `--cookies cookies.txt` |\n| `--verbose` | Print debug information to stderr | `--verbose` |\n| `--save \u003cfile\u003e` | Write output to a file instead of stdout | `--save output.txt` |\n| `--batch-file \u003cfile\u003e` | Read video IDs from a file (one per line) | `--batch-file ids.txt` |\n| `--fail-fast` | Stop on the first error | `--fail-fast` |\n| `--http-proxy \u003curl\u003e` | Use HTTP proxy | `--http-proxy http://proxy:8080` |\n| `--https-proxy \u003curl\u003e` | Use HTTPS proxy | `--https-proxy http://proxy:8080` |\n| `--webshare-proxy-username \u003cuser\u003e` | Webshare proxy username | `--webshare-proxy-username myuser` |\n| `--webshare-proxy-password \u003cpass\u003e` | Webshare proxy password | `--webshare-proxy-password mypass` |\n\n### Examples\n\n```bash\n# Get German transcript, fallback to English\nyoutube-transcript-api dQw4w9WgXcQ --languages de en\n\n# Export as SRT subtitle file\nyoutube-transcript-api dQw4w9WgXcQ --format srt \u003e subtitles.srt\n\n# Translate English transcript to Spanish\nyoutube-transcript-api dQw4w9WgXcQ --languages en --translate es\n\n# Use proxy for requests\nyoutube-transcript-api dQw4w9WgXcQ --http-proxy http://user:pass@proxy.com:8080\n\n# Get only manually created transcripts in JSON\nyoutube-transcript-api dQw4w9WgXcQ --exclude-generated --format json\n\n# Batch process videos from a file, save output, stop on error\nyoutube-transcript-api --batch-file video-ids.txt --save output.json --fail-fast --verbose\n\n# Fetch age-restricted video with cookies\nyoutube-transcript-api dQw4w9WgXcQ --cookies ~/cookies.txt\n```\n\n## Output Formatters\n\nFormat transcripts in different output formats.\n\n```typescript\nimport { FormatterLoader, SRTFormatter } from 'youtube-transcript-api-js';\n\nconst transcript = await api.fetch('VIDEO_ID');\n\n// Using FormatterLoader\nconst loader = new FormatterLoader();\nconst formatter = loader.load('srt');\nconsole.log(formatter.formatTranscript(transcript));\n\n// Or use formatters directly\nconst srtFormatter = new SRTFormatter();\nconsole.log(srtFormatter.formatTranscript(transcript));\n```\n\n| Format | Class | Description |\n|--------|-------|-------------|\n| `json` | `JSONFormatter` | Compact JSON output |\n| `pretty` | `PrettyPrintFormatter` | Pretty-printed JSON |\n| `text` | `TextFormatter` | Plain text (transcript only) |\n| `srt` | `SRTFormatter` | SubRip subtitle format |\n| `webvtt` | `WebVTTFormatter` | WebVTT subtitle format |\n| `timestamped` | `TimestampedTextFormatter` | LLM-friendly `[M:SS] text` format |\n\n### Timestamped Text Formatter\n\nProduces clean `[M:SS] text` output, ideal for feeding transcripts to LLMs. Supports grouping snippets into time buckets.\n\n```typescript\nimport { TimestampedTextFormatter } from 'youtube-transcript-api-js';\n\nconst formatter = new TimestampedTextFormatter();\nconst transcript = await api.fetch('VIDEO_ID');\n\n// Default: one line per snippet\nconsole.log(formatter.formatTranscript(transcript));\n// [0:00] Hello world\n// [0:05] This is a transcript\n\n// Grouped: combine snippets into 60-second buckets\nconsole.log(formatter.formatTranscript(transcript, { groupBySeconds: 60 }));\n// [0:00] Hello world This is a transcript ...\n// [1:00] Next minute of content ...\n```\n\n### Custom Formatters\n\nExtend the `Formatter` base class to create your own output format:\n\n```typescript\nimport { YouTubeTranscriptApi, Formatter, FetchedTranscript, FormatterOptions } from 'youtube-transcript-api-js';\n\nclass MarkdownFormatter extends Formatter {\n  formatTranscript(transcript: FetchedTranscript, options: FormatterOptions = {}): string {\n    return transcript.snippets\n      .map(s =\u003e `- **${this.toTimestamp(s.start)}** ${s.text}`)\n      .join('\\n');\n  }\n\n  formatTranscripts(transcripts: FetchedTranscript[], options: FormatterOptions = {}): string {\n    return transcripts.map(t =\u003e this.formatTranscript(t, options)).join('\\n\\n---\\n\\n');\n  }\n\n  private toTimestamp(seconds: number): string {\n    const m = Math.floor(seconds / 60);\n    const s = Math.floor(seconds % 60);\n    return `${m}:${s.toString().padStart(2, '0')}`;\n  }\n}\n\n// Usage:\nconst api = new YouTubeTranscriptApi();\nconst transcript = await api.fetch('VIDEO_ID');\n\nconst formatter = new MarkdownFormatter();\nconsole.log(formatter.formatTranscript(transcript));\n// - **0:00** Hello world\n// - **0:05** This is a test\n```\n\n## Proxy Support\n\n### Generic Proxy\n\n```typescript\nimport { YouTubeTranscriptApi, GenericProxyConfig } from 'youtube-transcript-api-js';\n\nconst proxyConfig = new GenericProxyConfig(\n  'http://user:pass@proxy.example.com:8080',  // HTTP\n  'http://user:pass@proxy.example.com:8080'   // HTTPS\n);\n\nconst api = new YouTubeTranscriptApi(proxyConfig);\n```\n\n### Webshare Rotating Proxy\n\nFor rotating residential proxies via [Webshare](https://www.webshare.io/).\n\n```typescript\nimport { YouTubeTranscriptApi, WebshareProxyConfig } from 'youtube-transcript-api-js';\n\nconst proxyConfig = new WebshareProxyConfig(\n  'your-username',\n  'your-password',\n  ['US', 'GB'],  // Filter by IP locations (optional)\n  10             // Retries when blocked (default: 10)\n);\n\nconst api = new YouTubeTranscriptApi(proxyConfig);\n```\n\n### Enhanced API with Proxy\n\nFor advanced use cases with Invidious fallback support.\n\n```typescript\nimport { EnhancedYouTubeTranscriptApi } from 'youtube-transcript-api-js';\n\nconst api = new EnhancedYouTubeTranscriptApi(\n  {\n    enabled: true,\n    http: 'http://user:pass@proxy.example.com:8080',\n    https: 'http://user:pass@proxy.example.com:8080'\n  },\n  {\n    enabled: true,\n    instanceUrls: ['https://invidious.example.com'],\n    timeout: 10000\n  }\n);\n\nconst transcript = await api.fetch('VIDEO_ID');\n```\n\n## Cookie Authentication\n\nAuthenticate requests using cookies for age-restricted or login-required videos. Export cookies from your browser using a \"cookies.txt\" extension.\n\n```typescript\nimport { YouTubeTranscriptApi } from 'youtube-transcript-api-js';\n\n// Pass cookie file path as an option\nconst api = new YouTubeTranscriptApi(undefined, undefined, {\n  cookiePath: '/path/to/cookies.txt'\n});\n\nconst transcript = await api.fetch('AGE_RESTRICTED_VIDEO_ID');\n```\n\nSupports both Netscape/Mozilla format (`.txt`) and JSON format (`.json`). Only cookies for YouTube/Google domains are used.\n\n## Retry Configuration\n\nRequests are automatically retried with exponential backoff on transient errors (`RateLimitExceeded`, `NetworkError`, `TimeoutError`, `ConnectionError`, `RequestBlocked`).\n\n```typescript\nimport { YouTubeTranscriptApi } from 'youtube-transcript-api-js';\n\nconst api = new YouTubeTranscriptApi(undefined, undefined, {\n  retryConfig: {\n    maxRetries: 5,        // default: 3\n    baseDelayMs: 1000,    // default: 1000\n    maxDelayMs: 30000,    // default: 30000\n    jitterFactor: 0.5,    // default: 0.5 (0-1)\n  }\n});\n```\n\n## Error Handling\n\n```typescript\nimport {\n  VideoUnavailable,\n  TranscriptsDisabled,\n  NoTranscriptFound,\n  RateLimitExceeded,\n  TimeoutError,\n  ConnectionError\n} from 'youtube-transcript-api-js';\n\ntry {\n  const transcript = await api.fetch('VIDEO_ID');\n} catch (error) {\n  if (error instanceof RateLimitExceeded) {\n    console.error(`Rate limited. Retry after ${error.retryAfter} seconds`);\n  } else if (error instanceof TimeoutError) {\n    console.error(`Request timed out after ${error.timeoutMs}ms`);\n  }\n}\n```\n\n| Error | Description |\n|-------|-------------|\n| `VideoUnavailable` | Video does not exist or is private |\n| `TranscriptsDisabled` | Subtitles are disabled for this video |\n| `NoTranscriptFound` | No transcript for requested languages |\n| `InvalidVideoId` | Invalid video ID (URL passed instead of ID) |\n| `AgeRestricted` | Video is age-restricted |\n| `VideoUnplayable` | Video cannot be played |\n| `RequestBlocked` | YouTube is blocking requests from your IP |\n| `IpBlocked` | IP address has been blocked |\n| `RateLimitExceeded` | Too many requests (HTTP 429) |\n| `NetworkError` | General network error |\n| `TimeoutError` | Request timed out |\n| `ConnectionError` | Failed to connect to server |\n\n## Tech Stack\n\n| Technology | Purpose |\n|------------|---------|\n| TypeScript | Type-safe JavaScript |\n| Axios | HTTP client |\n| Commander.js | CLI framework |\n| http-proxy-agent | Proxy support |\n| Jest | Testing |\n\n## Contributing\n\nContributions are welcome! Here's how you can help:\n\n- **Bug reports** — Open an [issue](https://github.com/rajat-mehra05/youtube-transcript-api-js/issues) with steps to reproduce\n- **Feature requests** — Open an [issue](https://github.com/rajat-mehra05/youtube-transcript-api-js/issues) to discuss your idea before submitting a PR\n- **Pull requests** — Fork the repo, create a branch, and submit a PR\n- **Questions \u0026 discussions** — Feel free to open an [issue](https://github.com/rajat-mehra05/youtube-transcript-api-js/issues) for general questions or discussions\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frajat-mehra05%2Fyoutube-transcript-api-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frajat-mehra05%2Fyoutube-transcript-api-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frajat-mehra05%2Fyoutube-transcript-api-js/lists"}