YouTube Caption & Whisper AI Transcript Extractor
Get timestamped transcripts from YouTube videos in your preferred language, with optional AI transcription for videos that have no captions at all. Returns full text, timed segments, and core video metadata.
Input schema
Input fields, types, required flags, descriptions, defaults, and prefills come from the published definition. Prefill examples are distinct from defaults.
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | optional | What to scrape: specific videos, a channel's uploads, or a playlist. |
videoUrls | array | optional | YouTube watch URLs, youtu.be short links, Shorts/embed URLs, or plain 11-character video IDs (mode=videos). Duplicate IDs are processed once. |
channelUrls | array | optional | Channel URLs or handles (mode=channel), e.g. https://www.youtube.com/@TED, https://www.youtube.com/channel/UC..., or @TED. Each channel's latest uploads are enumerated and every video is transcribed. |
Show all input fields
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | optional | What to scrape: specific videos, a channel's uploads, or a playlist. |
videoUrls | array | optional | YouTube watch URLs, youtu.be short links, Shorts/embed URLs, or plain 11-character video IDs (mode=videos). Duplicate IDs are processed once. |
channelUrls | array | optional | Channel URLs or handles (mode=channel), e.g. https://www.youtube.com/@TED, https://www.youtube.com/channel/UC..., or @TED. Each channel's latest uploads are enumerated and every video is transcribed. |
maxVideosPerChannel | integer | optional | Maximum number of videos to enumerate from each channel (mode=channel). 1-1,000. |
playlistUrls | array | optional | Playlist URLs or IDs (mode=playlist), e.g. https://www.youtube.com/playlist?list=PL... or PL.... Every video in the playlist is transcribed. |
maxVideosPerPlaylist | integer | optional | Maximum number of videos to enumerate from each playlist (mode=playlist). 1-1,000. |
language | string | optional | Caption language to fetch. Leave Auto-detect to use the video's original language. |
includeAutoGenerated | boolean | optional | Whether to include auto-generated captions when manual captions are not available. |
useWhisper | boolean | optional | When YouTube has no transcript (disabled captions, music-only, or blocked), download the audio and transcribe with Whisper AI (faster-whisper, CPU). Adds ~30-180 s per video. Enabled by default to guarantee transcript output even when YouTube captions are unavailable. |
whisperModel | string | optional | Whisper model size to use when `useWhisper` is enabled. Larger = more accurate but slower and more RAM. 'base' is balanced. |
includeWordTimings | boolean | optional | Add a wordTimings array with word-level start/end times. Only auto-generated YouTube captions expose word timings; manual captions and AI transcripts do not. |
maxWhisperMinutes | integer | optional | Leave unset for the legacy behavior (AI enabled with no length limit). Set to 0 explicitly to disable AI transcription. A positive value only sends videos of that length or shorter to AI. AI still requires Use Whisper AI fallback. |
proxyCountry | string | optional | Country/region for the proxy IP. Useful if transcripts are geo-blocked in the default US region. |
outputFormat | string | optional | How transcript data is included. 'full' = segments and full_text; 'text_only' = full_text only; 'segments_only' = segments only; 'srt' / 'vtt' = ready-to-use subtitle text derived from the segments. |
Download the published input schema
View complete JSON
{
"description": "Extract timestamped transcripts and rich metadata from YouTube videos, channels, and playlists, with optional AI transcription.",
"properties": {
"channelUrls": {
"description": "Channel URLs or handles (mode=channel), e.g. https://www.youtube.com/@TED, https://www.youtube.com/channel/UC..., or @TED. Each channel's latest uploads are enumerated and every video is transcribed.",
"editor": "stringList",
"items": {
"type": "string"
},
"title": "Channel URLs",
"type": "array"
},
"includeAutoGenerated": {
"default": true,
"description": "Whether to include auto-generated captions when manual captions are not available.",
"prefill": true,
"title": "Include Auto-Generated Captions",
"type": "boolean"
},
"includeWordTimings": {
"default": false,
"description": "Add a wordTimings array with word-level start/end times. Only auto-generated YouTube captions expose word timings; manual captions and AI transcripts do not.",
"editor": "checkbox",
"prefill": false,
"title": "Include Word Timings",
"type": "boolean"
},
"language": {
"default": "",
"description": "Caption language to fetch. Leave Auto-detect to use the video's original language.",
"editor": "select",
"enum": [
"",
"af",
"sq",
"am",
"ar",
"hy",
"az",
"eu",
"be",
"bn",
"bs",
"bg",
"my",
"ca",
"ceb",
"zh-Hans",
"zh-Hant",
"co",
"hr",
"cs",
"da",
"nl",
"en",
"eo",
"et",
"fil",
"fi",
"fr",
"fy",
"gl",
"ka",
"de",
"el",
"gu",
"ht",
"ha",
"haw",
"he",
"hi",
"hmn",
"hu",
"is",
"ig",
"id",
"ga",
"it",
"ja",
"jv",
"kn",
"kk",
"km",
"rw",
"ko",
"ku",
"ky",
"lo",
"la",
"lv",
"lt",
"lb",
"mk",
"mg",
"ms",
"ml",
"mt",
"mi",
"mr",
"mn",
"ne",
"no",
"ny",
"or",
"ps",
"fa",
"pl",
"pt",
"pa",
"ro",
"ru",
"sm",
"gd",
"sr",
"sn",
"sd",
"si",
"sk",
"sl",
"so",
"st",
"es",
"su",
"sw",
"sv",
"tg",
"ta",
"tt",
"te",
"th",
"tr",
"tk",
"uk",
"ur",
"ug",
"uz",
"vi",
"cy",
"xh",
"yi",
"yo",
"zu"
],
"enumTitles": [
"Auto-detect (video's original language)",
"Afrikaans",
"Albanian",
"Amharic",
"Arabic",
"Armenian",
"Azerbaijani",
"Basque",
"Belarusian",
"Bengali",
"Bosnian",
"Bulgarian",
"Burmese",
"Catalan",
"Cebuano",
"Chinese (Simplified)",
"Chinese (Traditional)",
"Corsican",
"Croatian",
"Czech",
"Danish",
"Dutch",
"English",
"Esperanto",
"Estonian",
"Filipino",
"Finnish",
"French",
"Frisian",
"Galician",
"Georgian",
"German",
"Greek",
"Gujarati",
"Haitian Creole",
"Hausa",
"Hawaiian",
"Hebrew",
"Hindi",
"Hmong",
"Hungarian",
"Icelandic",
"Igbo",
"Indonesian",
"Irish",
"Italian",
"Japanese",
"Javanese",
"Kannada",
"Kazakh",
"Khmer",
"Kinyarwanda",
"Korean",
"Kurdish",
"Kyrgyz",
"Lao",
"Latin",
"Latvian",
"Lithuanian",
"Luxembourgish",
"Macedonian",
"Malagasy",
"Malay",
"Malayalam",
"Maltese",
"Maori",
"Marathi",
"Mongolian",
"Nepali",
"Norwegian",
"Nyanja",
"Odia",
"Pashto",
"Persian",
"Polish",
"Portuguese",
"Punjabi",
"Romanian",
"Russian",
"Samoan",
"Scots Gaelic",
"Serbian",
"Shona",
"Sindhi",
"Sinhala",
"Slovak",
"Slovenian",
"Somali",
"Sesotho",
"Spanish",
"Sundanese",
"Swahili",
"Swedish",
"Tajik",
"Tamil",
"Tatar",
"Telugu",
"Thai",
"Turkish",
"Turkmen",
"Ukrainian",
"Urdu",
"Uyghur",
"Uzbek",
"Vietnamese",
"Welsh",
"Xhosa",
"Yiddish",
"Yoruba",
"Zulu"
],
"title": "Preferred Language",
"type": "string"
},
"maxVideosPerChannel": {
"default": 50,
"description": "Maximum number of videos to enumerate from each channel (mode=channel). 1-1,000.",
"maximum": 1000,
"minimum": 1,
"title": "Max Videos per Channel",
"type": "integer"
},
"maxVideosPerPlaylist": {
"default": 50,
"description": "Maximum number of videos to enumerate from each playlist (mode=playlist). 1-1,000.",
"maximum": 1000,
"minimum": 1,
"title": "Max Videos per Playlist",
"type": "integer"
},
"maxWhisperMinutes": {
"description": "Leave unset for the legacy behavior (AI enabled with no length limit). Set to 0 explicitly to disable AI transcription. A positive value only sends videos of that length or shorter to AI. AI still requires Use Whisper AI fallback.",
"maximum": 1440,
"minimum": 0,
"title": "Max AI Length (minutes)",
"type": "integer"
},
"mode": {
"default": "videos",
"description": "What to scrape: specific videos, a channel's uploads, or a playlist.",
"editor": "select",
"enum": [
"videos",
"channel",
"playlist"
],
"enumTitles": [
"Video URLs",
"Channel uploads",
"Playlist videos"
],
"prefill": "videos",
"title": "Mode",
"type": "string"
},
"outputFormat": {
"default": "full",
"description": "How transcript data is included. 'full' = segments and full_text; 'text_only' = full_text only; 'segments_only' = segments only; 'srt' / 'vtt' = ready-to-use subtitle text derived from the segments.",
"editor": "select",
"enum": [
"full",
"text_only",
"segments_only",
"srt",
"vtt"
],
"enumTitles": [
"Full (segments + text)",
"Text Only (no segments array)",
"Segments Only (no full_text)",
"SRT subtitles",
"WebVTT subtitles"
],
"title": "Output Format",
"type": "string"
},
"playlistUrls": {
"description": "Playlist URLs or IDs (mode=playlist), e.g. https://www.youtube.com/playlist?list=PL... or PL.... Every video in the playlist is transcribed.",
"editor": "stringList",
"items": {
"type": "string"
},
"title": "Playlist URLs",
"type": "array"
},
"proxyCountry": {
"default": "US",
"description": "Country/region for the proxy IP. Useful if transcripts are geo-blocked in the default US region.",
"editor": "select",
"enum": [
"US",
"GB",
"CA",
"AU",
"DE",
"FR",
"JP",
"KR",
"BR",
"IN",
"MX",
"IT",
"ES",
"NL",
"PL",
"RU",
"SE",
"NO",
"DK",
"FI",
"ZA",
"SG",
"HK",
"TW",
"ID",
"MY",
"TH",
"PH",
"AR",
"CO",
"CL"
],
"enumTitles": [
"United States",
"United Kingdom",
"Canada",
"Australia",
"Germany",
"France",
"Japan",
"South Korea",
"Brazil",
"India",
"Mexico",
"Italy",
"Spain",
"Netherlands",
"Poland",
"Russia",
"Sweden",
"Norway",
"Denmark",
"Finland",
"South Africa",
"Singapore",
"Hong Kong",
"Taiwan",
"Indonesia",
"Malaysia",
"Thailand",
"Philippines",
"Argentina",
"Colombia",
"Chile"
],
"prefill": "GB",
"sectionCaption": "Advanced",
"title": "Proxy Country",
"type": "string"
},
"useWhisper": {
"default": true,
"description": "When YouTube has no transcript (disabled captions, music-only, or blocked), download the audio and transcribe with Whisper AI (faster-whisper, CPU). Adds ~30-180 s per video. Enabled by default to guarantee transcript output even when YouTube captions are unavailable.",
"editor": "checkbox",
"prefill": true,
"title": "Use Whisper AI fallback",
"type": "boolean"
},
"videoUrls": {
"description": "YouTube watch URLs, youtu.be short links, Shorts/embed URLs, or plain 11-character video IDs (mode=videos). Duplicate IDs are processed once.",
"editor": "stringList",
"items": {
"type": "string"
},
"prefill": [
"https://www.youtube.com/watch?v=jNQXAC9IVRw"
],
"title": "Video URLs",
"type": "array"
},
"whisperModel": {
"default": "base",
"description": "Whisper model size to use when `useWhisper` is enabled. Larger = more accurate but slower and more RAM. 'base' is balanced.",
"editor": "select",
"enum": [
"tiny",
"base",
"small",
"medium",
"large-v3-turbo"
],
"enumTitles": [
"Tiny (fastest, ~39 MB)",
"Base (balanced, ~74 MB)",
"Small (~244 MB)",
"Medium (best quality/speed, ~769 MB)",
"Large-v3-turbo (highest accuracy, ~800 MB)"
],
"prefill": "tiny",
"title": "Whisper Model",
"type": "string"
}
},
"schemaVersion": 1,
"title": "YouTube Transcript Scraper Input",
"type": "object"
}
Output schema
Published result links and storage locations. This schema is not an exhaustive contract for every field in a dataset record.
| Field | Type | Required | Description |
|---|---|---|---|
transcripts | string | optional | Dataset containing every scraped video transcript with timed segments and metadata. |
Download the published output schema
View complete JSON
{
"actorOutputSchemaVersion": 1,
"description": "One record per video with its transcript (segments, full text, SRT/VTT, optional word timings), caption/translation metadata, chapters, heatmap, and channel identity.",
"properties": {
"transcripts": {
"description": "Dataset containing every scraped video transcript with timed segments and metadata.",
"template": "{{links.apiDefaultDatasetUrl}}/items",
"title": "YouTube Transcript Scraper dataset",
"type": "string"
}
},
"title": "YouTube Caption & Whisper AI Transcript Extractor Output"
}
Dataset schema
Published dataset views and any declared field definitions. A view can select only a subset of the returned record fields.
Download the published dataset schema
View complete JSON
{
"actorSpecification": 1,
"views": {
"overview": {
"display": {
"component": "table",
"properties": {}
},
"title": "Transcripts Overview",
"transformation": {
"fields": [
"video_id",
"title",
"channel_name",
"publishedAt",
"transcript_language",
"segment_count",
"success",
"transcript_available",
"transcript_source",
"accessStatus",
"errorCode",
"duration_seconds",
"scrapedAt"
]
}
},
"transcripts": {
"display": {
"component": "table",
"properties": {}
},
"title": "Full Transcripts",
"transformation": {
"fields": [
"video_id",
"canonicalUrl",
"title",
"channel_name",
"channel_id",
"channelHandle",
"publishedAt",
"full_text",
"transcript_language",
"transcript_language_name",
"is_auto_generated",
"was_translated",
"segment_count",
"duration_seconds",
"views",
"published_date",
"segments",
"wordTimings",
"srt",
"vtt",
"available_languages",
"captionTracks",
"chapters",
"heatmap",
"transcript_source",
"transcript_available",
"accessStatus",
"success",
"errorCode",
"inputUrl",
"scrapedAt"
]
}
}
}
}
Key-value schema
Published key-value store definitions, when provided by this build.
This definition is not present in the default published build. See the published README for available documentation.
Published README
Read the full published documentation
YouTube Caption & Whisper AI Transcript Extractor
Get clean, timestamped transcripts from YouTube — single videos, whole channels, or playlists — together with the metadata you need to organize, translate, and publish the result. Every row includes the full text, timed segments, caption-track details, chapters, and channel identity, with optional AI transcription and ready-to-use SRT or WebVTT subtitles.
What this actor does
- Three collection modes: scrape specific video URLs, every upload from one or more channels, or every video in a playlist.
- Transcripts with timing: full text, timestamped segments (start, duration, and end), optional word-level timings for auto-generated captions, and SRT/VTT export.
- Language selection and translation: request a caption language; when the video has no track in that language, the actor translates through YouTube's own translation targets.
- Rich video and channel metadata: exact publish time, channel handle/URL/avatar/verification, subscriber and comment display counts, chapters, most-replayed heatmap, caption tracks, translation targets, and access/live status.
- AI fallback: when a video has no captions at all, optional Whisper transcription produces a transcript from the audio.
- Empty fields are omitted: if a video genuinely lacks a data point (for example, no chapters), that field is left out of the record instead of being written as
null.
Output per video
video_id,title,channel_name,channel_id— core video and channel identitycanonicalUrl— canonicalhttps://www.youtube.com/watch?v=...URLpublished_date— publication date (YYYY-MM-DD)publishedAt— exact publication timestamp with timezoneduration_seconds,views,like_count,category,keywords,descriptionthumbnail— video thumbnail URLchannelHandle,channelUrl,channelThumbnail,channelVerifiedsubscriberCountText— display text such as6.71M subscriberssubscriberCount— approximate integer parsed from the display textcommentCountText— display text such as10M(not an exact integer)isUnlisted,is_family_safe,is_live_content,is_upcomingaccessStatus—ok,live,upcoming,age_restricted,private,unavailable,region_blocked, orlogin_requiredwasLive,liveStatus—live,upcoming, orended_livewhen applicablescheduledStartTime— scheduled or actual broadcast start for live/upcoming videoschapters[]—{ title, start, duration, startText }for videos that expose chaptersheatmap[]— most-replayed buckets as{ start, duration, intensity }captionTracks[]—{ languageCode, languageName, isAutoGenerated, isTranslatable }translationLanguages[]—{ languageCode, languageName }targets YouTube offersrequested_language,transcript_language,transcript_language_namelanguage_matched— whether the returned transcript is in the requested languageis_auto_generated—truefor YouTube auto-captions,falsefor manual/translated captions or AI outputwas_translated—trueonly when YouTube translated the transcript into the requested languagetranscript_source—library,android_player,playwright_dom, orwhisperavailable_languages[]— every caption track YouTube offers as{ code, name, is_auto_generated }segments[]—{ start, dur, end, text }(seconds with millisecond precision); omitted fortext_only,srt, andvttfull_text— the complete transcript as one string; omitted forsegments_only,srt, andvttwordTimings[]—{ start, end, text }word timings, only whenincludeWordTimingsis on and the source is auto-generatedsrt,vtt— subtitle text whenoutputFormatissrtorvttsegment_count,transcript_available,successerror— human-readable explanation when no transcript was producederrorCode— machine-readable reason:captions_disabled,no_captions,age_restricted,login_required,blocked,unavailable,private,upcoming,live_no_transcript,timeout,invalid_url, orwhisper_failedretryable— whether a later run may succeed (for example, a temporary block or timeout)language_probability— language-detection confidence for AI transcriptsinputUrl— the URL that produced this rowscrapedAt— ISO timestamp of the scrape
Input
| Field | Type | Default | Description |
|---|---|---|---|
mode |
String | videos |
videos (specific URLs), channel (channel uploads), or playlist (playlist videos) |
videoUrls |
Array | – | Watch URLs, youtu.be links, Shorts/embed URLs, or plain 11-character IDs (mode=videos). Duplicate IDs run once. |
channelUrls |
Array | – | Channel URLs, @handles, or UC... IDs (mode=channel) |
maxVideosPerChannel |
Integer | 50 |
Maximum videos enumerated per channel (1–1,000) |
playlistUrls |
Array | – | Playlist URLs or playlist IDs (mode=playlist) |
maxVideosPerPlaylist |
Integer | 50 |
Maximum videos enumerated per playlist (1–1,000) |
language |
String | Auto-detect (video's original language) | Caption language to prefer, as a two-letter code such as en, es, ja, or ar |
includeAutoGenerated |
Boolean | true |
Use YouTube auto-generated captions when manual captions are unavailable |
useWhisper |
Boolean | true |
Transcribe the audio with AI when no YouTube transcript can be retrieved |
whisperModel |
String | base |
tiny, base, small, medium, or large-v3-turbo |
includeWordTimings |
Boolean | false |
Include word-level timings (auto-generated captions only) |
maxWhisperMinutes |
Integer | – | Leave unset for no length limit; 0 disables AI explicitly; a positive value caps AI to that video length. |
proxyCountry |
String | US |
Country for the network connection, one of the 31 supported codes |
outputFormat |
String | full |
full, text_only, segments_only, srt, or vtt |
Example: several videos with SRT subtitles
{
"mode": "videos",
"videoUrls": [
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"https://youtu.be/jNQXAC9IVRw",
"https://www.youtube.com/shorts/s5ORfA5W-M0"
],
"language": "en",
"outputFormat": "srt"
}
Example: every upload from a channel
{
"mode": "channel",
"channelUrls": ["https://www.youtube.com/@TED"],
"maxVideosPerChannel": 25,
"language": "en",
"includeWordTimings": true
}
Example: a playlist translated to Spanish
{
"mode": "playlist",
"playlistUrls": ["https://www.youtube.com/playlist?list=PL1234567890abcdef"],
"maxVideosPerPlaylist": 100,
"language": "es",
"outputFormat": "full"
}
Example: AI transcription for videos without captions
{
"mode": "videos",
"videoUrls": ["https://www.youtube.com/watch?v=IR1xf8jG7ug"],
"useWhisper": true,
"whisperModel": "small",
"maxWhisperMinutes": 20
}
Use cases
- AI and RAG pipelines — feed clean, timestamped transcripts into language models, search indexes, and knowledge bases.
- Content repurposing — turn webinars, interviews, and long-form videos into articles, summaries, and social posts.
- Subtitling and localization — export SRT/VTT and translate transcripts for multilingual audiences.
- Media monitoring — follow a channel or playlist and collect everything its creators publish.
- Research and journalism — quote speakers accurately with timestamps, chapters, and exact publish dates.
- Education and accessibility — build searchable transcripts for lectures, courses, and public talks.
FAQ
Which videos can I scrape? Any public YouTube video with manual or auto-generated captions, plus public videos without captions when AI transcription is enabled. Private, deleted, members-only, and age-restricted videos cannot be transcribed.
What happens with live, upcoming, or age-restricted videos?
The actor returns the metadata it can see (title, channel, dates, status) with success: false and a truthful accessStatus / errorCode. Live streams, premieres, and age-gated videos have no transcript until they become publicly playable.
What if a video has no captions at all?
Keep useWhisper on and the actor transcribes the audio. base is a good balance; use small for accented speech, multiple speakers, or noisy recordings. Use maxWhisperMinutes to skip very long videos, or set it to 0 explicitly to turn AI off.
How does the requested language work?
The actor first looks for a caption track in your language, then for a regional variant such as en-GB for en. If no track exists, it asks YouTube to translate an available track. was_translated and language_matched tell you exactly what happened.
Which output formats are available?
full returns text plus timed segments; text_only returns only the text; segments_only returns only the timed segments; srt and vtt return ready-to-use subtitle files. All formats keep the video metadata.
Can I collect a whole channel or playlist?
Yes. Choose channel or playlist mode and provide one or more URLs. You can cap each target with maxVideosPerChannel or maxVideosPerPlaylist. Duplicate videos across targets are collected once.
Are word-level timestamps available?
Yes, for videos with auto-generated YouTube captions. Turn on includeWordTimings; manually uploaded captions and AI transcripts do not expose word timings.
Do I need to set up a proxy? No. The actor chooses a working connection to YouTube automatically. Just fill in the input and run it.
Is this affiliated with YouTube? No. This is an independent, third-party actor that reads publicly available YouTube data. It is not affiliated with, endorsed by, or operated by YouTube or Google.
Limitations
- YouTube sometimes blocks automated requests from cloud networks. The actor retries and switches connection paths automatically, but an occasional video may still return a truthful
success: falserow. - Age-restricted, members-only, private, deleted, live, and upcoming videos are metadata-only; they cannot be transcribed without a signed-in session.
- Translation uses YouTube's own translation targets. If YouTube does not offer the requested language, the actor returns the original transcript with
language_matched: falserather than inventing a translation. When YouTube login-walls the translation page for an automated connection, the same fallback applies. - AI transcription downloads the audio; when the connection is blocked, the actor retries through a residential path and still reports a truthful
whisper_failedif the block persists. - Channel and playlist expansion reads YouTube's public listings and honours
maxVideosPerChannel/maxVideosPerPlaylist; private, blocked or empty listings return fewer videos (or none) with a status note. - Chapters, heatmaps, and comment counts are not exposed for every video. They are omitted when YouTube does not provide them.
- Subscriber and comment counts are display strings;
subscriberCountis an approximation andcommentCountTextis not an exact integer. - AI transcription is not available for live or upcoming broadcasts, and its accuracy depends on audio quality, music, and the selected model.
- Setting
maxWhisperMinutesto0disables AI explicitly; leaving the field unset keeps the legacy no-length-limit behavior.
Python quickstart
Use a schema-derived input and the Python standard library to start a run. An Apify account and token are required for execution.
Source build mm7zKNeWAnPZWiEHh. Documentation is regenerated from the default published build; private drafts are not included.