YouTube Subtitles & Transcript Scraper API - Channels avatar

YouTube Subtitles & Transcript Scraper API - Channels

Pricing

from $2.13 / 1,000 transcripts

Go to Apify Store
YouTube Subtitles & Transcript Scraper API - Channels

YouTube Subtitles & Transcript Scraper API - Channels

Rising star

Bulk YouTube transcript API. YouTube to text for any video, Short, playlist, search or whole channel: each YouTube video transcript, subtitles and captions as text, JSON, YouTube SRT, VTT or RAG chunks, also via MCP. YouTube channel and playlist transcripts. $2.50 per 1,000; no captions, no charge.

Pricing

from $2.13 / 1,000 transcripts

Rating

4.0

(1)

Developer

Saulius AutomatesIT

Saulius AutomatesIT

Maintained by Community

Actor stats

1

Bookmarked

81

Total users

45

Monthly active users

3 days ago

Last modified

Categories

Share

YouTube Subtitles & Transcript Scraper API — Videos, Channels, Playlists & Search

Bulk YouTube transcript API: paste videos, Shorts, channels, playlists or search terms and get every transcript back as text, RAG chunks, SRT or VTT. $2.50 per 1,000 transcripts. Videos without captions cost nothing.

  • Proven at scale. One customer ran 8,500 runs and 436,000+ videos through it in a single day. Over the last 30 days, 99.9% of public runs succeeded (8,709 of 8,722 on 4 Oct, Apify's own run statistics).
  • Whole channels and playlists in one input. A channel URL, playlist URL or search term expands to its videos automatically. Mix them freely with single video links.
  • Pay only for delivered transcripts. No captions, private, deleted or blocked videos get a free diagnostic row, never a charge. Platform usage (compute, proxies) is included in the price.
  • Ready for AI. chunks gives paragraph-sized pieces with start and end times for RAG and embeddings; clean-text gives readable paragraphs for LLM prompts. Works from the API, Python, JavaScript, n8n, Make, Zapier and any MCP client (Claude, ChatGPT, Cursor).
  • No YouTube API key, no login, no cookies.

Try it free: Apify's free plan includes $5 of usage credit every month, enough for about 2,000 transcripts. Videos without captions never use any of it.

Quick start

  1. Paste one or more YouTube links or search terms into Videos, channels, playlists, or searches.
  2. Pick a Transcript format (text if unsure).
  3. Click Start. Transcripts stream into the dataset as they are extracted. Export as JSON, CSV, Excel, or download the srt / vtt column as subtitle files.
{
"videoUrls": ["https://www.youtube.com/@mkbhd"],
"transcriptFormat": "clean-text",
"maxVideosPerSource": 50
}

That returns the 50 newest uploads of the channel as paragraph text. Cost at the Free-plan price: at most $0.125.

What you can paste

InputExampleWhat happens
Video URL or IDyoutube.com/watch?v=dQw4w9WgXcQ, youtu.be/…, dQw4w9WgXcQOne transcript
YouTube Shortsyoutube.com/shorts/…One transcript
Live replay, embedyoutube.com/live/…, youtube.com/embed/…One transcript
Channelyoutube.com/@handle, youtube.com/channel/UC…The channel's uploads, newest first, up to maxVideosPerSource
Playlistyoutube.com/playlist?list=…Every video in the playlist, up to maxVideosPerSource
Search termmachine learning tutorialThe top search results, up to maxVideosPerSource

Pricing

$2.50 per 1,000 transcripts ($0.0025 each) on the Free plan. Paid Apify plans get the Store discount automatically: Bronze $2.375, Silver $2.25, Gold and above $2.125 per 1,000. Each run also has a $0.00005 start fee per GB of memory (about $0.00005 per run at the default 1 GB). Proxy and compute costs are included. That is the whole bill.

JobTranscripts deliveredFree planBusiness plan (Gold, -15%)
100-video playlist, 92 have captions92$0.23$0.20
1,000-video channel backfill~1,000~$2.50~$2.13
Daily check of 20 channels, 5 new videos each100 a day~$7.50 a month~$6.38 a month
20,000-video research corpus~20,000~$50.00~$42.50
100,000 videos a month~100,000~$250~$212.50

Apify's Starter plan gets the Bronze discount, Scale gets Silver and Business gets Gold, applied automatically. The free plan's $5 monthly credit covers about 2,000 transcripts.

  • Videos without captions cost $0, and so do private, deleted and blocked ones.
  • Set Maximum total charge in the run options to hard-cap spending. The Actor stops cleanly at the cap and keeps everything it already delivered.
  • For context, the two most-used YouTube transcript Actors on the Store charge $5 and $10 per 1,000 results (checked October 2026).

Bulk and recurring workloads

The Actor is built for large, repeated jobs, not just one-off lookups:

  • Throughput. 436,000+ videos processed for one customer in a day across 8,500 API runs. Results stream into the dataset while a run is still going.
  • Predictable cost. One flat event with platform usage included, the plan discount applied automatically, and Maximum total charge per run as a hard ceiling.
  • Nothing wasted. No-caption, private, deleted and blocked videos come back as free failure rows, so a channel where 20% of videos lack captions costs 20% less. Set includeFailures to false to drop those rows.
  • Safe to automate. The SUMMARY record reports exactly what happened in every run, and a restarted run never charges twice for the same video.

Running a large or recurring workload (100,000+ videos a month)? Open an issue on the Issues tab with your volume and output format, and you will get help sizing runs and concurrency.

Output

One dataset item per video:

{
"type": "transcript",
"videoId": "dQw4w9WgXcQ",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"title": "Rick Astley - Never Gonna Give You Up (Official Video)",
"channelName": "Rick Astley",
"channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
"lengthSeconds": 213,
"viewCount": 1697651560,
"language": "en",
"languageName": "English",
"isAutoGenerated": false,
"transcriptFormat": "text",
"transcript": "[♪♪♪] ♪ We're no strangers to love ♪ ♪ You know the rules and so do I ♪…",
"segmentCount": 61,
"wordCount": 488,
"availableLanguages": ["en", "en (auto)", "de-DE", "ja", "pt-BR", "es-419"],
"sourceInput": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"scrapedAt": "2026-08-11T21:35:20.991Z"
}

Videos that can't produce a transcript get a type: "failure" row (free of charge) with an error code such as NO_CAPTIONS, NO_MATCHING_LANGUAGE, or LOGIN_REQUIRED, so your pipeline can handle them explicitly. A run report with per-outcome counts is saved under the SUMMARY key of the run's key-value store.

Transcript formats

YouTube does not hand out prose. A caption track is a list of ~2-second display fragments, cut mid-sentence, with sound cues ([Music], [Applause]) inline — and auto-generated (ASR) tracks usually carry no punctuation at all. Pick the format that matches what you do next:

Formattranscript containsUse it for
textCaption fragments joined with spaces, exactly as YouTube sends themAnything already doing its own cleanup
clean-textThe same words, sound cues removed, split into paragraphs at pausesReading, summarising, prompting an LLM
segments[{ text, start, duration }] per caption fragmentTiming analysis, building your own subtitles
chunks[{ text, start, end, wordCount }] per paragraphRAG, embeddings, timestamped citations
srt / vttA ready-to-save subtitle filePlayers, editors, upload back to YouTube

clean-text and chunks share one cleanup pass: sound cues are dropped, and the words are regrouped into paragraphs that break at any pause of 2 seconds or more in the audio, or at chunkWords words (default 150) when the speaker never pauses. Each paragraph is capitalised and given a closing full stop. chunks keeps the start/end timing of every paragraph, so a retrieval hit can be linked straight back to youtube.com/watch?v=…&t=123s.

{
"transcriptFormat": "chunks",
"transcript": [
{ "text": "Hi I'm Matt I've worked at the RC now for 15 years as a patrolman today I'm going to talk you through going through a wheel change…", "start": 4.799, "end": 52.12, "wordCount": 155 },
{ "text": "Off now as doing this when the vehicle's on the jack could cause the jack to dislodge…", "start": 50.12, "end": 97.759, "wordCount": 150 }
],
"chunkCount": 4
}

What the cleanup does not do: it adds no punctuation inside a paragraph and corrects no words. If YouTube's ASR wrote the RC for "the RAC", that is what you get — restoring punctuation and fixing transcription errors needs a language model, which this Actor deliberately doesn't run (it would cost far more than the transcript itself). Manual caption tracks are usually already punctuated, and clean-text leaves that punctuation intact.

text and segments are unchanged from earlier builds — existing runs and integrations keep their exact output.

Input

{
"videoUrls": [
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"https://youtu.be/jNQXAC9IVRw",
"https://www.youtube.com/@mkbhd",
"https://www.youtube.com/playlist?list=PLFgquLnL59alCl_2TQvOiD5Vgm1hCaGSI",
"machine learning tutorial"
],
"languages": ["en"],
"transcriptFormat": "text",
"maxVideosPerSource": 200
}
FieldDefaultDescription
videoUrls—Video URLs/IDs, channel URLs (@handle or /channel/UC…), playlist URLs, or search queries
languages["en"]Preferred transcript languages, in priority order
transcriptFormattexttext, clean-text, segments, chunks, srt, or vtt
chunkWords150Target paragraph size for clean-text / chunks
preferAutoGeneratedfalsePrefer auto-generated (ASR) captions over manual ones
fallbackToAnyLanguagetrueUse the best available track if no preferred language exists
includeFailurestrueEmit uncharged diagnostic rows for videos without transcripts
maxVideosPerSource200Cap per channel/playlist/search
maxResults100000Global cap per run (spend guard)
concurrency10Parallel video fetches (1–25)
proxyStrategyautoauto ladder, or force datacenter-only / residential-only
maxUnchargedRatio90Stop early if more than this % of the first 200+ videos return no transcript. Set 100 to disable
maxResidentialAttempts0Cap on premium-proxy escalations per run. 0 = auto (25% of queued videos, min 500)

Early stopping

Two safeguards end a run cleanly rather than working through a list that cannot pay its way. Neither marks the run as failed, and both are reported in the SUMMARY record:

  • No transcripts available — if more than maxUnchargedRatio % of the first 200+ videos return no transcript, the run stops and says so. This almost always means the videos have no caption tracks. Normal jobs, including ones where many videos legitimately lack captions, are unaffected.
  • Premium proxy budget — YouTube bot-checks are retried on a residential proxy, which is much more expensive. Once maxResidentialAttempts is spent the run continues on datacenter only.

SUMMARY reports stoppedAtUnchargedLimit, premiumProxyAttempts and premiumProxyBudget alongside the existing counters.

Is there an official YouTube transcript API?

Not for other people's videos. The YouTube Data API's captions.download method "requires the user to have permission to edit the video", needs OAuth with the youtube.force-ssl or youtubepartner scope, and costs 200 quota units per call, so the default 10,000 units a day allow 50 downloads (YouTube Data API reference).

OptionAny public videoWorks from a serverCost
YouTube Data API captions.downloadNo, only videos you can editYesFree, about 50 downloads a day on the default quota
youtube-transcript-api (Python library)YesUsually blocked on cloud IPs unless you add a residential proxyFree, plus the proxy plan
This ActorYes, any public video with captionsYes, proxies included$2.50 per 1,000 transcripts; videos without captions free

youtube-transcript-api blocked on AWS, GCP or a VPS? (RequestBlocked, IpBlocked)

The youtube-transcript-api Python library works on a laptop and then raises RequestBlocked or IpBlocked once deployed, because YouTube blocks most IP ranges that belong to cloud providers. The library's own README says so and recommends rotating residential proxies. This Actor does the same lookup on Apify with proxy rotation built in, and segments returns the same text, start and duration fields.

Before, with the library:

from youtube_transcript_api import YouTubeTranscriptApi
fetched = YouTubeTranscriptApi().fetch("dQw4w9WgXcQ", languages=["en"])
for snippet in fetched:
print(snippet.start, snippet.text)

After, with a drop-in function that fetches many videos in one run:

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
def fetch_transcripts(video_ids, languages=("en",)):
"""{video_id: [{"text", "start", "duration"}, ...]} for every video that has captions."""
run = client.actor("sauliusautomatesit/youtube-transcript-scraper").call(run_input={
"videoUrls": list(video_ids),
"languages": list(languages),
"transcriptFormat": "segments",
})
transcripts = {}
for item in client.dataset(run.default_dataset_id).iterate_items():
if item["type"] == "transcript":
transcripts[item["videoId"]] = item["transcript"]
else:
print("no transcript:", item["videoId"], item["error"])
return transcripts
transcripts = fetch_transcripts(["dQw4w9WgXcQ", "jNQXAC9IVRw"])
for snippet in transcripts["dQw4w9WgXcQ"][:3]:
print(snippet["start"], snippet["text"])
youtube-transcript-apiThis Actor
fetch(video_id, languages=[...])videoUrls (IDs, links, channels, playlists) and languages
snippet.text, .start, .durationtranscriptFormat: "segments": text, start, duration
TextFormatter, SRTFormatter, WebVTTFormattertranscriptFormat: text, clean-text, srt, vtt
list(video_id)availableLanguages on every row
TranscriptsDisabledfree row with error: "NO_CAPTIONS"
NoTranscriptFoundfree row with error: "NO_MATCHING_LANGUAGE", or the best other track with fallbackToAnyLanguage
RequestBlocked, IpBlockedretried on a fresh proxy; a video still blocked is a free row, never a charge

Tutorial: Python, AI agents and RAG

Four copy-paste recipes. Each one needs an Apify API token (Apify Console > Settings > API & Integrations); the free plan's monthly credit covers about 2,000 transcripts.

1. Python: every video of a channel in one call

$pip install apify-client
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("sauliusautomatesit/youtube-transcript-scraper").call(run_input={
"videoUrls": ["https://www.youtube.com/@3blue1brown"],
"maxVideosPerSource": 5,
"transcriptFormat": "clean-text",
})
for item in client.dataset(run.default_dataset_id).iterate_items():
if item["type"] == "transcript":
print(item["title"], item["wordCount"], "words")
else:
print("skipped", item["videoId"], item["error"])

run.default_dataset_id is for apify-client 3.x; on 2.x write run["defaultDatasetId"]. The same code works with a playlist URL, a list of video links or a search term. To cap spend, pass max_total_charge_usd=1 to .call() and the run stops cleanly at $1.

2. AI agents: one MCP URL, one tool

This URL gives any MCP client exactly one tool, this Actor, instead of a search over the whole Apify Store:

https://mcp.apify.com/?tools=sauliusautomatesit/youtube-transcript-scraper

Claude Code:

$claude mcp add --transport http youtube-transcripts "https://mcp.apify.com/?tools=sauliusautomatesit/youtube-transcript-scraper"

Cursor (~/.cursor/mcp.json), Claude Desktop, VS Code and other clients that take JSON:

{
"mcpServers": {
"youtube-transcripts": {
"url": "https://mcp.apify.com/?tools=sauliusautomatesit/youtube-transcript-scraper",
"headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
}
}
}

Clients that support OAuth (Claude.ai custom connectors, ChatGPT) need only the URL and open an Apify sign-in on first use. Then ask things like:

  • "Get the transcripts of the last 10 videos on @lexfridman and list every book mentioned, with the timestamp."
  • "Pull the transcript of this video and turn it into a blog post outline."

The agent fills in videoUrls, maxVideosPerSource and transcriptFormat from the input schema. Videos without captions come back as free failure rows, so the agent can say why instead of guessing.

3. LangChain and CrewAI

pip install langchain-apify
export APIFY_API_TOKEN=YOUR_APIFY_TOKEN
from langchain_apify import ApifyActorsTool
youtube = ApifyActorsTool("sauliusautomatesit/youtube-transcript-scraper")
rows = youtube.invoke({"run_input": {
"videoUrls": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"],
"transcriptFormat": "chunks",
}})

youtube is a normal LangChain tool, so it also goes straight into an agent's tool list.

4. RAG: timestamped chunks that cite the exact second

chunks returns paragraphs (broken at pauses of 2 seconds or more, or every chunkWords words), each with its start time. Turn them into documents whose source link jumps to the moment:

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("sauliusautomatesit/youtube-transcript-scraper").call(run_input={
"videoUrls": ["https://www.youtube.com/@3blue1brown"],
"maxVideosPerSource": 20,
"transcriptFormat": "chunks",
"chunkWords": 150,
})
docs = []
for item in client.dataset(run.default_dataset_id).iterate_items():
if item["type"] != "transcript":
continue
for i, chunk in enumerate(item["transcript"]):
docs.append({
"id": f"{item['videoId']}-{i}",
"text": chunk["text"],
"metadata": {
"title": item["title"],
"channel": item["channelName"],
"url": f"https://www.youtube.com/watch?v={item['videoId']}&t={int(chunk['start'])}s",
},
})
print(len(docs), "chunks ready to embed")

Load docs into any vector store (Chroma, pgvector, Pinecone, Qdrant, LangChain or LlamaIndex documents). When the retriever returns a chunk, metadata.url sends the reader to the exact second. To keep a channel's index fresh, save the input as a Task with a daily schedule and embed only video IDs you have not seen.

Other ways to call it

API (one call, results in the response)

curl -X POST "https://api.apify.com/v2/acts/sauliusautomatesit~youtube-transcript-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"], "transcriptFormat": "clean-text" }'

For large jobs, start the run asynchronously and read the dataset when it finishes; results stream into the dataset while the run is still going.

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('sauliusautomatesit/youtube-transcript-scraper').call({
videoUrls: ['https://www.youtube.com/@mkbhd'],
maxVideosPerSource: 10,
transcriptFormat: 'srt',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
if (item.type === 'transcript') console.log(item.videoId, item.title, item.transcript.length, 'characters of SRT');
else console.log('skipped', item.videoId, item.error);
}

npm install apify-client first. The same input works with plain fetch against the API call above.

n8n, Make and Zapier

Use the Apify node or module, choose Run an Actor, enter sauliusautomatesit/youtube-transcript-scraper, pass the input JSON, then read the dataset items in the next step. transcript holds the text, type lets you filter out free failure rows.

Scheduled monitoring

Save your input as a Task and give it a schedule in Schedules (for example daily on a list of channel URLs) to collect transcripts of new uploads as they appear.

Use cases

  • AI and RAG pipelines. Turn channels into LLM-ready corpora with timestamped chunks.
  • Content repurposing. Transcripts for blogs, newsletters, show notes and social clips.
  • Media and brand monitoring. Schedule runs on channels and search terms.
  • Research. Collect interview and lecture transcripts with timestamps for citation.
  • Subtitles. Batch-download SRT/VTT files for re-upload, accessibility or translation.

Limitations

  • Transcripts come from YouTube caption tracks (manual or auto-generated). Videos with captions disabled can't be transcribed — they're reported as NO_CAPTIONS and not charged. To transcribe the audio of videos without captions, try Media Transcriber (YouTube support there is best effort).
  • Live streams in progress and age-restricted videos are generally not extractable.
  • Channel expansion returns the channel's regular uploads (newest first), up to maxVideosPerSource.

FAQ

Does YouTube have an official transcript API? Not for other people's videos. The YouTube Data API only lets you download captions for videos you have permission to edit. This Actor reads the public caption tracks YouTube shows in its player, for any public video.

Why does youtube-transcript-api raise RequestBlocked on my server? YouTube blocks most cloud provider IPs. The section "youtube-transcript-api blocked on AWS, GCP or a VPS?" above shows how to swap the call for this Actor and keep your segment handling.

How do I get a YouTube transcript in Python? pip install apify-client and use the fetch_transcripts function above, or tutorial recipe 1 for a whole channel.

How do I get the transcripts of a whole YouTube channel? Paste the channel URL (youtube.com/@handle) and set maxVideosPerSource to the number of uploads you want. Playlists and search terms work the same way.

How much does it cost to transcribe 10,000 YouTube videos? About $25 on the Free plan and $21.25 on Gold, minus every video without captions, which is free.

Do I need a YouTube API key or cookies? No. The Actor uses YouTube's public endpoints.

What languages are supported? Anything YouTube has captions for. Set languages to your priority list; availableLanguages on every item shows what exists.

Can I get timestamps? Yes. Segment-level timestamps (a few seconds each) via segments, srt or vtt, or paragraph-level ones via chunks.

The transcript is one long block with no punctuation — can you fix that? Set transcriptFormat to clean-text or chunks. That removes sound cues and breaks the text into paragraphs at pauses in the audio. Punctuation within a sentence comes from YouTube: manual caption tracks have it, auto-generated ones usually don't, and this Actor doesn't run a language model to invent it. See Transcript formats.

What happens on a video that's private or deleted? A free failure row with the error code, never a charge.

  • Google Ads Transparency API: every Google and YouTube ad an advertiser runs, with the YouTube link of each video ad. Feed those links into this Actor to get the script of every competitor video ad.
  • Telegram Channel Scraper: every post from public Telegram channels as clean rows, for the same research, monitoring and RAG pipelines.
  • Google Trends API: search interest over time for the topics your videos cover, to pick what to transcribe or publish next.
  • Bing Search API: live web search results for the same AI agents and RAG pipelines, now that Microsoft has retired its own Bing API.
  • Bilibili API: videos, stats and danmaku from China's biggest video platform.

Support and reviews

Found a problem or missing a feature? Open an issue on this Actor's Issues tab; issues are answered within 24 hours. If this Actor saves you time, please leave a short review. Reviews are how other people find it.