Get YouTube transcripts in Node.js
Get any YouTube video's transcript from Node 18+, Deno, Bun or an edge function with plain fetch. No dependencies, and no proxies to manage when you deploy.
1. Get an API key
Sign up with your email on the home page: you get a key with 100 free credits. Store it as TRANSKRIO_API_KEY.
2. Fetch a transcript
type Segment = { text: string; start: number; duration: number };
type Transcript = {
video_id: string; language_code: string; is_generated: boolean | null;
segments: Segment[]; text: string;
};
const API = "https://api.transkrio.com/v1";
const headers = { "x-api-key": process.env.TRANSKRIO_API_KEY! };
export async function getTranscript(url: string, lang?: string): Promise<Transcript> {
const params = new URLSearchParams({ url });
if (lang) params.set("lang", lang);
for (;;) {
const res = await fetch(`${API}/transcript?${params}`, { headers });
const body = await res.json();
if (res.status === 202) { // long audio still being transcribed
await new Promise((r) => setTimeout(r, body.retry_after * 1000));
continue;
}
if (!res.ok) throw new Error(body.error?.message ?? body.detail);
return body;
}
}
const t = await getTranscript("https://youtu.be/dQw4w9WgXcQ");
console.log(t.language_code, t.segments.length, t.text.slice(0, 200));
YouTube answers immediately. The 202 loop only matters for TikToks, Reels and podcast episodes that have no captions and are transcribed from the audio.
3. Subtitles or plain text
const srt = await fetch(`${API}/transcript?url=dQw4w9WgXcQ&format=srt`, { headers })
.then((r) => r.text());
4. Many videos at once
const res = await fetch(`${API}/batch`, {
method: "POST",
headers: { ...headers, "content-type": "application/json" },
body: JSON.stringify({ urls: ["dQw4w9WgXcQ", "https://youtu.be/jNQXAC9IVRw"], format: "text" }),
});
const { results, succeeded, failed, credits_charged } = await res.json();
Up to 50 URLs per batch. Results keep the order of urls, each with ok and either the transcript or an error. Failed items are free. To get a channel's or playlist's video URLs first, call /v1/videos?url=@handle.
Errors
Errors have a stable error.code: invalid_url, no_transcript, video_unavailable, video_restricted. They never cost credits. A 402 means the key is out of credits and 429 means more than 60 requests per minute.
See also: the Python version, the full API reference, and the MCP server if you are building an AI agent.