NewMCP server live - use YouTube transcripts inside Claude Desktop & Cursor.Learn more →
Credits never expire. Not monthly, not ever.

The YouTube Transcript API
that doesn't break in production.

One API call. Timestamped JSON. No proxy setup, no RequestBlocked errors, no credits vanishing at midnight. Extract any YouTube transcript in your language, your format. Call it from Python, JavaScript, PHP, or plain curl — anything that speaks HTTP.

Get Started Free →

No credit card. No subscription. See all plans. Credits never expire.

Cached results return instantly · Whisper fallback built in
curl
python
javascript
# 1 credit · enqueue, then poll until completed
curl -X POST https://api.youtubetranscripts.co/v1/transcript \
  -H "Authorization: Bearer yt_live_••••••••" \
  -d '{"url":"https://youtu.be/dQw4w9WgXcQ","format":"json"}'

# 202 queued → poll GET /v1/transcript/:id → completed
{
  "status":    "completed",
  "video_id":  "dQw4w9WgXcQ",
  "result": {
    "language":          "en",
    "source":            "native_captions",
    "credits_used":      1,
    "credits_remaining": 99,
    "segments": [
      { "start": 1.36, "duration": 1.68, "text": "We're no strangers to love" }
    ]
  }
}
Never expire
Our credits
vs. monthly reset on Supadata
$5 entry
Lowest paid tier
vs. $9–10 elsewhere
<1.5s
Response time
native captions
45 langs
Languages supported
auto-detect or specify
The problem

You've already tried
the free library.
It broke.

“Deployed to Railway Sunday night. Got RequestBlocked within the hour. Client demo Monday morning.”- Actual developer, actual Slack message

The open-source youtube-transcript-api library is brilliant on localhost. The moment it hits a cloud IP - AWS, GCP, Railway, Render, Vercel - YouTube sees it and blocks it. Every time.

So you spend a weekend on proxy rotation. Then the proxies get flagged. Then YouTube updates something and the whole thing breaks again. This is not a problem worth solving yourself.

production.log - 3:14 AM
$ python app.py ← local, works fine
$ git push && railway up
Deploying to prod...
Build complete. ✓

TranscriptsDisabled:
Could not retrieve a transcript
for the video dQw4w9WgXcQ.

RequestBlocked:
YouTube is blocking requests
from this IP address.

# Client demo at 9 AM.
# You are not okay.

$ curl api.youtubetranscripts.co \
-d '{"url":"..."}'
→ {"source":"native_captions",...} ✓
# Went to bed.
How it works

Get a YouTube transcript
in under 2 minutes.

No infrastructure to manage. No proxies to rotate. No YouTube bot detection to battle. Just a clean YouTube Transcript API that returns what you need.

1

Sign up with email

Create an account with your email and password, confirm via the verification link, then generate an API key in your dashboard. No credit card, no approval queue.

100 free credits, waiting for you
2

Make your first call

Pass any public YouTube URL. Choose your language and format (json, text, srt, vtt). Whisper fallback runs automatically when a video has no captions.

Cached videos come back instantly
3

Ship your product

Timestamped segments, word count, balance remaining, video metadata - all in one response. Pipe it straight into your LLM, vector DB, or content pipeline.

Never worry about IP blocks again
Features

Built for developers
who ship fast.

Fast, cached responses

Native caption extraction is fast, and anything we've fetched before is served straight from cache — often before your UI spinner completes its first rotation.

Per-segment timestamps

Every segment returns start and duration in seconds. Build transcript viewers, chapter markers, and searchable archives.

0
credits lost at month-end, ever

Credits that never expire

Buy once. Use whenever. No monthly resets, no “use it or lose it” anxiety.

AI fallback via Whisper

Video has no captions? We run OpenAI Whisper automatically — no flag needed (or set native_only=true to skip it). 1 credit per video-minute. Response includes source: "whisper".

45 languages

Auto-detect or pass an ISO-639 code. 45 languages supported, with optional translation.

enesfrdeptjazhkoar+36

Five output formats

Choose json, text, text-timestamps, srt, or vtt. Works as a YouTube captions API, subtitles API, or raw transcript source.

Metadata always free

Title, channel, duration, and thumbnail — bundled with every transcript call at no extra cost. Never a separate API hit.

Works in production

Handles proxy rotation, IP management, and YouTube changes automatically. No more RequestBlocked errors on AWS, GCP, or Railway.

Use cases

What developers build
with the YouTube Transcript API.

The same API. Six completely different products.

AI · RAG

Chatbots & RAG pipelines

Feed transcripts into your vector DB. Let users ask questions about any video. Build knowledge bases from entire channels in hours.

Content

Content repurposing at scale

One 20-minute video becomes a blog post, 10 tweets, a newsletter section, and show notes. No manual copy-paste.

Research

Brand & competitor monitoring

Track what's being said about your brand across YouTube at scale. Mine transcripts for signals competitors haven't noticed.

Accessibility

Captions for uncaptioned videos

Meet ADA, WCAG, and EU accessibility mandates. AI fallback generates captions even when YouTube doesn't provide them.

SEO

Video SEO & search indexing

Search engines can't watch video. Publish the full transcript alongside each video. More text means more index surface.

Training data

AI training datasets

Process entire channels or curated playlists. Clean JSON straight into your labelling pipeline. Up to 100 videos per batch call.

Integrations

Plug into your
existing stack.

LangChain
LlamaIndex
n8n
Make
Zapier
ActivePieces
Claude Desktop
Cursor
Windsurf
Supabase
Pinecone
Weaviate
REST API & MCP

YouTube Transcript API
in the language you already write.

A plain REST API, an MCP server, and no-code connectors — all from one API key. No SDK lock-in.

python · requests
import time, requests

API = "https://api.youtubetranscripts.co"
headers = {"Authorization": "Bearer yt_your_key"}

# Enqueue — 1 credit, native captions
job = requests.post(f"{API}/v1/transcript",
    json={"url": "https://youtu.be/VIDEO_ID", "language": "en", "format": "json"},
    headers=headers).json()

# Poll until status == "completed"
res = requests.get(f"{API}/v1/transcript/{job['id']}", headers=headers).json()
data = res["result"]

# segments carry start + duration (seconds)
for seg in data["segments"]:
    print(f"{seg['start']}s → {seg['text']}")

print(data["source"], data["credits_remaining"])
javascript / typescript · fetch
const API = 'https://api.youtubetranscripts.co'
const headers = {
  Authorization: 'Bearer yt_your_key',
  'Content-Type': 'application/json',
}

// Enqueue — 1 credit
const job = await (await fetch(`${API}/v1/transcript`, {
  method: 'POST', headers,
  body: JSON.stringify({ url: 'https://youtu.be/VIDEO_ID', format: 'json' }),
})).json()

// Poll GET /v1/transcript/:id until status === 'completed'
const res = await (await fetch(`${API}/v1/transcript/${job.id}`, { headers })).json()
console.log(res.result.transcript, res.result.credits_remaining)
php · cURL
$ch = curl_init("https://api.youtubetranscripts.co/v1/transcript");
curl_setopt_array($ch, [
  CURLOPT_POST           => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER     => ["Authorization: Bearer yt_your_key", "Content-Type: application/json"],
  CURLOPT_POSTFIELDS     => json_encode(["url" => "https://youtu.be/VIDEO_ID", "format" => "json"]),
]);
$job = json_decode(curl_exec($ch), true);

// Poll GET /v1/transcript/{id} until status == "completed"
echo $job["id"];
curl · works anywhere HTTP works
# Enqueue a transcript (1 credit)
curl -X POST https://api.youtubetranscripts.co/v1/transcript \
  -H "Authorization: Bearer yt_your_key" \
  -d '{"url":"https://youtu.be/VIDEO_ID","format":"json"}'

# Poll until status is "completed"
curl https://api.youtubetranscripts.co/v1/transcript/REQUEST_ID \
  -H "Authorization: Bearer yt_your_key"

# Bulk — a playlist, a channel, or up to 100 URLs
curl -X POST https://api.youtubetranscripts.co/v1/transcripts/bulk \
  -H "Authorization: Bearer yt_your_key" \
  -d '{"urls":["ID_1","ID_2","ID_3"]}'

# Remaining balance
curl https://api.youtubetranscripts.co/v1/credits \
  -H "Authorization: Bearer yt_your_key"
Claude Desktop

Pull transcripts directly inside Claude conversations via MCP

Cursor

Transcribe YouTube from your code editor, no context switching

Windsurf / Zed

MCP server installs in under 30 seconds

Comparison

Why developers
switch to us.

The only YouTube Transcript API with never-expire credits, AI fallback, and no subscription. Get YouTube transcripts in production without IP blocks or broken scrapers.

ProviderCredits expire?AI fallbackNo subscriptionEntry priceWorks in production?
YouTubeTranscripts.co us Never expire Whisper Pay once$5 for 300 Always
Supadata⚠ Monthly reset Sub only$5/mo → 300⚠ Intermittent
ScrapeCreators Never expire$10 for 1,000
TranscriptAPI.com⚠ End of period Sub only~$10/mo
Transcribr.io⚠ 6-month limit$9 for 500
Open-source libraryN/A - free$0 Blocked by cloud IPs
Pricing

Buy once.
Use forever.

No subscriptions. No resets. No auto-charge. Credits stack - buy multiple packs and balances combine.

Credits never expire
Packs stack and combine
No subscription ever
Failed requests = 0 credits
Free forever
Trial
$0
100 credits
no card needed
Never expire on active accounts
  • 100 real API calls
  • Native captions only
  • Full dashboard access
  • AI fallback (Whisper)
  • Batch API
Starter
$5
300 credits
$16.67 per 1,000
Never expire
  • 300 transcripts
  • Native captions
  • Full dashboard
  • AI fallback
  • Batch API
Basic
$19
2,000 credits
$9.50 per 1,000
Never expire
  • 2,000 transcripts
  • Native + AI fallback
  • Browse & search endpoints
  • MCP server access
  • Batch API
Most popular
Pro
$59
10,000 credits
$5.90 per 1,000
Never expire
  • 10,000 transcripts
  • Native + AI fallback
  • Batch API (100 videos)
  • Priority support
  • 99.5% uptime SLA
Growth
$149
40,000 credits
$3.73 per 1,000
Never expire
  • 40,000 transcripts
  • Native + AI fallback
  • Batch API (100 videos)
  • Priority + Slack support
  • 99.5% uptime SLA
Scale
$250
100,000 credits
$2.50 per 1,000
Never expire
  • 100,000 transcripts
  • Native + AI fallback
  • Batch API (100 videos)
  • Dedicated Slack channel
  • 99.9% uptime SLA
📄
1 credit = 1 transcript when the video has native captions. Covers ~85% of YouTube.
🤖
AI fallback = 1 credit/minute via Whisper when no captions exist. A 10-min video = 10 credits.
🎁
Metadata always free. Title, channel, duration, and thumbnail bundled with every transcript call.
🛡️
Failed requests cost nothing. Credits are only charged after a transcript succeeds, so a failure for any reason is never billed.
FAQ

Everything you
need to know.

How do I use the YouTube Transcript API with Python?+
It's a plain REST API, so use requests — no SDK to install. POST to /v1/transcript with an Authorization: Bearer header and a video URL. The API is asynchronous: you get back a queued request, then poll GET /v1/transcript/{id} until status is completed. The result holds transcript, a segments array (each with start and duration in seconds), language, source, and credits_remaining. Full examples in the API docs.
Do YouTube Transcript API credits really never expire?+
Yes. Paid pack credits are permanent, no expiry under any conditions. Unlike Supadata (monthly reset) and TranscriptAPI.com (end-of-period expiry), your balance is a permanent asset you spend at your own pace. The free-tier 100 credits never expire either.
What happens when a YouTube video has no captions?+
On the Basic plan and above, we fall back to OpenAI Whisper automatically — no flag required. We download the audio and transcribe it. Cost: 1 credit per video-minute (rounded up), so a 10-minute video costs 10 credits. The response includes source: "whisper" so you always know which path ran. Set native_only: true to skip Whisper and fail fast instead. On the free tier (native captions only), uncaptioned videos return a clear error.
Is there a YouTube Transcript API for JavaScript / TypeScript?+
Yes — it's a standard REST API, so fetch or axios works in Node.js 18+, Bun, and Deno with full async/await. POST to /v1/transcript and poll GET /v1/transcript/{id} until it's complete. There's also an MCP server for Claude Desktop, Cursor, and Windsurf - pull YouTube transcripts inside your AI assistant without writing any HTTP calls.
Is there a free YouTube Transcript API?+
Yes. YouTubeTranscripts.co offers a free YouTube Transcript API tier — your first 100 credits are completely free with no credit card. These never expire on active accounts. Paid packs start at $5 for 300 credits, and those never expire either. There is no subscription, no monthly fee, no auto-charge of any kind.
How is this different from the open-source youtube-transcript-api?+
The open-source library works perfectly on localhost. The moment it hits a cloud provider - AWS, GCP, Railway, Render, Vercel - YouTube sees the cloud IP and blocks it with a TranscriptsDisabled or RequestBlocked error. YouTubeTranscripts.co handles proxy rotation, IP management, and YouTube API changes automatically. Your production app never breaks.
How fast is the API? What are the rate limits?+
Transcripts you've fetched before are cached, so repeat requests come back fast. Fresh native-caption fetches typically complete in a few seconds; Whisper transcriptions take longer (15–45 seconds depending on length) because they process the full audio. The rate limit is 100 requests per minute per API key, and every response carries X-RateLimit-Limit, -Remaining, and -Reset headers plus credits_remaining — so you never need a separate balance call.
Can I stack multiple credit packs?+
Yes. Packs stack. If you have 500 credits remaining and buy a Pro pack (10,000 credits), your new balance is 10,500. Credits from different packs are pooled into a single balance. There is no cap on how many packs you can hold.

What is a YouTube Transcript API?

A YouTube Transcript API is a programmatic interface for extracting the text content of YouTube videos: auto-generated captions, manually uploaded subtitles, and AI-generated transcriptions for uncaptioned videos. It is also commonly referred to as a YouTube captions API or YouTube subtitles API — all three terms describe the same underlying capability. YouTube's official Data API v3 does not expose transcripts to third-party developers, so every service in this category works by accessing YouTube's public caption infrastructure directly.

The key differences between providers are: reliability in cloud environments, pricing model, and what happens when a video has no captions. The open-source youtube-transcript-api Python library is the most popular starting point, but it fails consistently when deployed to cloud providers because YouTube blocks their IP ranges.

Common production use cases include:

  • Building RAG (Retrieval-Augmented Generation) pipelines from YouTube content
  • Content repurposing - video to blog post, newsletter, or social thread
  • Brand and competitor monitoring across YouTube at scale
  • AI training dataset creation from video content
  • Accessibility compliance - generating captions for ADA and WCAG requirements
  • Video SEO - publishing full transcripts to improve search indexing

YouTube Transcript API: Python quick start

There's no SDK to install — it's a plain REST API you call with requests. Enqueue a request, poll until it's done, and get structured data back with timestamps and metadata included.

import time, requests API = "https://api.youtubetranscripts.co" headers = {"Authorization": "Bearer yt_your_api_key"} # 1. Enqueue - 1 credit, native captions job = requests.post( f"{API}/v1/transcript", json={"url": "https://youtu.be/VIDEO_ID", "format": "json"}, headers=headers, ).json() # 2. Poll until status == "completed" res = job while res["status"] in ("queued", "processing"): time.sleep(1.5) res = requests.get( f"{API}/v1/transcript/{job['id']}", headers=headers ).json() data = res["result"] # Plain text print(data["transcript"]) # Per-segment timestamps (start + duration in seconds) for seg in data["segments"]: print(f"{seg['start']}s: {seg['text']}") print(data["source"], data["credits_remaining"])

The response includes credits_remaining in every call. You never need a separate balance endpoint. Full API reference at the API docs.

Start in the next
two minutes.

100 free credits. No card. No subscription. Credits that actually stay in your account.

Get Started Free →

No credit card. No subscription. Free credits never expire.