YouTube Transcripts
Give it YouTube video, Shorts, channel or playlist links (or plain video IDs) and it returns each transcript (subtitles, captions) as JSON: full text, timed segments, language, whether it was auto-generated, every caption language the video has, and the video's title, channel, length, publish date and views.
Sample output
One row as the API returns it. Long text is shortened here; names inside text read [name].
| Field | Value |
|---|---|
| rowType | transcript |
| platform | youtube |
| videoId | dQw4w9WgXcQ |
| url | https://www.youtube.com/watch?v=dQw4w9WgXcQ |
| title | Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster) |
| channelName | Rick Astley |
| channelId | UCuAXFkgsw1L7xaCfnd5JJOw |
| channelHandle | @RickAstleyYT |
| channelUrl | https://www.youtube.com/channel/UCuAXFkgsw1L7xaCfnd5JJOw |
| durationSeconds | 213 |
| publishDate | 2009-10-24T23:57:33-07:00 |
| viewCount | 1,829,055,386 |
Call it from code or from your agent
This is the request. Small runs answer in the same call; large ones return a run ID.
curl -X POST https://scrapers-api.arcadiumdata.io/v1/scrapers/youtube-transcripts/runs \
-H "Authorization: Bearer $ARCADIUM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": {
"urls": [
"https://www.youtube.com/watch?v=dQw4w9WgXcQ"
],
"captionType": "any",
"maxVideosPerSource": 10,
"subtitleFormat": "none"
}
}'What each row holds
Every row says what it is in rowType: transcript rows are charged, coverage and error rows are free.
The transcript 31 fields
| Field | Type | What it holds |
|---|---|---|
| platform | string | Always 'youtube'. |
| videoId | string | YouTube video id, 11 characters, e.g. dQw4w9WgXcQ. |
| url | string | Watch page link of the video (Shorts included). |
| title | string | Video title. |
| channelName | string | Name of the channel that published the video (the publisher, not a viewer). |
| channelId | string | Channel id, starts with UC, e.g. UCuAXFkgsw1L7xaCfnd5JJOw. |
| channelHandle | string | Channel handle with the @, e.g. @RickAstleyYT. Null if YouTube did not return it. |
| channelUrl | string | Link to the channel page built from channelId. |
| durationSeconds | number | Video length in seconds. |
| publishDate | string | Publish date and time as YouTube gives it, ISO 8601 with offset, e.g. 2009-10-24T23:57:33-07:00. |
| viewCount | number | Views at the time of the run. |
| likeCount | number | Likes at the time of the run; null when hidden. |
| category | string | YouTube category, e.g. Music, Education, News & Politics. |
| isLiveContent | boolean | True for live streams and recorded live streams. |
| keywords | array | Tags the creator set on the video (may be empty). |
| description | string | Video description, short (about 300 characters) or full per input; emails and phone numbers are removed. |
| language | string | Language code of the returned transcript, e.g. en, de-DE, pt-BR. |
| languageName | string | English name of that language, e.g. German (Germany). |
| isAutoGenerated | boolean | True when the transcript is YouTube's speech recognition (no punctuation, may misspell names); false when the creator uploaded it. |
| languageMatched | boolean | False when none of the requested languages existed and the original-language track was returned instead. |
| translationStatus | string | Values: 'not_requested', 'original' (the video has a native track in translateTo), 'translated' (YouTube's own machine translation), 'unavailable' (YouTube refused it; the original is returned). |
| translatedFrom | Source language code when translationStatus is 'translated', else null. | |
| availableLanguages | array | Every caption track of the video: code, name, isAutoGenerated. Use it to request another language. |
| transcript | string | The whole transcript as one text: caption lines joined with spaces. Emails and phone numbers are removed. |
| segmentCount | number | Number of caption lines. |
| wordCount | number | Words in transcript, for chunking and token estimates. |
| segments | array | Caption lines in order: start (seconds from the start), duration (seconds), text. Present when includeSegments is on. |
| srt | The captions as an SRT subtitle file, when subtitleFormat is srt. | |
| vtt | The captions as a WebVTT subtitle file, when subtitleFormat is vtt. | |
| source | The channel or playlist URL this video came from; null for videos given directly. | |
| scrapedAt | string | When the row was read, ISO 8601. |
Error rows, free 3 fields
| Field | Type | What it holds |
|---|---|---|
| input | Error rows: the URL or id as given. | |
| code | Error rows: not_found (private, removed, unknown channel), no_match (no captions, or none of the requested type), unavailable (age-restricted, members-only, upcoming, temporary error), blocked (rate limited, retry later), invalid_input. | |
| message | Error rows: what happened, in plain English. |
What it can't do
- It returns captions YouTube already has. It does not transcribe audio.
- It does not return comments or the names of commenters.
- Private and members-only videos are not read.
Channel names and URLs are the publisher labels YouTube shows publicly on every video.
What you send
Every field is optional. The example request above fills the ones shown here.
| Field | Type | What it does |
|---|---|---|
| urls | array | Example: https://www.youtube.com/watch?v=dQw4w9WgXcQ, https://youtu.be/dQw4w9WgXcQ, a Shorts URL, a bare video ID (dQw4w9WgXcQ), a channel (https://www.youtube.com/@kurzgesagt, add /shorts or /streams for those tabs) or a playlist URL. Channels and playlists give up to maxVideosPerSource videos each, channels newest first. |
| languages | array | ISO language codes in order of preference, e.g. ["en", "de"]; en also matches en-US and en-GB. The first one the video has is used. Empty or none available: the original spoken language (languageMatched is false when none matched). |
| captionType | string (one of 3) | Values: any (uploaded captions first, else auto-generated), manual (uploaded by the creator only), auto (YouTube speech recognition only). Videos without that type give a free error row. Default: any. |
| maxVideosPerSource | integer | Transcripts per channel or playlist URL, 1 to 5,000 (default 50). Videos without captions or outside the date range do not count. Direct video URLs are not limited by this. |
| subtitleFormat | string (one of 3) | Values: none, srt, vtt. srt or vtt adds the captions as a ready subtitle file in the srt or vtt field. Default: none. |
More options (7)
| Field | Type | What it does |
|---|---|---|
| translateTo | string | ISO language code, e.g. es. A native track in that language is used when the video has one (translationStatus original). Otherwise YouTube's own machine translation is asked for; YouTube currently refuses it for anonymous clients, so you get the original with translationStatus unavailable. |
| publishedAfter | string | Date as YYYY-MM-DD, e.g. 2026-01-01. Videos published earlier are skipped for free; on a channel the listing stops at the first older videos. |
| publishedBefore | string | Date as YYYY-MM-DD, e.g. 2026-06-30. Videos published later are skipped for free. |
| includeSegments | boolean | Adds segments: one entry per caption line with start and duration in seconds and its text. The joined transcript text is always included.Default true |
| description | string (one of 3) | Values: short (about 300 characters, default), full, none. Emails and phone numbers are removed.Default "short" |
| maxResults | integer | Stops the run after this many transcripts across all URLs, 1 to 1,000,000. A cost cap; leave empty for no limit. |
| includeErrorRows | boolean | Adds a free row (rowType error, with a code and message) for every video or URL that gave no transcript: no captions, private, age-restricted, not found. On by default.Default true |
Questions people ask before they top up
What does a run cost?
Each transcript costs $0.0015, which is $1.50 per 1,000. A run that delivers rows also pays a $0.001 start fee.
A run that returns rows costs at least $0.005, start fee included. Failed runs, empty runs and duplicate rows cost $0. You set the most a run may cost, and it stops there.
Do you ever return personal data?
Not about reviewers or users. Reviewer names, profile links, photos, emails and phone numbers are not collected. When a name appears inside a review or a reply, it is replaced with [name].
Job titles and company sizes stay where a site shows them, because they describe a role rather than a person. On YouTube, channel names and URLs are the publisher labels YouTube shows publicly.
How fresh is the data?
Each run reads the live site when you start it, so rows are as current as the site itself.
More from YouTube
Views, likes, duration, exact publish date, Shorts flag, tags
$1.25per 1,000 videos