|
| 1 | +# TranscriptFetch Node.js SDK |
| 2 | + |
| 3 | +The official Node.js / TypeScript client for the [TranscriptFetch API](https://transcriptfetch.com). Fetch YouTube transcripts, channels, playlists, and search as clean, typed data, with built-in retries, idempotency, and a typed error hierarchy. |
| 4 | + |
| 5 | +- Typed responses (full TypeScript types, ESM + CommonJS) |
| 6 | +- Automatic retries on 429 and 5xx with backoff |
| 7 | +- Auto-generated idempotency keys on writes |
| 8 | +- Auto-paginating async iterators |
| 9 | +- Zero runtime dependencies (uses the built-in `fetch`, Node 18+) |
| 10 | + |
| 11 | +## Install |
| 12 | + |
| 13 | +```bash |
| 14 | +npm install transcriptfetch |
| 15 | +``` |
| 16 | + |
| 17 | +## Quickstart |
| 18 | + |
| 19 | +```ts |
| 20 | +import { TranscriptFetch } from "transcriptfetch"; |
| 21 | + |
| 22 | +// apiKey falls back to the TRANSCRIPTFETCH_API_KEY env var |
| 23 | +const tf = new TranscriptFetch("tf_live_..."); |
| 24 | + |
| 25 | +const t = await tf.transcripts.video("https://youtu.be/aircAruvnKk"); |
| 26 | +console.log(t.title); |
| 27 | +console.log(t.text); |
| 28 | +for (const seg of t.segments) { |
| 29 | + console.log(`[${seg.start.toFixed(1)}] ${seg.text}`); |
| 30 | +} |
| 31 | + |
| 32 | +console.log("credits left:", t.usage?.balance); |
| 33 | +``` |
| 34 | + |
| 35 | +Keep your key server-side. Never ship it to the browser. |
| 36 | + |
| 37 | +## Endpoints |
| 38 | + |
| 39 | +```ts |
| 40 | +await tf.transcripts.video(video); // single transcript (text + segments) |
| 41 | +await tf.transcripts.channel(channel, { limit, cursor }); // a channel's videos (metadata) |
| 42 | +await tf.transcripts.playlist(playlist, { limit, cursor }); // a playlist's videos |
| 43 | +await tf.transcripts.search(query, { limit, cursor }); // search YouTube |
| 44 | +await tf.transcripts.batch(videoIds); // up to 50 transcripts in one call |
| 45 | +await tf.health(); // unauthenticated liveness probe |
| 46 | +``` |
| 47 | + |
| 48 | +## Pagination |
| 49 | + |
| 50 | +Skip cursor bookkeeping with the auto-paginating iterators: |
| 51 | + |
| 52 | +```ts |
| 53 | +for await (const video of tf.transcripts.iterChannel("@lexfridman", { limit: 10 })) { |
| 54 | + console.log(video.videoId, video.title); |
| 55 | +} |
| 56 | +``` |
| 57 | + |
| 58 | +Or page manually via `page.nextCursor` and the `cursor` option. |
| 59 | + |
| 60 | +## Errors |
| 61 | + |
| 62 | +Every failure maps to a typed subclass so you can branch with `instanceof`: |
| 63 | + |
| 64 | +```ts |
| 65 | +import { |
| 66 | + TranscriptFetch, |
| 67 | + InsufficientCreditsError, |
| 68 | + RateLimitError, |
| 69 | + APIError, |
| 70 | +} from "transcriptfetch"; |
| 71 | + |
| 72 | +try { |
| 73 | + await tf.transcripts.video("bad"); |
| 74 | +} catch (err) { |
| 75 | + if (err instanceof InsufficientCreditsError) { |
| 76 | + // 402: top up at /pricing |
| 77 | + } else if (err instanceof RateLimitError) { |
| 78 | + console.log("retry after", err.retryAfter); // 429 |
| 79 | + } else if (err instanceof APIError) { |
| 80 | + console.log(err.status, err.code, err.requestId); |
| 81 | + } |
| 82 | +} |
| 83 | +``` |
| 84 | + |
| 85 | +The full hierarchy: `AuthenticationError`, `InvalidRequestError`, `InsufficientCreditsError`, `IdempotencyConflictError`, `RateLimitError`, `UpstreamUnavailableError`, `InternalServerError` (all extend `APIError`), plus `APIConnectionError` and `APITimeoutError` for transport failures. All extend `TranscriptFetchError`. |
| 86 | + |
| 87 | +## Configuration |
| 88 | + |
| 89 | +```ts |
| 90 | +const tf = new TranscriptFetch({ |
| 91 | + apiKey: "tf_live_...", // or TRANSCRIPTFETCH_API_KEY |
| 92 | + baseUrl: "https://transcriptfetch.com", |
| 93 | + timeout: 30_000, // ms |
| 94 | + maxRetries: 2, // retries 429 + 5xx |
| 95 | +}); |
| 96 | +``` |
| 97 | + |
| 98 | +## Links |
| 99 | + |
| 100 | +- API docs: https://transcriptfetch.com/docs |
| 101 | +- Python SDK: https://github.com/TranscriptFetch/python-sdk |
| 102 | + |
| 103 | +## License |
| 104 | + |
| 105 | +MIT |
0 commit comments