YouTube Transcript Scraper — Multi-Client Fallback
Pricing
from $1.40 / 1,000 results
YouTube Transcript Scraper — Multi-Client Fallback
Get YouTube transcripts and subtitles reliably. Seven InnerTube clients with automatic fallback, residential retry when YouTube blocks an IP, SRT/VTT/plain text output. No browser, no API key.
Pricing
from $1.40 / 1,000 results
Rating
0.0
(0)
Developer
Steady API
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
19 days ago
Last modified
Categories
Share
Pull transcripts and subtitles from any YouTube video. Watch pages, youtu.be links, Shorts, live replays and bare video IDs all work.
Output as timed segments, plain text, SRT or WebVTT — or all four at once.
Why another transcript Actor
Because the popular ones still fail, and they fail for a reason you can fix.
YouTube serves its player data through InnerTube, the private API its own apps use. Every client — iOS, Android, mobile web, desktop web — gets a slightly different response, and YouTube gates them independently. Measured on 2026-09-15 against the same video:
| Client | Caption tracks | Transcript body |
|---|---|---|
ANDROID | returned 6 tracks | served XML only, fmt=json3 ignored |
IOS | returned 6 tracks | clean json3, 61 segments |
If your scraper speaks one client and that client is gated today, your run returns nothing.
This Actor tries four clients in order (IOS → ANDROID → MWEB → WEB) and parses both json3 and the legacy XML caption format. Every row tells you which client actually resolved it, in resolvedWith.
What you get
- Four-client fallback. One gated client does not end the run.
- Two caption parsers.
json3first, XML second. Format changes do not break you. - No browser, no proxy required. Direct API calls. Runs are fast and cheap, and a proxy is optional rather than mandatory.
- Every language the video has.
availableLanguageslists all tracks with auto-generated flags, so you can see what else you could have pulled. - Honest failures. A missing video returns a row with
errorType, not a dead run.NO_CAPTIONS,VIDEO_UNAVAILABLE,INVALID_INPUT,FETCH_FAILED. - Billing is one result per returned row, including rows that carry an
error, so what you are charged always matches the dataset you get. RUN_SUMMARYin the key-value store:requested,succeeded,failed,successRate.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
videos | array | required | URLs or 11-char IDs. Watch, youtu.be, /shorts/, /live/, /embed/ all parsed |
startUrls | array | [] | Same thing in Apify request-list format, if you prefer it |
preferredLanguages | array | ["en"] | In order of preference. Manual captions win over auto-generated |
translateTo | string | "" | YouTube-side auto-translation, e.g. es. Empty keeps the original |
outputFormat | string | segments | segments, text, srt, vtt, or all |
includeMetadata | boolean | true | Title, channel, duration, views, description, thumbnail |
maxConcurrency | integer | 5 | 1-10 |
proxyConfiguration | object | optional | Not needed for normal volumes |
Example
{"videos": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ","https://youtu.be/jNQXAC9IVRw","https://www.youtube.com/shorts/tPEE9ZwTmy0","kJQP7kiw5Fk"],"preferredLanguages": ["en", "es"],"outputFormat": "all"}
Output
{"videoId": "jNQXAC9IVRw","url": "https://www.youtube.com/watch?v=jNQXAC9IVRw","title": "Me at the zoo","channelName": "jawed","durationSeconds": 19,"viewCount": 430401896,"language": "en","isAutoGenerated": false,"availableLanguages": [{ "code": "en", "name": "English", "auto": false },{ "code": "de", "name": "German", "auto": false }],"segmentCount": 6,"characterCount": 212,"resolvedWith": "IOS","segments": [{ "start": 1.2, "duration": 2.16, "text": "All right, so here we are, in front of the elephants" }],"text": "All right, so here we are, in front of the elephants ...","srt": "1\n00:00:01,200 --> 00:00:03,360\nAll right, so here we are...","vtt": "WEBVTT\n\n00:00:01.200 --> 00:00:03.360\n..."}
Failed rows look like this instead:
{"videoId": "ZZZZZZZZZZZ","error": "Video could not be opened (tried: IOS:ERROR, ANDROID:ERROR, MWEB:ERROR, WEB:ERROR)","errorType": "VIDEO_UNAVAILABLE"}
The tried: list tells you exactly which clients were attempted and what each said. No guessing.
Common uses
- Feed video content into an LLM for summaries, chapters or Q&A
- Build searchable archives of a channel
- Generate SRT files for re-uploading or translation
- Content research: what a competitor actually says, not just their title
Notes
- Not every video has captions. Music videos, many Shorts and some regional uploads have none. Those return
NO_CAPTIONSrather than pretending. - Auto-generated captions have no punctuation and mis-hear proper nouns.
isAutoGeneratedtells you which you got, so you can decide whether to clean it. translateTouses YouTube's own machine translation. Quality varies. YouTube sometimes refuses translated captions; in that case the original-language transcript is returned andtranslationErrorexplains why.- Private, deleted, members-only and some age-restricted videos cannot be read by anyone without login, and this Actor does not attempt to log in.
Legal
Only publicly available caption data is requested, through the same endpoints YouTube's own clients use. No login, no DRM circumvention, no video or audio download.
Code examples
Copy-paste Python and Node examples (zero dependencies) live in github.com/steadyapi/scrapers. The Python one for this Actor is python/youtube_transcript.py.
Minimal call with plain HTTP:
curl -X POST "https://api.apify.com/v2/acts/steadyapi~youtube-transcript-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' -d @input.json
Use it from AI agents (MCP)
Add this Actor as a tool in Claude, Cursor or any MCP client through the Apify MCP server:
https://mcp.apify.com/?tools=steadyapi/youtube-transcript-scraper
Authenticate with your Apify token (OAuth is also supported). The agent can then call the Actor directly and read the results.
FAQ
Do I need a YouTube API key? No. The Actor reads the same caption data the YouTube apps use, so no Google Cloud project or quota is involved.
What if a video has no captions?
You get a row with errorType: NO_CAPTIONS so you always know what happened to every URL.
Does it work with auto-generated captions and Shorts? Yes. Auto-generated tracks are returned when there is no manual track, and Shorts URLs are accepted like any other video URL.
Why did a video need a residential proxy?
YouTube sometimes asks datacenter IPs to sign in. When that happens the Actor retries that single video on a residential proxy and marks the row with residentialFallbackUsed: true.
Can it translate transcripts?
It asks YouTube for its own machine translation. YouTube sometimes refuses; then you get the original language plus a translationError note.