YouTube Transcript & Subtitles API: Bulk, Channels, Playlists avatar

YouTube Transcript & Subtitles API: Bulk, Channels, Playlists

Pricing

from $5.00 / 1,000 transcripts

Go to Apify Store
YouTube Transcript & Subtitles API: Bulk, Channels, Playlists

YouTube Transcript & Subtitles API: Bulk, Channels, Playlists

Get YouTube transcripts and subtitles (SRT/VTT) in bulk, from videos, channels or playlists. $5 per 1,000 on paid plans, and you only pay for successful transcripts.

Pricing

from $5.00 / 1,000 transcripts

Rating

0.0

(0)

Developer

Nawfel

Nawfel

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Get YouTube transcripts and subtitles (SRT/VTT) in bulk: one video, a list, a whole channel, or a playlist, as clean JSON with timestamps. Compatible with the common videoUrl + targetLanguage input and {"data": [{start, dur, text}]} output, so a single-video pipeline can switch by changing only the Actor ID. $5 per 1,000 transcripts on paid plans, and you only pay for successful transcripts. Videos without captions are free.

What you get

  • Transcripts with timestamps: every caption line with its start time and duration, plus the full text as one string.
  • Bulk, channels and playlists: pass hundreds of video URLs, a channel (@handle), or a playlist in one run.
  • Subtitles: standard SRT and WebVTT files, ready to upload or burn in.
  • AI-ready chunks: transcript split into pieces of the size you choose, each with its time range, chapter, and a link that opens the video at that exact moment (&t=123s). Built for RAG pipelines and chatbots that cite their sources.
  • Chapters and video details: title, channel, duration, view count, and the video's chapters ("Intro", "Pricing", ...) with timestamp links.
  • Find the moment: give keywords ("pricing", "Bitcoin", a brand name) and get every moment they are said, with links.
  • Channel monitoring: schedule the Actor on a channel and each run returns only the new videos' transcripts.
  • Markdown and paragraphs: readable text grouped by pauses, with clickable timestamps, for blog posts and notes.
  • Reliable: blocked requests are retried automatically on fresh connections, and region-locked videos are retried from other countries. Runs don't fail because one video has no captions.

Pricing

Price
Successful transcript, paid Apify plans$5 per 1,000 ($0.005 each)
Successful transcript, free Apify plan$10 per 1,000
Video without captions, private, deleted, age-restricted...free
Start fee, compute, proxiesincluded

Chapters, chunks, SRT, VTT, Markdown, paragraphs and keyword search are included at no extra cost. The spending limit you set on a run is respected: the run stops cleanly when it is reached, and you are never charged above it.

Quick start

One video (the classic input):

{
"videoUrl": "https://www.youtube.com/watch?v=8KkKuTCFvzI",
"targetLanguage": "en"
}

Many videos: videoUrl and videoUrls accept watch URLs, youtu.be links, Shorts, embed and live URLs, or bare 11-character IDs. Duplicates are removed.

{
"videoUrls": [
"https://www.youtube.com/watch?v=8KkKuTCFvzI",
"https://youtu.be/dQw4w9WgXcQ",
"https://www.youtube.com/shorts/BR06T1eJ3go"
],
"targetLanguage": "en"
}

A channel or a playlist (newest videos first, up to maxVideos):

{
"channelUrl": "https://www.youtube.com/@TED",
"playlistUrl": "https://www.youtube.com/playlist?list=PLxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"maxVideos": 100
}

Subtitles and AI chunks:

{
"videoUrls": ["https://www.youtube.com/watch?v=8KkKuTCFvzI"],
"chunkSize": 1500,
"extraFormats": ["srt", "vtt", "markdown", "paragraphs"]
}

Find every moment a word is said across a channel (outputFormat: "none" keeps the results small):

{
"channelUrl": "@veritasium",
"maxVideos": 50,
"searchKeywords": ["black hole", "quantum"],
"outputFormat": "none"
}

Monitor a channel: create a Schedule (daily or weekly) with this input. Each run returns only videos it hasn't delivered before.

{
"channelUrl": "@mkbhd",
"maxVideos": 20,
"onlyNewVideos": true
}

Input

FieldTypeDescription
videoUrlstringOne video URL or ID.
targetLanguagestringTranscript language, ISO 639-1 (en, es, pt, fr, de, ja, ...). Default en.
videoUrlsarrayMany video URLs or IDs.
channelUrlstring@handle, channel URL, or UC... channel ID.
playlistUrlstringPlaylist URL or ID.
maxVideosintegerVideos taken from the channel and from the playlist. Default 50.
outputFormatstringboth (default), segments (data only), text (text only), none.
fallbackToAnyLanguagebooleanIf the requested language isn't available, return the video's own language (flagged). Default true.
searchKeywordsarrayWords or phrases to find; returns matches.
chunkSizeintegerSplit into chunks of up to this many characters (e.g. 1000-2000). 0 = off.
extraFormatsarrayAny of srt, vtt, markdown, paragraphs.
onlyNewVideosbooleanMonitoring: skip videos delivered by earlier runs of the same input.
monitorStateKeystringOptional name to keep several monitors on the same channel separate.

Give at least one of videoUrl, videoUrls, channelUrl, playlistUrl.

Output

One dataset item per video. data is first and has the same shape as the common single-video format; everything else is added alongside it.

{
"data": [
{ "start": "0.280", "dur": "4.440", "text": "Welcome back to the channel." },
{ "start": "4.720", "dur": "3.960", "text": "Today we're looking at pricing." }
],
"videoId": "8KkKuTCFvzI",
"videoUrl": "https://www.youtube.com/watch?v=8KkKuTCFvzI",
"title": "Example video title",
"channelName": "Example Channel",
"channelId": "UCxxxxxxxxxxxxxxxxxxxxxx",
"durationSeconds": 754,
"viewCount": 182345,
"chapters": [
{ "title": "Intro", "start": 0, "end": 95, "startTime": "0:00", "url": "https://www.youtube.com/watch?v=8KkKuTCFvzI&t=0s" },
{ "title": "Pricing", "start": 95, "end": 754, "startTime": "1:35", "url": "https://www.youtube.com/watch?v=8KkKuTCFvzI&t=95s" }
],
"language": "en",
"requestedLanguage": "en",
"isAutoGenerated": false,
"isLanguageFallback": false,
"availableLanguages": ["en", "es"],
"text": "Welcome back to the channel. Today we're looking at pricing. ...",
"status": "success",
"errorType": null,
"errorMessage": null
}

With options, items also contain:

  • chunks: [{ index, start, end, startTime, url, chapter, text }]
  • matches and matchCount: [{ keyword, start, startTime, url, chapter, context }]
  • srt, vtt, markdown: strings; paragraphs: [{ start, startTime, url, text }]

For very long videos (several hours) with many formats, the biggest formats are saved to the run's key-value store and the item links to them (srtUrl, vttUrl, ...) to stay within dataset size limits.

The dataset has three views: Transcripts, Details (video details and language handling), and Moments (one row per keyword match).

Errors

Videos without a transcript are still listed, so you can see what happened, and are never charged:

errorTypeMeaning
NO_CAPTIONSThe video has no captions (manual or auto-generated).
LANGUAGE_NOT_AVAILABLENo captions in targetLanguage and fallbackToAnyLanguage is off. availableLanguages lists what exists.
VIDEO_UNAVAILABLEPrivate, deleted, or otherwise unavailable.
AGE_RESTRICTEDAge-restricted videos need a signed-in account, which this Actor never uses.
MEMBERS_ONLYChannel-members-only video.
LIVE_NOT_FINISHEDA live stream or premiere that hasn't ended yet.
GEO_RESTRICTEDNot available in any country we tried.
INVALID_URLNot a YouTube video URL or ID.
BLOCKED_AFTER_RETRIESYouTube refused repeatedly. Rare; try again later.

A run only fails if the input itself is invalid (for example, no video, channel or playlist given).

Migrating from a single-video transcript Actor

If you call a transcript Actor with {"videoUrl": ..., "targetLanguage": ...} and read items[0]["data"], change only the Actor ID:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("nawfel_bc/youtube-transcript-api").call(run_input={
"videoUrl": "https://www.youtube.com/watch?v=8KkKuTCFvzI",
"targetLanguage": "en",
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
segments = items[0]["data"] if items else None # [{"start": "0.280", "dur": "4.440", "text": "..."}]

What stays the same with a classic single-video input (only videoUrl):

  • The dataset item has data with start / dur / text as strings, in seconds with 3 decimals.
  • The key-value store record output holds the same object; when there is no transcript it holds {"success": false, "videoUrl", "targetLanguage", "error": {"code", "message", "retryable"}}, with code NO_CAPTION_AVAILABLE for videos without captions.
  • When there is no transcript, the dataset stays empty and the run still succeeds, with the reason in the status message.

One difference: this Actor never machine-translates. If the video has no captions in targetLanguage, you get the video's own language with isLanguageFallback: true (or LANGUAGE_NOT_AVAILABLE if you turn fallback off).

Then, to process many videos, send them all in one run with videoUrls instead of one run per video: it is faster and you avoid per-run overhead.

Use cases

  • RAG and AI agents: index transcripts with chunkSize, and let your assistant cite the exact moment with the chunk url.
  • Content repurposing: turn videos into blog posts, newsletters and social posts with markdown or paragraphs.
  • Subtitles: export srt or vtt for editing, accessibility, or re-uploading.
  • SEO: publish transcripts next to embedded videos.
  • Research and monitoring: track what competitors, creators or news channels say with searchKeywords and scheduled onlyNewVideos runs.

Use from AI agents (MCP)

This Actor can be used as a tool through the Apify MCP server. An agent can call it with {"videoUrl": "...", "outputFormat": "text"} for a quick summary input, or with chunkSize and searchKeywords to retrieve and cite specific moments.

FAQ

Which videos work? Public YouTube videos that have captions, manual or auto-generated, including Shorts and finished live streams.

Can I get a transcript in another language? Only if the video has captions in that language. Transcripts are never machine-translated. Use availableLanguages to see what exists.

What about videos without captions? They return NO_CAPTIONS and are free. Speech-to-text transcription is not included.

Does a failed video fail the run? No. Each video gets its own item with status and errorType.

How fast is it? Up to 20 videos are processed at once; a typical video takes 1 to 5 seconds.

Where are chapters from? From the timestamps in the video's description ("0:00 Intro"), using YouTube's rules: at least three, starting at 0:00. Videos without them return chapters: [].

How does monitoring remember what it already delivered? In a key-value store named youtube-transcript-monitor in your own Apify account. Videos whose captions aren't ready yet are retried on later runs for up to 7 days, and charged only when they succeed.

Do I need a YouTube account or API key? No.

Limitations

  • Only public videos; never private, members-only or age-restricted ones.
  • One transcript language per run.
  • Chapters only when the description lists them.