Skip to content

YouTube Transcript API Reference

The YouTube Transcript API provides a simple and reliable way to extract transcripts from YouTube videos programmatically. This complete reference covers authentication, request parameters, response formats, and practical examples.

Want to test the API interactively? Try our Swagger UI where you can make live requests right in your browser.

All API requests are made to:

https://transcriptapi.com/api/v2

The API provides the following endpoints:

EndpointDescriptionCredits
GET /youtube/transcriptExtract video transcript1
GET /youtube/searchSearch YouTube videos or channels1
GET /youtube/channel/resolveResolve @handle/URL to channel IDFree
GET /youtube/channel/searchSearch within a channel1
GET /youtube/channel/videosPaginated channel uploads1/page
GET /youtube/channel/latestLatest 15 videos via RSSFree
GET /youtube/playlist/videosPaginated playlist videos1/page

Here’s how to make your first API request:

Terminal window
curl -X GET "https://transcriptapi.com/api/v2/youtube/transcript?video_url=dQw4w9WgXcQ" \
-H "Authorization: Bearer YOUR_API_KEY"

Don’t have an API key yet? Get one from your dashboard.

Expected Response:

{
"video_id": "dQw4w9WgXcQ",
"language": "en",
"transcript": [
{
"text": "Never gonna give you up",
"start": 0.0,
"duration": 4.12
},
{
"text": "Never gonna let you down",
"start": 4.12,
"duration": 3.85
}
]
}

The API uses Bearer token authentication. Include your API key in the Authorization header of every request:

Authorization: Bearer YOUR_API_KEY

Example:

Terminal window
curl -X GET "https://transcriptapi.com/api/v2/youtube/transcript?video_url=..." \
-H "Authorization: Bearer YOUR_API_KEY"

Get your API key from your API Keys dashboard.

The YouTube video URL or video ID to fetch transcripts for.

PropertyValue
Typestring
Pattern^([a-zA-Z0-9_-]{11}|https?://.\*)$
RequiredYes

Accepted Formats:

  • Full YouTube URL: https://www.youtube.com/watch?v=dQw4w9WgXcQ
  • Short YouTube URL: https://youtu.be/dQw4w9WgXcQ
  • Video ID only: dQw4w9WgXcQ

Examples:

Terminal window
# Full URL
?video_url=https://www.youtube.com/watch?v=dQw4w9WgXcQ
# Short URL
?video_url=https://youtu.be/dQw4w9WgXcQ
# Video ID only
?video_url=dQw4w9WgXcQ

The output format for the transcript response.

PropertyValue
Typestring
Valuesjson, text
Defaultjson
  • json: Returns structured data with transcript segments
  • text: Returns plain text transcript

Whether to include timestamps in the transcript output.

PropertyValue
Typeboolean
Defaulttrue

Behavior Matrix:

Formatinclude_timestampOutput
jsontrueSegments with text, start, duration
jsonfalseSegments with only text
texttrueLines formatted as [123.45s] text
textfalsePlain concatenated text

Whether to include video metadata in the response.

PropertyValue
Typeboolean
Defaultfalse

When enabled, includes:

  • title: Video title
  • author_name: Channel name
  • author_url: Channel URL
  • thumbnail_url: Video thumbnail

The API supports multiple response formats based on your parameters:

{
"video_id": "dQw4w9WgXcQ",
"language": "en",
"transcript": [
{
"text": "Never gonna give you up",
"start": 0.0,
"duration": 4.12
},
{
"text": "Never gonna let you down",
"start": 4.12,
"duration": 3.85
}
],
"metadata": {
"title": "Rick Astley - Never Gonna Give You Up",
"author_name": "RickAstleyVEVO",
"author_url": "https://www.youtube.com/@RickAstley",
"thumbnail_url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg"
}
}
HeaderDescription
X-Cache-StatusCache status: HIT, PARTIAL-HIT, or MISS

GET /youtube/search

Search YouTube for videos or channels.

ParameterTypeRequiredDefaultDescription
qstringYesSearch query (1–200 characters)
typestringNovideoResult type: video or channel
limitintegerNo20Max results to return (1–50)
{
"results": [
{
"type": "video",
"videoId": "dQw4w9WgXcQ",
"title": "Rick Astley - Never Gonna Give You Up",
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"channelTitle": "Rick Astley",
"channelHandle": "@RickAstley",
"channelVerified": true,
"lengthText": "3:33",
"viewCountText": "1.5B views",
"publishedTimeText": "14 years ago",
"hasCaptions": true,
"thumbnails": [
{"url": "https://i.ytimg.com/vi/dQw4w9WgXcQ/default.jpg", "width": 120, "height": 90}
]
}
],
"result_count": 20
}

Example:

Terminal window
curl -X GET "https://transcriptapi.com/api/v2/youtube/search?q=python+tutorial&type=video&limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"

GET /youtube/channel/resolve

Resolve any channel reference (@handle, URL, or UC… ID) to a canonical UC… channel ID. Free — no credits charged.

ParameterTypeRequiredDescription
inputstringYes@handle, channel URL, or UC… ID (1–200 characters)

Response:

{
"channel_id": "UCuAXFkgsw1L7xaCfnd5JJOw",
"resolved_from": "@mkbhd"
}

Example:

Terminal window
curl -X GET "https://transcriptapi.com/api/v2/youtube/channel/resolve?input=@mkbhd" \
-H "Authorization: Bearer YOUR_API_KEY"
GET /youtube/channel/search

Search for videos within a specific channel.

ParameterTypeRequiredDefaultDescription
channel_idstringYesChannel ID (must start with UC, 24 characters)
qstringYesSearch query (1–200 characters)
limitintegerNo30Max results (1–50)

Response:

{
"results": [
{
"type": "video",
"videoId": "abc123xyz00",
"title": "Video Title",
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"channelTitle": "MKBHD",
"channelHandle": "@mkbhd",
"channelVerified": true,
"lengthText": "12:34",
"viewCountText": "2.1M views",
"publishedTimeText": "3 months ago",
"hasCaptions": true,
"thumbnails": [...]
}
],
"result_count": 12
}

Example:

Terminal window
curl -X GET "https://transcriptapi.com/api/v2/youtube/channel/search?channel_id=UCBcRF18a7Qf58cCRy5xuWwQ&q=review&limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"
GET /youtube/channel/videos

List all videos uploaded to a channel, paginated at ~100 per page.

ParameterTypeRequiredDescription
channel_idstringConditionalChannel ID (first page). Must start with UC.
continuationstringConditionalContinuation token from previous response (next pages).

Provide exactly one of channel_id or continuation.

Response:

{
"results": [
{
"videoId": "abc123xyz00",
"title": "Latest Video",
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"channelTitle": "MKBHD",
"channelHandle": "@mkbhd",
"lengthText": "15:22",
"viewCountText": "3.2M views 2 weeks ago",
"thumbnails": [...],
"index": "0"
}
],
"playlist_info": {
"title": "Uploads from MKBHD",
"numVideos": "1893",
"description": "",
"ownerName": "MKBHD",
"viewCount": null
},
"continuation_token": "4qmFsgKlARIYVVV1QVhGa2dz...",
"has_more": true
}

Pagination flow:

  1. First request: ?channel_id=UCuAXFkgsw1L7xaCfnd5JJOw — returns first ~100 videos + continuation_token
  2. Next request: ?continuation=4qmFsgKlARIYVVV1QVhGa2dz... — returns next ~100 + new token
  3. Repeat until has_more is false or continuation_token is null

Example:

Terminal window
# First page
curl -X GET "https://transcriptapi.com/api/v2/youtube/channel/videos?channel_id=UCBcRF18a7Qf58cCRy5xuWwQ" \
-H "Authorization: Bearer YOUR_API_KEY"
# Next page
curl -X GET "https://transcriptapi.com/api/v2/youtube/channel/videos?continuation=4qmFsgKlARIYVVV1QVhGa2dz..." \
-H "Authorization: Bearer YOUR_API_KEY"
GET /youtube/channel/latest

Get the latest 15 videos from a channel via YouTube RSS feed. Returns exact publish timestamps and view counts. Free — no credits charged.

ParameterTypeRequiredDescription
channel_idstringYesChannel ID (must start with UC, 24 characters)

Response:

{
"channel": {
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"title": "MKBHD",
"author": "MKBHD",
"url": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw",
"published": "2008-03-21T00:00:00Z"
},
"results": [
{
"videoId": "abc123xyz00",
"title": "Latest Video Title",
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"author": "MKBHD",
"published": "2026-01-30T16:00:00Z",
"updated": "2026-01-31T02:00:00Z",
"link": "https://www.youtube.com/watch?v=abc123xyz00",
"description": "Full video description...",
"thumbnail": {"url": "https://i1.ytimg.com/vi/abc123xyz00/hqdefault.jpg", "width": "480", "height": "360"},
"viewCount": "2287630",
"starRating": {"average": "4.92", "count": "45000", "min": "1", "max": "5"}
}
],
"result_count": 15
}

Example:

Terminal window
curl -X GET "https://transcriptapi.com/api/v2/youtube/channel/latest?channel_id=UCBcRF18a7Qf58cCRy5xuWwQ" \
-H "Authorization: Bearer YOUR_API_KEY"

GET /youtube/playlist/videos

List videos in a playlist, paginated at ~100 per page.

ParameterTypeRequiredDescription
playlist_idstringConditionalPlaylist ID (first page). Must start with PL, UU, LL, FL, or OL.
continuationstringConditionalContinuation token from previous response (next pages).

Provide exactly one of playlist_id or continuation.

Response:

{
"results": [
{
"videoId": "abc123xyz00",
"title": "Playlist Video",
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"channelTitle": "MKBHD",
"channelHandle": "@mkbhd",
"lengthText": "10:05",
"viewCountText": "1.5M views 6 months ago",
"thumbnails": [...],
"index": "0"
}
],
"playlist_info": {
"title": "Best Tech of 2025",
"numVideos": "47",
"description": "My picks for the best tech this year",
"ownerName": "MKBHD",
"viewCount": "5000000"
},
"continuation_token": "4qmFsgKlARIYVVV1QVhGa2dz...",
"has_more": true
}

Pagination: Same flow as channel/videos — use continuation_token from each response to fetch the next page.

Example:

Terminal window
# First page
curl -X GET "https://transcriptapi.com/api/v2/youtube/playlist/videos?playlist_id=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf" \
-H "Authorization: Bearer YOUR_API_KEY"
# Next page
curl -X GET "https://transcriptapi.com/api/v2/youtube/playlist/videos?continuation=4qmFsgKlARIYVVV1QVhGa2dz..." \
-H "Authorization: Bearer YOUR_API_KEY"

EndpointCredits per RequestNotes
GET /youtube/transcript1 creditOnly charged on successful response (200)
GET /youtube/search1 creditSearch videos or channels
GET /youtube/channel/resolveFreeRequires auth + at least 1 active credit
GET /youtube/channel/search1 creditSearch within a channel
GET /youtube/channel/videos1 credit/pagePaginated — each page costs 1 credit
GET /youtube/channel/latestFreeRequires auth + at least 1 active credit
GET /youtube/playlist/videos1 credit/pagePaginated — each page costs 1 credit
  • Successful requests (HTTP 200) - 1 credit (paid endpoints only)
  • Cached responses (HTTP 200) - 1 credit (paid endpoints only)
  • Free endpoints (HTTP 200) - 0 credits (requires at least 1 active credit)
  • Failed requests (4xx, 5xx errors) - 0 credits
  • Rate limited requests (HTTP 429) - 0 credits

Credits are deducted in real-time only when a request is successfully returned.

When credits are exhausted, the API returns HTTP 402 Payment Required.

All API keys are subject to the following rate limits:

  • 300 requests per minute per API key

Each response includes rate limit information in the headers:

HeaderDescription
X-RateLimit-LimitTotal allowed requests in the window
X-RateLimit-RemainingRemaining requests in the window
X-RateLimit-ResetUTC epoch seconds when the window resets
Retry-AfterSeconds until you can retry (only on 429)

Example Headers:

X-RateLimit-Limit: 200
X-RateLimit-Remaining: 195
X-RateLimit-Reset: 1678901234
  1. Implement exponential backoff on 429 errors
  2. Respect the Retry-After header value
  3. Cache responses when appropriate to reduce API calls
  4. Don’t retry failed requests more than 2 times within 3 seconds
  5. Monitor rate limit headers to avoid hitting limits

The API uses standard HTTP status codes:

Status CodeMeaningRetry?Action
200SuccessTranscript returned, 1 credit charged
400Bad Request❌ NoCheck your request parameters
401Unauthorized❌ NoInvalid or missing API key
402Payment Required❌ NoNo credits remaining - visit billing
404Not Found❌ NoVideo not found or transcript unavailable
408Timeout / RetryYesTemporary failure (bot detection, network) - retry in 1-5s
422Validation Error❌ NoInvalid YouTube URL or ID
429Too Many RequestsYesRate limit exceeded - retry after Retry-After header
500Server Error⚠️ MaybeContact support if persistent
503Service UnavailableYesService temporarily down - retry in 1-5s

For retryable errors (408, 429, 503):

  1. Wait the recommended delay (1-5 seconds, or check Retry-After header for 429)
  2. Retry up to 2-3 times with exponential backoff
  3. Give up after max retries and log the failure

For non-retryable errors (400, 401, 402, 404, 422): Do not retry - fix the request parameters or check your account status.

All error responses follow this format:

{
"detail": "Human-readable error message",
"code": "ERROR_CODE"
}

Includes a WWW-Authenticate header:

WWW-Authenticate: Bearer

Special format with action details:

Insufficient Credits:

{
"detail": {
"message": "You have an active plan, but you've run out of credits.",
"reason": "insufficient_credits",
"action_label": "Top up credits",
"action_url": "https://transcriptapi.com/top-up"
}
}

No Active Plan:

{
"detail": {
"message": "You don't have an active paid plan yet.",
"reason": "no_active_paid_plan",
"action_label": "Go to billing to choose a plan",
"action_url": "https://transcriptapi.com/billing"
}
}

Here are complete examples in multiple languages:

Terminal window
# Basic request
curl -X GET "https://transcriptapi.com/api/v2/youtube/transcript?video_url=dQw4w9WgXcQ" \
-H "Authorization: Bearer YOUR_API_KEY"
# With all parameters
curl -X GET "https://transcriptapi.com/api/v2/youtube/transcript?video_url=dQw4w9WgXcQ&format=json&include_timestamp=true&send_metadata=true" \
-H "Authorization: Bearer YOUR_API_KEY"
# Text format without timestamps
curl -X GET "https://transcriptapi.com/api/v2/youtube/transcript?video_url=dQw4w9WgXcQ&format=text&include_timestamp=false" \
-H "Authorization: Bearer YOUR_API_KEY"
  1. Implement retry logic with exponential backoff

    async function fetchWithRetry(url, options, maxRetries = 3) {
    const RETRYABLE_CODES = [408, 429, 503];
    for (let i = 0; i < maxRetries; i++) {
    try {
    const response = await fetch(url, options);
    // Return immediately if not a retryable error
    if (!RETRYABLE_CODES.includes(response.status)) {
    return response;
    }
    // Calculate delay: use Retry-After header or exponential backoff
    const retryAfter =
    response.headers.get("Retry-After") || Math.pow(2, i);
    console.log(
    `Retryable error ${response.status}, waiting ${retryAfter}s...`
    );
    await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
    } catch (error) {
    // Network error - retry with backoff
    if (i === maxRetries - 1) throw error;
    await new Promise((resolve) =>
    setTimeout(resolve, Math.pow(2, i) * 1000)
    );
    }
    }
    throw new Error("Max retries exceeded");
    }
  2. Handle payment required errors gracefully

    • Redirect users to billing page
    • Show clear messaging about credit status
    • Provide action buttons for top-up
  • Cache successful responses to reduce API calls
  • Respect cache headers if provided
  • Consider transcript immutability (transcripts rarely change)
  • Implement cache invalidation for metadata
  • Monitor X-RateLimit-Remaining header
  • Implement request queuing when approaching limits
  • Use exponential backoff on 429 errors
  • Consider implementing client-side rate limiting
  • Never expose API keys in client-side code
  • Store API keys in environment variables
  • Use backend proxy for browser applications
  • Rotate API keys regularly
  • Use separate keys for different environments
  • Log all API responses including headers
  • Monitor credit usage patterns
  • Track rate limit approaches
  • Set up alerts for 402 and 429 responses
  • Monitor response times and cache hit rates

If you have questions or need assistance: