YouTube Transcript API: Scrape Video Transcripts, No API Key
Pricing
Pay per event
YouTube Transcript API: Scrape Video Transcripts, No API Key
Fetch the transcript of any public YouTube video, Short or embed as clean text, timed JSON, SRT or WebVTT. Manual captions first, auto-generated as fallback, clear error per video. Uses Apify residential proxy. $4 per 1,000 transcripts, MCP-ready.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Nguyen Vu Trung Hieu
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Share
Fetch the transcript of any public YouTube video, Short or embed as clean text, timed JSON segments, SRT or WebVTT. Manual captions are used before auto-generated ones, and every video gets either a transcript or a clear error code instead of failing the run. Pay per use: $4 per 1,000 transcripts, failed videos are free.
Use it to download YouTube transcripts in bulk, feed videos to ChatGPT, Claude or a RAG pipeline, or build a searchable transcript archive without a YouTube API key.
This Actor runs through Apify residential proxy on the Apify platform, because YouTube blocks most datacenter and cloud IPs. The proxy is enabled by default in the input and its cost is included in the per-transcript price.
Use it from an AI agent (MCP)
Call this Actor from any MCP client through the Apify MCP server.
A hosted MCP server and HTTP API for the same data is being prepared at api.openkrill.app (planned tool get_transcript, overview at tools.openkrill.app); the YouTube tool there is coming soon.
What it does
- Accepts video IDs and every common link form:
watch?v=,youtu.be/,/shorts/,/embed/,/live/,m.andmusic.hosts. - Picks the best caption track by your language priority list, using human-made captions before auto-generated ones for each language;
enalso matches regional tracks such asen-USoren-GB, with an exact match winning. - When none of your languages exist, returns the transcript in the video's original spoken language instead of failing (
languageFallback: truemarks it); setfallbackToAnyLanguagetofalseto get aNoTranscriptFounderror instead. - Optionally returns YouTube's own machine translation into a target language.
- Returns the video title and channel name with every transcript.
- Never fails the whole run because of one video: each video gets either a transcript or an error object with a machine-readable code and a
retryableflag. - Skips duplicate videos in the same run, so you are never charged twice for one transcript.
- Retries network and server errors with exponential backoff, and retries blocked requests from fresh proxy IPs when a proxy is configured.
Input
| Field | Type | Default | Description |
|---|---|---|---|
videos | string[] | required | Video URLs or IDs, up to 1000 per run. |
languages | string[] | ["en"] | Language codes in priority order, e.g. ["en", "en-GB", "de"]. A code also matches its regional variants. |
fallbackToAnyLanguage | boolean | true | When none of languages exist, return the original-language (or first available) track instead of an error. |
translateTo | string | none | Language code to translate into when no track in that language exists. |
outputFormat | segments | text | srt | vtt | segments | Shape of the transcript in each result. |
maxConcurrency | integer 1-10 | 3 | Videos fetched in parallel. |
proxyConfiguration | proxy | Apify residential | Leave the default on the Apify platform; see Limits. |
Example:
{"videos": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ","https://youtu.be/jNQXAC9IVRw","https://www.youtube.com/shorts/xxxxxxxxxxx"],"languages": ["en"],"outputFormat": "segments"}
Output
One dataset item per video. A successful item (segments shortened):
{"status": "ok","input": "https://www.youtube.com/watch?v=dQw4w9WgXcQ","videoId": "dQw4w9WgXcQ","title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)","channelName": "Rick Astley","languageCode": "en","language": "English","isGenerated": false,"languageFallback": false,"translatedFrom": null,"format": "segments","text": "[♪♪♪] ♪ We're no strangers to love ♪ ♪ You know the rules and so do I ♪ ...","segments": [{ "text": "[♪♪♪]", "start": 1.36, "duration": 1.68 },{ "text": "♪ We're no strangers to love ♪", "start": 18.64, "duration": 3.24 }],"segmentCount": 61,"fetchedAt": "2026-09-30T08:00:00.000Z"}
With outputFormat srt or vtt, segments is replaced by subtitles holding the file content; with text, only text is returned.
text is always present.
A failed item:
{"status": "error","input": "https://www.youtube.com/shorts/xxxxxxxxxxx","videoId": "xxxxxxxxxxx","error": {"code": "VideoUnavailable","message": "The video is no longer available: xxxxxxxxxxx","retryable": false},"fetchedAt": "2026-09-30T08:00:00.000Z"}
Error codes
| Code | Meaning | Retryable |
|---|---|---|
InvalidVideoId | The input is not a YouTube video ID or link. | no |
VideoUnavailable | The video does not exist or was removed. | no |
VideoUnplayable | YouTube will not play it (private, processing, region-locked); the message has YouTube's reason. | no |
AgeRestricted | Age-gated; transcripts need a signed-in account, which this Actor does not use. | no |
TranscriptsDisabled | The uploader turned captions off. | no |
NoTranscriptFound | None of your languages exist and fallbackToAnyLanguage is false; error.available lists the ones that do. | no |
NotTranslatable / TranslationLanguageNotAvailable | YouTube does not offer that translation; error.available lists options. | no |
RequestBlocked / IpBlocked | YouTube blocked the request as automated traffic. | yes |
PoTokenRequired | YouTube demanded a proof-of-origin token for this track. | no |
FailedToCreateConsentCookie | The EU cookie consent page could not be passed. | no |
YouTubeRequestFailed | Network or YouTube server error after retries. | yes |
YouTubeDataUnparsable | YouTube changed its response format; we monitor for this and fix it. | no |
Pricing
Pay per event: $4 per 1,000 transcripts ($0.004 per transcript event, charged only for items with status: "ok").
Failed videos, invalid inputs and duplicates are free.
Residential proxy traffic is covered by that price; you are not billed for it separately.
On the Apify free plan a run processes the first 10 videos and skips the rest (the run log and status message say so); any paid Apify plan runs up to 1000 videos per run.
FAQ
Do I need a YouTube API key? No.
Does it work for videos without captions? No. Only captions YouTube already has are returned; there is no speech-to-text.
Can I get channel or playlist transcripts? Not directly: pass the video URLs or IDs. Up to 1000 videos per run.
Which formats are supported?
segments (timed JSON plus text), text, srt and vtt.
Limits
- YouTube blocks most datacenter and cloud IPs, so the Actor is meant to run on the Apify platform with the default residential proxy. Turning the proxy off (or running it elsewhere) typically produces
RequestBlockedorIpBlockedon anything beyond a few videos. - Translation uses YouTube's own machine translation. YouTube currently rate-limits translated caption downloads for anonymous clients, so
translateTooften returnsRequestBlocked; requesting the original language is reliable. - Age-restricted, private and members-only videos are not supported, because they require signing in.
- On the Apify free plan, runs are capped at 10 videos; upgrade to any paid plan for up to 1000 per run.
- Only captions YouTube already has are returned; there is no speech-to-text for videos without captions.
Credits
The caption discovery approach is a TypeScript port of youtube-transcript-api by Jonas Depoix (MIT License).
See NOTICE for the license text.