Youtube Transcript Scraper
Pricing
from $3.00 / 1,000 results
Youtube Transcript Scraper
Pricing
from $3.00 / 1,000 results
Rating
0.0
(0)
Developer
Gorav Agarwal
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Bulk YouTube Transcript Scraper
Extract transcripts and subtitles from hundreds of YouTube videos in a single run — by video URL, playlist, channel, @handle or search query. Returns timestamped segments, clean plain text, optional SRT, the full list of available caption languages, and a per-video status code so a partial failure is visible instead of silent.
You are only charged for transcripts that are actually returned. A video with no captions, a private video, or one YouTube refuses to serve costs you nothing.
Why this one
Most YouTube transcript Actors take one video per run. If you have 500 videos, that is 500 runs to orchestrate, 500 sets of overhead, and no consolidated output. This one takes a list — or a whole channel — and gives you a single dataset.
The other common failure is silence. When YouTube declines a request, a naive scraper writes an empty string and moves on, so you discover months later that a chunk of your corpus is blank. Here every video carries an explicit status: OK, NO_TRANSCRIPT, NO_MATCHING_LANGUAGE, VIDEO_UNAVAILABLE, AGE_RESTRICTED, LIVE_STREAM, EMPTY_TRANSCRIPT, IP_BLOCKED, FETCH_FAILED or INVALID_INPUT — and failures are written to a separate failures dataset with a human-readable reason.
Read this before you run it: YouTube blocks datacenter IPs
This is the single most important thing to understand, and most listings in this category do not tell you.
YouTube now answers transcript requests from cloud/datacenter IP ranges with "Sign in to confirm you're not a bot". I measured this directly from two independent datacenter networks (Google Cloud and Cloudflare) against five different endpoints — watch page, mobile watch page, embed, youtube-nocookie, and the watch page with consent parameters. Every one returned LOGIN_REQUIRED and zero caption tracks. The same requests from a residential connection returned a full 28-language track list.
Apify runs on exactly those cloud ranges. So:
- This Actor defaults to Apify Proxy with the
RESIDENTIALgroup. Without it, expect most videos to come backIP_BLOCKED. - Residential proxy bandwidth is billed to your own Apify account, separately from this Actor's per-result price.
- Measured consumption is 51.4 KB per video on the wire. At Apify's residential rate of $8/GB that is about $0.39 per 1,000 transcripts.
So the honest all-in cost is roughly $2.89–$3.39 per 1,000 transcripts, of which ~$0.39 is proxy bandwidth on your account. I would rather you see that here than on your invoice.
If you already run your own residential or mobile proxy, point proxyConfiguration at it and the bandwidth cost disappears.
How it works
- Expand every input into video IDs. Playlists, channels, @handles and search queries are paged through YouTube's internal API.
- Resolve each video through the InnerTube player endpoint using a mobile client context.
- Select the best caption track: your preferred languages in order, human-written before auto-generated, with an optional fallback to any available language.
- Download and parse the caption document into timestamped segments.
- Write successes to the default dataset and failures to the
failuresdataset.
A technical note on why the mobile client matters
The traditional approach — scrape the watch page, read captionTracks[].baseUrl, fetch it — is broken in a way that is easy to miss. Those WEB-client caption URLs now return HTTP 200 with a zero-length body unless they carry a Proof-of-Origin token. It looks exactly like success and yields nothing, which is why so many transcript tools quietly started returning empty strings. This Actor uses the iOS and Android client contexts, whose caption URLs still return real content, and treats an empty document as an explicit EMPTY_TRANSCRIPT failure rather than a blank result.
It also handles both caption schemas YouTube serves — the legacy <transcript><text start= dur=> form used by older videos and the newer millisecond-based timedtext format="3" form — which is a common source of "works on some videos, not others".
Input
| Field | Type | Default | Description |
|---|---|---|---|
videos | array | 1 demo video | URLs, bare IDs, playlists, channels, @handles, or search:your query |
languages | array | ["en"] | Preferred language codes, in priority order |
preferManualCaptions | boolean | true | Human-written before auto-generated |
allowAutoGenerated | boolean | true | Accept ASR captions |
anyLanguageFallback | boolean | true | Use any track if preferred languages are missing |
includeSegments | boolean | true | Timestamped segment array |
includeTimestampedText | boolean | false | [mm:ss]-prefixed single string |
includeSrt | boolean | false | Ready-to-use .srt |
maxItems | integer | 1000 | Total videos this run |
maxVideosPerSource | integer | 200 | Cap per playlist/channel/search |
Example input
{"videos": ["https://www.youtube.com/watch?v=aircAruvnKk","https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi","@3blue1brown","search:transformer architecture explained"],"languages": ["en", "en-GB"],"maxVideosPerSource": 50,"includeSrt": true}
Output example
One item per successful transcript (text abbreviated here):
{"position": 1,"videoId": "aircAruvnKk","url": "https://www.youtube.com/watch?v=aircAruvnKk","status": "OK","title": "But what is a neural network?","channel": "3Blue1Brown","channelId": "UCYO_jab_esuFRV4b17AJtAw","durationSeconds": 1120,"viewCount": 19528431,"language": "en","languageName": "English","isAutoGenerated": false,"availableLanguages": [{ "languageCode": "en", "languageName": "English", "isGenerated": false, "isTranslatable": true },{ "languageCode": "de", "languageName": "German", "isGenerated": false, "isTranslatable": true }],"segmentCount": 286,"characterCount": 18342,"wordCount": 3357,"text": "…full transcript as a single clean string…","segments": [{ "start": 4.2, "duration": 3.1, "end": 7.3, "text": "…" },{ "start": 7.3, "duration": 2.8, "end": 10.1, "text": "…" }],"scrapedAt": "2026-09-21T09:14:02Z"}
A failed video, written to the failures dataset and not billed:
{"videoId": "XXXXXXXXXXX","url": "https://www.youtube.com/watch?v=XXXXXXXXXXX","status": "NO_TRANSCRIPT","error": "video has no caption tracks","title": "Some video","availableLanguages": [],"sourceInput": "@somechannel"}
Each run also writes a RUN_SUMMARY record to the key-value store with the status breakdown, request count, bytes transferred and the estimated residential-proxy cost for that run.
Pricing
Pay per result, and only for a transcript actually returned. Failures go to a separate dataset that is not billed.
| Actor price | $3.00 per 1,000 transcripts |
| Residential proxy bandwidth (your account) | ~$0.39 per 1,000 |
| Realistic all-in | ~$3.39 per 1,000 |
Use cases
Feeding LLMs and RAG pipelines. Clean plain text plus timestamps is exactly the shape a chunker wants. Turn a 200-video channel into a searchable corpus in one run.
Content repurposing. Pull transcripts for a whole playlist and generate summaries, blog drafts, show notes or clip suggestions.
Research and media analysis. Quantitative study of what was said across a channel or topic over time, with timestamps for citation.
Subtitle workflows. Export SRT for videos where captions exist but the file was never published.
Accessibility auditing. The availableLanguages array plus isAutoGenerated shows which videos have real human captions and which rely on ASR.
FAQ & Support
Can it do a whole channel? Yes. Pass the channel URL or @handle and it pages through the Videos tab, optionally including Shorts. Use maxVideosPerSource to cap it.
Do I need a YouTube API key? No. This uses no authentication, no cookies and no login. It also does not touch the official Data API, so it does not consume your quota.
Why did I get IP_BLOCKED? YouTube refused the request because it came from a datacenter IP. Enable Apify Proxy with the RESIDENTIAL group — that is the default, so this usually means it was switched off.
Why EMPTY_TRANSCRIPT? YouTube returned a caption document with no cues. This is normally a Proof-of-Origin rejection. Retrying through a residential proxy usually resolves it. It is reported rather than silently returned as empty text.
Can I get auto-generated captions only, or human-written only? Yes — preferManualCaptions and allowAutoGenerated control this independently.
What about videos with no captions at all? They return NO_TRANSCRIPT in the failures dataset and cost you nothing. No scraper can generate captions that YouTube does not have; anything claiming otherwise is transcribing the audio, which is a different and far more expensive job.
How fast is it? Around 5 videos in parallel by default. Concurrency is deliberately conservative because YouTube rate-limits aggressively and a throttled run is worse than a slightly slower one. Raise maxConcurrency if your proxy pool can take it.
Is this legal? It reads publicly available caption tracks from public videos — no login, no DRM circumvention, no personal data. Transcripts are the copyrighted work of their creators; you are responsible for how you use them, and fair-use limits apply to reproduction.
Something looks wrong. Open an issue on the Issues tab with your input JSON and the run ID. Include the RUN_SUMMARY record if you can — it contains the status breakdown that usually identifies the cause immediately.