YouTube Transcript API
Pricing
from $1.76 / 1,000 transcripts
YouTube Transcript API
Get YouTube transcripts in supplied languages from videos, Shorts, channels and playlists. Export segments, plain text and video metadata.
Pricing
from $1.76 / 1,000 transcripts
Rating
0.0
(0)
Developer
Eli J
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 hours ago
Last modified
Categories
Share
Extract supplied YouTube captions from video IDs, video URLs, Shorts, channels and playlists. Get one transcript per video with language, manual/auto kind, timestamped segments, plain text and video metadata.
Choose caption languages in order, prefer manual captions within each requested language, or exclude auto-generated captions. Failures are saved separately in the run's ERRORS record. Attempts that fail availability or access checks do not produce transcript rows or transcript-row charges.
Quick start
{"sources": ["https://www.youtube.com/watch?v=iG9CE55wbtY","https://www.youtube.com/watch?v=qp0HIF3SfI4"],"preferredLanguages": ["en", "fr"],"includeAutoGenerated": true,"includeSegments": true,"includePlainText": true}
For a channel, use https://www.youtube.com/@TED or a /channel/UC… URL. For a playlist, use https://www.youtube.com/playlist?list=PL8dPuuaLjXtNlUrzyH5r6jN9ulIgZBpdo. Mix video, channel and playlist sources in one run. Repeated video IDs produce at most one transcript per run.
Input
| Field | Type | Default | What it does |
|---|---|---|---|
sources | array | none (form prefill only) | Video IDs or HTTPS YouTube sources. Omitted, null or empty sources mean no source work. Watch, youtu.be, Shorts, live and embed video URLs are accepted. Channels accept handles or channel IDs; playlists accept a list ID in their URL. |
maxVideosPerSource | integer | 10 | Maximum distinct video IDs inspected per channel/playlist, 0–200. Zero means no source work. Failed, date-filtered and already-seen-in-run videos consume the per-source bound. Single-video sources inspect one. |
preferredLanguages | array | [] | Exact supplied language codes in fallback order, matched without case sensitivity. Manual before auto within the matching language. If no preference matches, use the unique source default when eligible. If that default exists but is ineligible, use the first eligible track. If no unique source default exists, report CAPTION_SELECTION. Empty follows the same default selection. |
includeAutoGenerated | boolean | true | Allow auto-generated captions. False excludes them. |
includeSegments | boolean | true | Include segments with times in seconds. |
includePlainText | boolean | true | Include paragraph text joined with newlines. |
startDate | string | "" | Inclusive UTC publication date YYYY-MM-DD or timezone-bearing ISO timestamp. Optional. |
endDate | string | "" | Inclusive UTC publication date (whole day) or timezone-bearing ISO timestamp. Optional; cannot precede startDate. |
When no preference matches and YouTube supplies no single default track, the
video goes to ERRORS as CAPTION_SELECTION; name an available language in
preferredLanguages to select it. Date-only publication values retain that
precision and compare as midnight UTC against timestamp filters. A supplied
timestamp without a timezone is refused as SOURCE_SCHEMA.
Omitted or null optional settings use the defaults above; explicit false, zero and empty arrays are preserved. Date filters apply within the per-source bound, so a source may yield fewer transcripts than the bound. A missing publication date becomes an error when a date filter needs it. An input of {} exits successfully with guidance and an empty dataset. Both text output toggles may be false; the Actor still fetches and validates a nonempty transcript before emitting its metadata row.
Output
One dataset item is one video with a nonempty supplied caption transcript. The following is an illustrative field-shape example, with sample values rather than a claimed live result:
{"videoId": "iG9CE55wbtY","url": "https://www.youtube.com/watch?v=iG9CE55wbtY","title": "Example video title","channelName": "Example channel","channelId": "UCAuUUnT6oDeKwE6v1NGQxug","languageCode": "en","kind": "manual","availableCaptionLanguages": ["en", "fr"],"segments": [{"start": 0.4, "duration": 1.2, "end": 1.6, "text": "Example caption."}],"plainText": "Example caption.","description": "Example video description","durationSeconds": 123,"viewCount": 876,"likeCount": 92,"publishedAt": "2007-01-07T05:00:34Z","publishedTimestamp": 1168146034,"thumbnail": "https://i.ytimg.com/vi/iG9CE55wbtY/hqdefault.jpg","channelUsername": "TED","channelThumbnail": null,"subscriberCount": 27900000,"subscriberCountPrecision": "rounded","subscriberCountText": "27.9M subscribers","commentCount": 13034,"commentCountText": "13K","availableCountries": ["US", "CA"],"geoRestriction": {"allowedCountries": ["US", "CA"]},"scrapedAt": "2026-10-06T17:00:00Z"}
start and duration are seconds converted from supplied caption milliseconds. end is start plus duration; absent duration makes both duration and end null. Source words, text-node order and line breaks are preserved. Nonempty paragraphs are joined with newlines for plainText; segments may overlap as they do in YouTube's captions. kind is manual or auto-generated. The language inventory lists supplied caption codes, including auto tracks even when they are excluded from selection. No machine translation is requested.
scrapedAt is the UTC read time. publishedAt is the supplied publication time normalized to UTC; a date-only source remains YYYY-MM-DD. Duration is seconds; views and likes are counts. Metadata absent from the public responses is null. The availability player response decides video availability. The metadata player can report that its own playback client is unavailable while still supplying metadata; if it omits that metadata, likeCount, publishedAt, publishedTimestamp, availableCountries and geoRestriction are null. Date filters then report PUBLICATION_UNKNOWN.
subscriberCount expands a displayed number such as 27.9M to 27900000. subscriberCountPrecision is rounded for compact displays, exact for an unabridged integer, and null when absent. This expansion does not recover the exact subscriber total. commentCount uses the unabridged public comment-header count when supplied, otherwise an unabridged display; compact displays remain text and do not become exact counts.
publishedTimestamp is Unix seconds for a timezone-bearing publication time, and null for a date-only or absent value. geoRestriction.allowedCountries and availableCountries carry the supplied country-code allowlist. Missing lists are null; this is not a test of playback in every country. segments and plainText are omitted when their toggles are false.
Errors and reliability
Open the run's key-value store record ERRORS for reasons, source URLs and video IDs when known. Codes distinguish INVALID_INPUT, INVALID_SOURCE, NO_CAPTIONS, AUTO_CAPTIONS_EXCLUDED, EMPTY_CAPTIONS, CAPTION_SCHEMA, CAPTION_SELECTION, PRIVATE, REMOVED, AGE_RESTRICTED, LOGIN_REQUIRED, UNAVAILABLE, BOT_WALL, RATE_LIMITED, ACCESS_DENIED, SOURCE_5XX, HTTP_ERROR, TRANSPORT, SOURCE_SCHEMA, IDENTITY_MISMATCH, DISCOVERY_SCHEMA, SOURCE_REJECTED, SOURCE_UNAVAILABLE, REPEATED_CONTINUATION, DISCOVERY_STALLED, BROWSER_BLOCK, BROWSER_FAILED, PUBLICATION_UNKNOWN, PROXY_SETUP and DATASET_WRITE. Invalid source entries are identified by their zero-based input index.
The primary path uses public JSON responses without downloading each video's watch page. The five video request classes (bootstrap, availability player, metadata player, comment header and captions) use US Apify residential sessions. Field selection keeps these JSON responses small. Channel/playlist discovery starts without a proxy; a measured bot wall, HTTP 429/403/5xx or transport failure moves only the affected request class to residential.
There are up to three browserless attempts with fresh sessions between attempts, then an isolated headless Playwright browser fallback by default. No account login or account cookies are used. Two videos can be fetched at once on the browserless path; each worker spaces request starts by at least 250 milliseconds. After date filtering, browserless caption and comment-header requests can overlap.
Browser fallback work runs one video at a time, closes each browser session and allows one fresh-session retry for classified transient failures. Its 45-second item budget includes queue time. Use at least 512 MB memory: forced browser work stalled at 256 MB in the retained platform checks. Discovery remains sequential. Permanent availability, identity and caption outcomes are reported directly. Valid empty sources and date-filtered results exit successfully; a run in which every attempt fails ends as failed. Partial success retains successful rows and the remaining error reasons. Once the run reaches the customer's maximum charge, the Actor starts no further source or video requests.
Channels expand their public /videos tab in source order. Separate channel Shorts and live-stream tabs are not expanded; provide their video URLs or a playlist explicitly. Playlists expand their supplied video items and continuations in source order. Private channels/playlists, legacy /user/ and /c/ channel URLs, search results, comments, audiovisual downloads, translation and captions requiring sign-in are outside coverage. Caption text comes from YouTube; accuracy and audiovisual completeness are not independently established.
A page alert is treated as SOURCE_UNAVAILABLE, including an informational
alert if YouTube supplies one. The per-source bound counts distinct video IDs. Two consecutive pages that add no new IDs while still offering a continuation stop that source with DISCOVERY_STALLED, even if their tokens differ. A final page without a continuation ends the source normally. Use individual video URLs when a source has this behavior.
Speed
In the timing sample, single-video runs finished in about 5 seconds without retries or browser fallback. About 1 to 1.5 seconds was Python and SDK start-up. Much of the remaining time was spent on requests to YouTube through residential proxies. Tested direct video requests from Apify's servers were blocked. In testing, pulling the container image took about 15 seconds. A run with an image pull and slow responses over residential proxies lasted past a minute. Larger batches share the start-up time across videos.
Pricing
Each delivered transcript is one billable dataset-item event. Errors and filtered videos do not incur transcript-row charges. An Actor Start charge may also apply, including to empty runs. Check the Actor page for the current event prices.
Python and JavaScript examples
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("danthedataman/youtube-transcript-language-api").call(run_input={"sources": ["qp0HIF3SfI4"], "preferredLanguages": ["en", "fr"]})for transcript in client.dataset(run["defaultDatasetId"]).iterate_items():print(transcript["plainText"])
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });const run = await client.actor('danthedataman/youtube-transcript-language-api').call({sources: ['qp0HIF3SfI4'], preferredLanguages: ['en', 'fr']});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.map(item => item.plainText));
Apify datasets can also be exported as JSON, CSV or Excel. Keep language and kind with the text when building a multilingual search index.
Frequently asked questions
Does this transcribe speech?
It reads captions supplied by YouTube. Videos without eligible captions produce an ERRORS entry; there is no speech-to-text or translation.
Can I select a language?
Set preferredLanguages in order. The row states the selected language and whether its captions are manual or auto-generated.
Why are some counts null?
Counts and geography depend on the public responses. Rounded subscriber values are labeled; exact comment headers are not supplied for every video.
Support
For a reproducible issue, open the Actor's Issues tab with the public video URL, input settings, run ID and ERRORS code. Do not include API tokens or account cookies.