Skip to content

About

YouTube Transcript API Node.js / TypeScript SDK: get YouTube video transcripts, search YouTube, list channel and playlist videos. Typed, zero dependencies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

YouTube Transcript API: Node.js / TypeScript SDK

License Website TypeScript

The official Node.js / TypeScript SDK (@tubeagentkit/getyoutubetranscript) for the GetYouTubeTranscript YouTube Transcript API. Get YouTube video transcripts, captions and subtitles (optionally with per-line timestamps) in JavaScript without a Google API key, yt-dlp, or a headless browser, plus YouTube search, channel, and playlist data over a simple REST API.

  • Fully typed, Promise-based client
  • Zero dependencies - built on native fetch (Node 18+)
  • ESM and CommonJS builds, with .d.ts types included
  • Typed errors: every failed request throws a GetYouTubeTranscriptError with a code, message, and statusCode

npm

npm install @tubeagentkit/getyoutubetranscript

Works the same on a laptop, a VPS, a serverless function or a CI job: the API fetches transcripts on its own servers, so YouTube never sees (or blocks) your server's IP and there are no proxies to manage.

Quickstart

import { GetYouTubeTranscript } from "@tubeagentkit/getyoutubetranscript";

const client = new GetYouTubeTranscript({ apiKey: process.env.GYT_API_KEY! });

const { title, transcript, word_count } = await client.getTranscript({
  v: "https://www.youtube.com/watch?v=jNQXAC9IVRw",
});

console.log(title, word_count, transcript.slice(0, 200));

Timestamps

Pass timestamps: true to also get one entry per caption line in segments (same 1 credit). Without it, the response has no segments key.

const { transcript, segments } = await client.getTranscript({
  v: "5e37ZT3SQbk",
  timestamps: true,
});

console.log(segments?.[0]); // { start: 3.96, duration: 4.56, text: "So, Reed, education, which a lot of" }

Each segment is { start, duration, text } with start and duration in seconds (exported as the Segment type).

Where a transcript came from

Field Meaning
language_code The caption track actually returned
requested_language What you asked for. If it differs from language_code, YouTube didn't have that language
caption_type "manual" (uploaded by the creator), "auto" (YouTube speech recognition), or null if unknown
cached true when served from the stored copy rather than fetched from YouTube just now
fetched_at ISO 8601 time it was fetched from YouTube

Not sure which languages a video has? getTranscriptLanguages lists them for free, before you spend a credit:

const { default_language_code, languages } = await client.getTranscriptLanguages({ v: "kJQP7kiw5Fk" });
for (const lang of languages) console.log(lang.language_code, lang.caption_type, lang.name); // "es manual Spanish"

An empty languages list means the video has captions turned off.

Batch: many videos at once

Queue up to 100 videos in one call; transcripts are fetched in the background. Submitting is free, each video that returns a transcript costs 1 credit, and failed videos are never charged (10 videos where 2 have no captions = 8 credits).

const { batch_id } = await client.createBatch({ videos: ["jNQXAC9IVRw", "https://youtu.be/dQw4w9WgXcQ"] });
const result = await client.waitForBatch(batch_id); // polls, then collects every page

for (const item of result.items ?? []) {
  if (item.status === "succeeded") console.log(item.video_id, item.caption_type, item.transcript?.slice(0, 80));
  else console.log(item.video_id, "failed:", item.error_code); // e.g. TRANSCRIPT_DISABLED
}
console.log("credits used:", result.credits_charged);

getBatch({ id, offset, limit }) returns the status and one page if you'd rather poll yourself. Pass idempotencyKey to createBatch so a retried call returns the same batch instead of queuing a second one. Batches are kept for 7 days, and an account can have 5 unfinished batches at a time.

To be notified instead of polling, pass webhookUrl (public https). The response includes a webhook_secret (shown once); each delivery is signed, so check it against the raw body before trusting it:

import { verifyWebhookSignature } from "@tubeagentkit/getyoutubetranscript";

// e.g. a Next.js route handler
export async function POST(request: Request) {
  const body = await request.text(); // raw body, not re-serialized JSON
  if (!(await verifyWebhookSignature(body, request.headers.get("x-gyt-signature"), process.env.GYT_WEBHOOK_SECRET!))) {
    return new Response("invalid signature", { status: 401 });
  }
  const event = JSON.parse(body); // { event: "batch.completed", batch_id, results_url, ... }
  return new Response("ok");
}

Getting an API key

Every request needs an API key. New accounts get 100 free credits, no card required - grab one at getyoutubetranscript.com.

Prefer to do it in code? Use the self-serve signup flow, which sends a 6-digit email OTP and hands back a key once verified:

import { signup, verifySignup } from "@tubeagentkit/getyoutubetranscript";

await signup("you@example.com");
// check your inbox for the 6-digit code, then:
const { api_key } = await verifySignup("you@example.com", "123456");

Usage

Every method returns the parsed data payload directly - no need to unwrap { success, data } yourself.

// Search videos or channels
const results = await client.search({ q: "lofi beats" });

// Resolve a channel handle to its channel ID (free)
const { channel_id } = await client.resolveChannel({ handle: "@mkbhd" });

// List a playlist's videos
const playlist = await client.getPlaylist({ list: "PLillGF-RfqbYE6Ik_EuXA2iZFcE082B3s" });

// Channel metadata + latest uploads (free)
const channel = await client.getChannelLatest({ channel: "@mkbhd" });

// Search within a channel
const channelResults = await client.searchChannel({ channel: "@mkbhd", q: "iphone" });

// List all of a channel's uploads
const uploads = await client.listChannelVideos({ channel: "@mkbhd" });

// Check remaining credits, plan, and rate limit (free)
const { plan_credits_left, plan } = await client.getCredits();

Paginated endpoints (search, getPlaylist, searchChannel, listChannelVideos) return a continuation token you feed back in on the next call:

let page = await client.search({ q: "lofi beats" });
while (page.continuation_token) {
  page = await client.search({ pageToken: page.continuation_token });
}

Handling errors

import { GetYouTubeTranscriptError } from "@tubeagentkit/getyoutubetranscript";

try {
  await client.getTranscript({ v: "invalid" });
} catch (err) {
  if (err instanceof GetYouTubeTranscriptError) {
    console.error(err.statusCode, err.code, err.message);
    // e.g. 402 PAYMENT_REQUIRED "You have used all your credits."
  } else {
    throw err;
  }
}

API coverage

Method Endpoint Credits
getTranscript(params) GET /transcript (optional timestamps: true) 1
getTranscriptLanguages(params) GET /transcript/languages free
createBatch(params) POST /batch (up to 100 videos) 1 per successful video
getBatch(params) / waitForBatch(id) GET /batch free
search(params) GET /search 1
resolveChannel(params) GET /resolve free
getPlaylist(params) GET /playlist 1
getChannelLatest(params) GET /channel/latest free
searchChannel(params) GET /channel/search 1
listChannelVideos(params) GET /channel/videos 1
getCredits() GET /credits free
signup(email) POST /signup free
verifySignup(email, otp) POST /signup/verify free

Full parameter and response shapes are exported as TypeScript types (TranscriptData, SearchData, PlaylistData, etc.) - see src/types.ts or your editor's autocomplete.

Development

npm install
npm run build       # tsup -> dist/ (ESM + CJS + .d.ts)
npm test            # unit tests, mocked fetch, no network
npm run typecheck

Live integration tests hit the real API and are skipped unless GYT_API_KEY is set:

GYT_API_KEY=sk_live_... npm run test:live

Links

Related projects

Other ways to use the GetYouTubeTranscript API:

License

MIT © tubeagentkit

About

YouTube Transcript API Node.js / TypeScript SDK: get YouTube video transcripts, search YouTube, list channel and playlist videos. Typed, zero dependencies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages