YouTube Transcript Scraper — Multi-Client Fallback avatar

YouTube Transcript Scraper — Multi-Client Fallback

Pricing

from $1.40 / 1,000 results

Go to Apify Store
YouTube Transcript Scraper — Multi-Client Fallback

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

Steady API

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

19 days ago

Last modified

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:

ClientCaption tracksTranscript body
ANDROIDreturned 6 tracksserved XML only, fmt=json3 ignored
IOSreturned 6 tracksclean 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. json3 first, 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. availableLanguages lists 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_SUMMARY in the key-value store: requested, succeeded, failed, successRate.

Input

FieldTypeDefaultNotes
videosarrayrequiredURLs or 11-char IDs. Watch, youtu.be, /shorts/, /live/, /embed/ all parsed
startUrlsarray[]Same thing in Apify request-list format, if you prefer it
preferredLanguagesarray["en"]In order of preference. Manual captions win over auto-generated
translateTostring""YouTube-side auto-translation, e.g. es. Empty keeps the original
outputFormatstringsegmentssegments, text, srt, vtt, or all
includeMetadatabooleantrueTitle, channel, duration, views, description, thumbnail
maxConcurrencyinteger51-10
proxyConfigurationobjectoptionalNot 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_CAPTIONS rather than pretending.
  • Auto-generated captions have no punctuation and mis-hear proper nouns. isAutoGenerated tells you which you got, so you can decide whether to clean it.
  • translateTo uses YouTube's own machine translation. Quality varies. YouTube sometimes refuses translated captions; in that case the original-language transcript is returned and translationError explains 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.

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.