YouTube Transcript Scraper - Subtitles & Timestamps
Pricing
$0.80 / 1,000 per video transcript returneds
YouTube Transcript Scraper - Subtitles & Timestamps
Get YouTube transcripts with timestamps from any video, playlist, channel or search. Auto-generated (ASR) and human captions, any language, optional machine translation, plus SRT/VTT and full video metadata. No API key, no login.
Pricing
$0.80 / 1,000 per video transcript returneds
Rating
0.0
(0)
Developer
Scrapers Delight
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
π¬ YouTube Transcript Scraper
Pull the transcript of any YouTube video β as plain text and as timestamped cues β from a video URL, a whole playlist, a channel, or a search query. Auto-generated (ASR) captions and human-written subtitles, in any language the video publishes, with optional machine translation into 18+ more.
No API key. No login. No cookies. No YouTube Data API quota.
What does YouTube Transcript Scraper do?
You give it videos. It gives you back, one row per video:
- π
transcriptβ the whole thing as clean, joined plain text, ready to paste into an LLM - β±οΈ
segmentsβ every caption cue withstart,durationandendin seconds - ποΈ
srt/vttβ the same transcript rendered as a ready-to-use subtitle file (optional) - π
languageCode+isAutoGeneratedβ exactly which track you got, and whether a human wrote it - ποΈ
availableLanguagesβ every other caption track the video offers, so you know what else you could have asked for - π
translateToβ have YouTube translate the transcript before it is returned - πΊ video metadata β title, channel, channel ID, duration, views, likes, publish date, YouTube category, description, keywords, thumbnail
- π¦
transcriptStatusβok,no-captions,no-transcript-in-requested-language,video-unavailable. A row is never silently empty.
Quick start
{"videoUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ","https://youtu.be/jNQXAC9IVRw","dQw4w9WgXcQ"]}
Or point it at a whole channel, a playlist and a search at once:
{"channelUrls": ["https://www.youtube.com/@veritasium"],"playlistUrls": ["https://www.youtube.com/playlist?list=PLbpi6ZahtOH6Blw3RGYpWkSByi_T7Rygb"],"searchQueries": ["noticias en espaΓ±ol hoy"],"maxVideosPerSource": 25,"maxItems": 75}
URL forms accepted: watch?v=, youtu.be/, /shorts/, /embed/, /live/, music.youtube.com, youtube-nocookie.com, and bare 11-character video IDs. Channels accept @handle, /channel/UCβ¦, /c/, /user/ or a bare UCβ¦ ID. All twelve URL forms are covered by the parser's test cases.
Two things most transcript scrapers get wrong
1. Auto-generated captions come back duplicated. YouTube's ASR json3 stream is a rolling caption: every real cue is followed by an aAppend redraw event whose only content is a newline. Parsers that ignore the flag emit every line twice. Measured on a real ASR track: 133 caption events, of which 66 were redraws β this actor keeps the 67 real ones.
2. A Spanish video comes back blank because you asked for English. By default fallbackToAnyLanguage is on: if the video publishes captions but not in your preferred languages, you get the best track it does have, correctly labelled, instead of an empty row. In a 15-video mixed run, that is what turned four Spanish news videos from blanks into full transcripts.
And when a transcript genuinely cannot be produced, the row says so in transcriptStatus and transcriptError rather than shipping an empty string.
Output
One row per video. Measured over a 32-video corpus (music, tutorials, TED talks, Spanish and Korean news, DIY, Shorts, 24/7 livestreams) parsed offline from captured bytes on 2026-09-02: 28 of 32 produced a transcript β 27,678 caption cues and 226,853 words β and the other 4 genuinely publish no captions at all (three are 24/7 live news streams).
{"videoId": "dQw4w9WgXcQ","videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ","title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)","channelName": "Rick Astley","channelId": "UCuAXFkgsw1L7xaCfnd5JJOw","channelUrl": "https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw","durationSeconds": 213,"viewCount": 1810788783,"likeCount": 19368027,"publishedAt": "2009-10-24T23:57:33-07:00","uploadedAt": "2009-10-24T23:57:33-07:00","category": "Music","keywords": ["rick astley", "never gonna give you up", "β¦"],"description": "The official video for βNever Gonna Give You Upββ¦","thumbnailUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/sddefault.jpg","isLiveContent": false, "isPrivate": false, "isUnlisted": false, "isFamilySafe": true,"transcriptStatus": "ok","language": "English","languageCode": "en","isAutoGenerated": false,"isTranslated": false,"translatedTo": null,"transcript": "[βͺβͺβͺ] βͺ We're no strangers to love βͺ βͺ You know the rules and so do I βͺ β¦","segments": [{ "start": 1.36, "duration": 1.68, "end": 3.04, "text": "[βͺβͺβͺ]" },{ "start": 18.64, "duration": 3.24, "end": 21.88, "text": "βͺ We're no strangers to love βͺ" }],"segmentCount": 61,"wordCount": 487,"characterCount": 2089,"availableLanguages": [{ "languageCode": "en", "languageName": "English", "kind": "manual" },{ "languageCode": "en", "languageName": "English (auto-generated)", "kind": "asr" },{ "languageCode": "de-DE", "languageName": "German (Germany)", "kind": "manual" },{ "languageCode": "ja", "languageName": "Japanese", "kind": "manual" },{ "languageCode": "pt-BR", "languageName": "Portuguese (Brazil)", "kind": "manual" },{ "languageCode": "es-419", "languageName": "Spanish (Latin America)", "kind": "manual" }],"availableLanguageCount": 6,"translationLanguages": ["ar", "zh-Hant", "nl", "en", "fr", "de", "hi", "id", "β¦"],"scrapedAt": "2026-09-02T04:22:21.784Z"}
Measured field fill
Over the same 32-video corpus. "With a transcript" is the 28 rows that produced one.
| Field | All 32 rows | Rows with a transcript |
|---|---|---|
videoId, videoUrl, title, channelName, channelId, channelUrl | 100% | 100% |
durationSeconds, viewCount, thumbnailUrl | 100% | 100% |
publishedAt, uploadedAt, category | 100% | 100% |
isLiveContent, isPrivate, isUnlisted, isFamilySafe | 100% | 100% |
transcriptStatus, segmentCount, wordCount, characterCount | 100% | 100% |
likeCount | 97% | 96% |
description | 91% | 93% |
keywords | 81% | 86% |
transcript, segments, languageCode, language, isAutoGenerated | 88% | 100% |
likeCount is missing where the uploader hides it; keywords and description where the uploader left them empty. Nothing here is estimated β these are counts over real rows.
Options that matter
languagesβ ordered preference list, e.g.["en", "es", "pt-BR"].enalso matchesen-USanden-GB. Use["any"]to always take the video's own default track.fallbackToAnyLanguage(on) β never return blank just because your preferred language is missing.preferAutoGenerated(off) β human captions win by default because they are punctuated; switch on for ASR, which is usually more complete on long videos.translateToβ a language code (es,fr,de,jaβ¦) to have YouTube translate the transcript. Each row lists its own valid targets intranslationLanguages.includeSegments(on) /includeSrt/includeVttβ which representations you want. TurnincludeSegmentsoff for much smaller rows when you only need the text.includeVideoMetadata(on) β publish date, category and like count come from a second, small request; turn it off to shave a request per video.skipVideosWithoutTranscript(off) β leave off to see every video and why it failed; switch on to deliver only successes.maxVideosPerSource(50) andmaxItems(200) β both bounded by default so a 5,000-upload channel cannot run away.
Pricing
Pay per result. You are charged for rows you actually receive, and never for a video that was blocked.
| Event | Price | When it fires |
|---|---|---|
transcript-scraped | $0.0008 | One per video row pushed to the dataset |
That is $0.80 per 1,000 videos β no run start fee, and cheaper than every other YouTube transcript actor on the Store with real traction (the lane sits between $0.001 and $0.01 per video). Videos are deduplicated across playlists, channels and searches before billing, so the same video is never charged twice in one run.
Worked examples: a 200-video channel β $0.16. Ten thousand videos β $8.00. A single video β $0.0008.
Rows are billed through Apify's gated pushData form, so at a spend cap the run stops cleanly and you are never charged for rows you did not receive.
FAQ
Does this need a YouTube API key or a Google account? No. It talks to YouTube's own public InnerTube endpoint with YouTube's own public web key. No login, no cookies, no OAuth, no Data API quota.
Does it transcribe videos that have no captions?
No β and it says so plainly rather than pretending. This actor reads the captions YouTube already publishes (human-written or YouTube's own ASR). If a video has neither, the row comes back with transcriptStatus: "no-captions". Speech-to-text on the audio is a different, much more expensive product.
Do I get auto-generated captions, or only human ones?
Both. Human captions are preferred for the same language because they are punctuated and accurate, and YouTube's ASR track is used whenever that is what exists. isAutoGenerated tells you which one you got, every time.
Why does it need a residential proxy?
Because YouTube blocks datacenter IPs on this endpoint. Measured 2026-09-02 across three videos and seven InnerTube client profiles: through a datacenter pool every single request answered LOGIN_REQUIRED β "Sign in to confirm you're not a bot" with zero caption tracks; through residential it returned full transcripts on all three. Apify Proxy with the RESIDENTIAL group is the default and needs no configuration from you.
What happens when a video is blocked? It is retried on fresh proxy exits (the wall is per-IP, not per-video), then β if it still will not open β it is counted and named in the run's status message, not delivered as an empty row and not charged. A blocked page reported as "no results" is the failure mode this actor exists to avoid.
Can I get transcripts for a whole channel?
Yes. Put the channel URL or @handle in channelUrls. It walks the channel's Videos tab with continuation tokens, bounded by maxVideosPerSource (default 50 β raise it for a full back catalogue).
Can I translate the transcript?
Yes. Set translateTo to a language code and YouTube translates it server-side before it is returned. Each row lists its own available targets in translationLanguages (18 for the sample video above).
Does it work on YouTube Shorts and livestreams?
Shorts, yes β pass the /shorts/ URL. Livestreams only once the stream has captions; 24/7 news channels streaming live usually publish none, and come back no-captions. Three of the four caption-less videos in our corpus were exactly that.
How long can a transcript be?
The longest in our corpus was a 12-hour Python course: 15,121 cues, 92,922 words, a 1.89 MB row. Everything fits in one dataset item; on the rare video large enough to exceed Apify's 9 MB item limit the timestamped representations are dropped and the plain text kept, flagged with oversizedRow.
Are the timestamps accurate?
They come straight from YouTube's own cue timings in milliseconds, converted to seconds. start, duration and end are all provided, and the SRT/VTT renderers use the same numbers.
What if YouTube changes the caption format? The parser reads json3 first and falls back to YouTube's srv1 XML shape. Verified on the same video: both produce 61 identical cues with identical text.
Is the output stable enough to diff between runs?
Yes β field names and types do not change per video, and every row carries scrapedAt. Counts like viewCount and likeCount are a snapshot at that moment.
Notes and honest limits
- Captions only. This reads what YouTube publishes. It does not run speech recognition on the audio, so a video with no captions produces no transcript β by design, and reported as such.
- Residential proxy is required, not optional. Datacenter IPs get the bot wall on this endpoint. It is the default; leave it alone unless you are supplying your own residential proxy.
- Private, deleted, age-restricted and members-only videos return
transcriptStatus: "video-unavailable"with the reason YouTube gave. This actor has no login and does not attempt one. - Translations are YouTube's machine translation, not a human or an LLM. Quality is whatever YouTube's is.
enmatchesen-US/en-GB, and both anenmanual and anenASR track can exist on the same video βisAutoGenerateddisambiguates.- You are responsible for your use of this data. Review YouTube's Terms of Service and respect copyright in the transcripts you collect.