YouTube Transcript API
The TubeTranscript API returns a YouTube video's timestamped transcript as JSON from one POST /api/v1/extract call. It reads the captions first and, when a video has none, transcribes the audio with Whisper. It needs a Pro API key ($9/month).
curl -X POST https://tubetranscript.io/api/v1/extract \
-H "Authorization: Bearer $TUBETRANSCRIPT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.youtube.com/watch?v=jNQXAC9IVRw"}'Pro plan required. Free accounts can run the same extraction on the home page.
Get a transcript with one request
Send POST https://tubetranscript.io/api/v1/extract with an Authorization: Bearer header and a JSON body. url is any YouTube video link (watch, youtu.be, shorts, embed or live), up to 2,048 characters. The optional features array asks for hooks, mindmap and action_items in the same call. Set your client timeout to 300 seconds.
import os, time, requests
def get_transcript(video_url):
api_key = os.environ['TUBETRANSCRIPT_API_KEY']
while True:
r = requests.post(
'https://tubetranscript.io/api/v1/extract',
headers={'Authorization': f'Bearer {api_key}'},
json={'url': video_url},
timeout=300,
)
body = r.json()
if r.status_code == 202: # audio transcription still running
time.sleep(int(r.headers.get('Retry-After', 60)))
continue # send the same request again
if not body['success']:
raise RuntimeError(body['error']['code'])
return body['data']
data = get_transcript('https://www.youtube.com/watch?v=jNQXAC9IVRw')
print(data['transcript']['text'])async function getTranscript(videoUrl) {
while (true) {
const res = await fetch('https://tubetranscript.io/api/v1/extract', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TUBETRANSCRIPT_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ url: videoUrl }),
signal: AbortSignal.timeout(300000),
});
const body = await res.json();
if (res.status === 202) {
// audio transcription still running: wait, then send the same request again
const seconds = Number(res.headers.get('Retry-After') ?? 60);
await new Promise(resolve => setTimeout(resolve, seconds * 1000));
continue;
}
if (!body.success) throw new Error(body.error.code);
return body.data;
}
}
const data = await getTranscript('https://www.youtube.com/watch?v=jNQXAC9IVRw');
console.log(data.transcript.text);Response fields
Every response, success or error, has the same envelope: success, data and error (code, message). On success, data holds:
| Field | Meaning |
|---|---|
video_id | The 11-character YouTube video ID taken from url. |
source | captions, audio (Whisper) or existing_job (your team already had a job for this video). |
language | Caption language code when source is captions, otherwise null. |
job_id | Set when the transcript came from an extraction job, otherwise null. |
video_title, channel_name | Set when the transcript came from a job, otherwise null. |
transcript.text | The whole transcript as plain text, without timestamps. |
transcript.chunks | Timed lines: { start, duration, text }, start and duration in seconds. |
features | Only the features you asked for: hooks, mindmap, action_items. |
Videos without captions
- The API first reuses your team's job for the same video, then reads the video's captions, which takes seconds.
- When there are no captions, it transcribes the audio with Whisper. That can take minutes.
- If transcription is still running when the request runs out of time, you get
202 EXTRACTION_IN_PROGRESSwithRetry-After: 60. Send the same request again: it resumes that job, so nothing is transcribed twice. - On Pro, audio transcription handles videos up to 2 hours. Private and removed videos, and live streams in progress, fail.
Not writing code? Get a transcript of a video without captions in the browser, or read why a transcript is not available.
Authentication and limits
| Plan | Pro, $9/month. Only keys from teams on Pro are accepted. |
|---|---|
| Authentication | Authorization: Bearer <API_KEY>. A missing or unknown key gets 401 (MISSING_API_KEY, INVALID_API_KEY); a key of a team that is not on Pro gets 403 PLAN_UPGRADE_REQUIRED. |
| API keys | Created by the team owner in the dashboard, up to 10 active keys per team. A key is shown once; we store only a hash. |
| Rate limit | 1,000 requests per 24 hours per key. Each call counts once. X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset show what is left. |
| Long transcripts | AI features split transcripts over 120,000 characters into segments and merge the results; the ceiling is 1,200,000 characters. |
Already on Pro? Manage your keys in the dashboard. Key handling and limits in detail: security and rate limits.
Errors
Branch on error.code, not on the message text. Only 202 and 502 carry a non-null data.
| HTTP | Code | Meaning | What to do |
|---|---|---|---|
| 202 | EXTRACTION_IN_PROGRESS | Whisper is still transcribing the audio. | Send the same request again after Retry-After seconds. |
| 400 | INVALID_JSON, INVALID_INPUT | The body is not JSON, or url or features is invalid. | Fix the field named in the message. |
| 401 | MISSING_API_KEY, INVALID_API_KEY | No key, or a malformed, unknown or revoked key. | Send a valid Pro key in the Bearer header. |
| 403 | PLAN_UPGRADE_REQUIRED | The key belongs to a team that is not on Pro. | Upgrade the team to Pro. |
| 404 | TRANSCRIPT_NOT_FOUND | The video is not available. | Check the URL. |
| 405 | METHOD_NOT_ALLOWED | A method other than POST. | Use POST. |
| 422 | EXTRACTION_FAILED | The video could not be transcribed: private, removed or no speech. | Try another video. |
| 429 | RATE_LIMIT_EXCEEDED | The 24-hour limit of the key is used up. | Wait Retry-After seconds. |
| 500 | INTERNAL_ERROR, WORKER_ERROR | Unexpected server or worker error. | Retry later. |
| 502 | FEATURES_FAILED | Some AI features failed; data still holds the transcript and the features that worked. | Retry for the failed features. |
| 503 | WORKER_UNAVAILABLE, RATE_LIMIT_UNAVAILABLE | The extraction service or the quota store is unreachable. | Retry later. |
The full API reference lists every field and code.
Use it in n8n, Make and MCP
- n8n: call the endpoint from an HTTP Request node with a 300 s timeout, enable Settings → Never Error and branch on
success. - Make: set Evaluate all states as errors to No, then branch on
success. - Claude and Cursor: connect the MCP server with the same Pro key; it exposes a
get_transcripttool. See the MCP setup.
New to the API? The quickstart covers the first request end to end.
Compared with the youtube-transcript-api Python library
youtube-transcript-api is a Python library you run yourself. It is a good fit when you work from your own machine or already run a proxy.
| Aspect | youtube-transcript-api (library) | TubeTranscript API |
|---|---|---|
| Where it runs | In your code, from your IP | Hosted: you send one HTTPS request |
| IP blocks | YouTube can block the IP it runs from; proxies are yours to set up | No proxy to set up on your side |
FAQ
How much does the YouTube transcript API cost?
The API is part of the Pro plan, $9/month. One Pro API key can make up to 1,000 requests per 24 hours. See pricing.
Does it work for videos without captions?
Yes. The API reads the captions first. If there are none, it transcribes the audio with Whisper, which can take minutes. If that is still running, you get a 202 response: send the same request again after the Retry-After delay. Pro covers videos up to 2 hours.
What is the rate limit?
Up to 1,000 requests per 24 hours per API key, under fair use. Each call counts once, whatever features it asks for. The X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers show what is left. Over the limit you get 429 RATE_LIMIT_EXCEEDED with a Retry-After header.
Is there a free API key?
No. Only API keys from teams on the Pro plan are accepted; other keys get 403 PLAN_UPGRADE_REQUIRED. To see what a transcript looks like first, paste a link on the home page.
What output formats does the API return?
JSON only. Each response holds the transcript as plain text and as timed chunks with start and duration in seconds. You can add hooks, mindmap and action_items to the same call. For SRT or VTT files, use YouTube to SRT or YouTube to VTT.
Can I use it with MCP, n8n or Make?
Yes. Call POST /api/v1/extract from an HTTP node in n8n or Make. Claude and Cursor can use the same Pro key through the MCP server: see the MCP setup guide.
Ready to call it? Pro is $9/month.
By Kenji Saito · Updated