YouTube Subtitles & Transcript Scraper API - Channels
Pricing
from $2.13 / 1,000 transcripts
YouTube Subtitles & Transcript Scraper API - Channels
Rising starBulk 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
Maintained by CommunityActor stats
1
Bookmarked
81
Total users
45
Monthly active users
3 days ago
Last modified
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.
chunksgives paragraph-sized pieces with start and end times for RAG and embeddings;clean-textgives 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
- Paste one or more YouTube links or search terms into Videos, channels, playlists, or searches.
- Pick a Transcript format (
textif unsure). - Click Start. Transcripts stream into the dataset as they are extracted. Export as JSON,
CSV, Excel, or download the
srt/vttcolumn 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
| Input | Example | What happens |
|---|---|---|
| Video URL or ID | youtube.com/watch?v=dQw4w9WgXcQ, youtu.be/…, dQw4w9WgXcQ | One transcript |
| YouTube Shorts | youtube.com/shorts/… | One transcript |
| Live replay, embed | youtube.com/live/…, youtube.com/embed/… | One transcript |
| Channel | youtube.com/@handle, youtube.com/channel/UC… | The channel's uploads, newest first, up to maxVideosPerSource |
| Playlist | youtube.com/playlist?list=… | Every video in the playlist, up to maxVideosPerSource |
| Search term | machine learning tutorial | The 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.
| Job | Transcripts delivered | Free plan | Business plan (Gold, -15%) |
|---|---|---|---|
| 100-video playlist, 92 have captions | 92 | $0.23 | $0.20 |
| 1,000-video channel backfill | ~1,000 | ~$2.50 | ~$2.13 |
| Daily check of 20 channels, 5 new videos each | 100 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
failurerows, so a channel where 20% of videos lack captions costs 20% less. SetincludeFailurestofalseto drop those rows. - Safe to automate. The
SUMMARYrecord 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:
| Format | transcript contains | Use it for |
|---|---|---|
text | Caption fragments joined with spaces, exactly as YouTube sends them | Anything already doing its own cleanup |
clean-text | The same words, sound cues removed, split into paragraphs at pauses | Reading, summarising, prompting an LLM |
segments | [{ text, start, duration }] per caption fragment | Timing analysis, building your own subtitles |
chunks | [{ text, start, end, wordCount }] per paragraph | RAG, embeddings, timestamped citations |
srt / vtt | A ready-to-save subtitle file | Players, 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}
| Field | Default | Description |
|---|---|---|
videoUrls | — | Video URLs/IDs, channel URLs (@handle or /channel/UC…), playlist URLs, or search queries |
languages | ["en"] | Preferred transcript languages, in priority order |
transcriptFormat | text | text, clean-text, segments, chunks, srt, or vtt |
chunkWords | 150 | Target paragraph size for clean-text / chunks |
preferAutoGenerated | false | Prefer auto-generated (ASR) captions over manual ones |
fallbackToAnyLanguage | true | Use the best available track if no preferred language exists |
includeFailures | true | Emit uncharged diagnostic rows for videos without transcripts |
maxVideosPerSource | 200 | Cap per channel/playlist/search |
maxResults | 100000 | Global cap per run (spend guard) |
concurrency | 10 | Parallel video fetches (1–25) |
proxyStrategy | auto | auto ladder, or force datacenter-only / residential-only |
maxUnchargedRatio | 90 | Stop early if more than this % of the first 200+ videos return no transcript. Set 100 to disable |
maxResidentialAttempts | 0 | Cap 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
maxResidentialAttemptsis 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).
| Option | Any public video | Works from a server | Cost |
|---|---|---|---|
YouTube Data API captions.download | No, only videos you can edit | Yes | Free, about 50 downloads a day on the default quota |
youtube-transcript-api (Python library) | Yes | Usually blocked on cloud IPs unless you add a residential proxy | Free, plus the proxy plan |
| This Actor | Yes, any public video with captions | Yes, 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 YouTubeTranscriptApifetched = 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 ApifyClientclient = 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 transcriptstranscripts = fetch_transcripts(["dQw4w9WgXcQ", "jNQXAC9IVRw"])for snippet in transcripts["dQw4w9WgXcQ"][:3]:print(snippet["start"], snippet["text"])
| youtube-transcript-api | This Actor |
|---|---|
fetch(video_id, languages=[...]) | videoUrls (IDs, links, channels, playlists) and languages |
snippet.text, .start, .duration | transcriptFormat: "segments": text, start, duration |
TextFormatter, SRTFormatter, WebVTTFormatter | transcriptFormat: text, clean-text, srt, vtt |
list(video_id) | availableLanguages on every row |
TranscriptsDisabled | free row with error: "NO_CAPTIONS" |
NoTranscriptFound | free row with error: "NO_MATCHING_LANGUAGE", or the best other track with fallbackToAnyLanguage |
RequestBlocked, IpBlocked | retried 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 ApifyClientclient = 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-apifyexport APIFY_API_TOKEN=YOUR_APIFY_TOKEN
from langchain_apify import ApifyActorsToolyoutube = 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 ApifyClientclient = 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":continuefor 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_CAPTIONSand 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.
Related Actors
- 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.