YouTube Transcript Scraper - Full Text + Timestamps for LLMs avatar

YouTube Transcript Scraper - Full Text + Timestamps for LLMs

Pricing

$2.99 / 1,000 transcripts

Go to Apify Store
YouTube Transcript Scraper - Full Text + Timestamps for LLMs

YouTube Transcript Scraper - Full Text + Timestamps for LLMs

YouTube transcripts from video, channel or playlist links: full plain text ready for an LLM, timed segments, caption language, plus title, channel, publish date, duration, views and every caption language. No login, no cookies. Videos without captions or not public are marked, not charged.

Pricing

$2.99 / 1,000 transcripts

Rating

0.0

(0)

Developer

Lantern Lab

Lantern Lab

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

8 days ago

Last modified

Categories

Share

YouTube Transcript Scraper — Full Text + Timestamps, Ready for an LLM

A Lantern Lab Actor. Give it YouTube video links — or a channel or playlist link — and get each video's public captions back: the full plain text you can paste straight into an LLM, the timed segments (start, end, text) you can link to, the caption language and whether the track is human-written or auto-generated, plus the video's title, channel, publish date, duration, view count and every caption language it offers. No YouTube login, no cookies, no account of your own.

Price: USD 2.99 per 1,000 transcript rows. No run-start fee. Videos without captions, blocked videos, duplicates and the run summary are free — you pay for transcripts, not for attempts.

Input:

{
"videoUrls": [
"https://www.youtube.com/watch?v=LKrwhjOI8Nc",
"https://www.youtube.com/@3blue1brown"
],
"maxItems": 10,
"language": "en",
"includeSegments": true
}

Output — one row per video (recordType: "transcript"), plus one free RUN_SUMMARY row at the end. Sample from a real run, transcript shortened:

{
"recordType": "transcript",
"platform": "youtube",
"videoInput": "https://www.youtube.com/watch?v=LKrwhjOI8Nc",
"videoId": "LKrwhjOI8Nc",
"url": "https://www.youtube.com/watch?v=LKrwhjOI8Nc",
"title": "There's never been a better time to go into math",
"authorName": "3Blue1Brown",
"channelName": "3Blue1Brown",
"channelId": "UCYO_jab_esuFRV4b17AJtAw",
"channelUrl": "https://www.youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw",
"publishedAt": "2026-10-16T09:15:20-07:00",
"durationSec": 2444,
"viewCount": 2453196,
"language": "en",
"languageName": "English",
"isAutoGenerated": false,
"transcriptSource": "platform_caption",
"asrModel": null,
"text": "Well, let's talk about it.\nIt feels like the whole math world is on fire…",
"wordCount": 6271,
"segments": [
{ "start": 0, "end": 1.432, "text": "Well, let's talk about it." },
{ "start": 1.432, "end": 3.873, "text": "It feels like the whole math world is on fire" }
],
"segmentCount": 884,
"availableCaptionLanguages": [
{ "languageCode": "ar", "languageName": "Arabic", "isAutoGenerated": false },
{ "languageCode": "en", "languageName": "English", "isAutoGenerated": false },
{ "languageCode": "en", "languageName": "English (auto-generated)", "isAutoGenerated": true }
],
"partial": false,
"partialReason": null,
"statusText": null,
"egress": "residential",
"collectedAt": "2026-10-24T10:18:31.204Z"
}

Limits:

  • Public captions only. The caption tracks YouTube publishes on a public video page: human-written and auto-generated. No login, no cookies, no members-only, private, age-restricted or deleted videos — those get a row saying exactly that. No video or audio files and no comments.
  • A video with no captions says so. partialReason: "no_captions" is a different row from "blocked", and neither is ever reported as an empty transcript. See Partial is not empty.
  • This build reads platform captions; it does not transcribe audio. transcriptSource is always platform_caption and asrModel is always null. YouTube auto-generates captions for nearly every public video, so this covers almost everything.
  • Your limits stop collection and appear in the row: maxItems per channel or playlist, the maxUpstreamRequests request ceiling and the maximum charge per run (see Pricing).

What it does

  • Gives you text an LLM can read. text is the joined plain transcript with one caption line per line — no markup, no timestamps in the way — and wordCount tells you what it will cost you in tokens before you send it.
  • Keeps the timings. segments[] carries start, end and text in seconds, so you can quote a passage and link to the second it is spoken at. Turn includeSegments off and you get the text and the word count only, which keeps the dataset small.
  • Takes a channel or a playlist, not just a video. A youtube.com/@handle or /channel/UC… link collects that channel's most recent maxItems uploads; a playlist?list=… link collects the playlist in order. Every row still carries the entry it came from in videoInput.
  • Picks the caption track the way a human would. With no language, it takes the track the video itself defaults to — the language it is actually in, which is not the same as the first entry in YouTube's own list (that list is sorted by language name, so an English video with community translations starts with Arabic) — and prefers a human-written track over the auto-generated one. With language, only that language is accepted — a regional variant matches its base language (en accepts en-GB) — and a video that has captions but not in that language is reported with availableCaptionLanguages rather than silently given a different language.
  • Keeps the provenance separate. The source ID (videoId), the platform's own publish time (publishedAt, exactly as YouTube reports it) and our collection time (collectedAt) are three different fields.
  • Deduplicates the run. A video that appears twice — directly and through a channel, or twice in the list — is collected and charged once; the repeat gets a free row saying so.
  • Caps itself. maxUpstreamRequests is a hard ceiling on requests to YouTube for the whole run, derived from your input when you leave it empty, so a run is never unbounded.
  • Charges transcript rows only. Videos without captions, blocked videos, unavailable videos, duplicates, unreadable input lines and the run summary are all free.

What it does not do

  • No speech-to-text: it returns the captions YouTube publishes, not a transcription of the audio.
  • No video, audio or thumbnail downloads, and no comments or channel statistics.
  • No login and no cookies, so nothing behind a sign-in: members-only, private, age-restricted and deleted videos are reported, not collected.
  • No search: you give it videos, channels or playlists, not keywords.
  • No translation: language picks one of the tracks YouTube already publishes for that video.

Input

FieldTypeDefaultWhat it does
videoUrlsstring[]requiredOne video, channel or playlist per line. Videos: watch?v=…, youtu.be/…, /shorts/…, /embed/…, /live/… or a bare 11-character ID. Channels: /@handle, /channel/UC…, /c/…, /user/…. Playlists: ?list=…. A link that carries both a video and a playlist is treated as the video.
maxItemsinteger10How many of a channel's or playlist's most recent videos to take, per channel or playlist line. Maximum 500. Ignored for single videos.
languagestringemptyCaption language to return, e.g. en, zh-Hans, ru. Empty takes each video's own default track.
includeSegmentsbooleantrueInclude segments[] with per-line start, end and text.
maxUpstreamRequestsintegerderivedHard ceiling on requests to YouTube for the whole run.
proxyConfigurationobjectApify ProxyProxy for the caption downloads and channel pages. The caption-list call always uses a residential IP, because YouTube answers datacenter IPs with a bot check.

Output

One row per video, plus a final RUN_SUMMARY row (also stored under the RUN_SUMMARY key).

FieldWhat it is
platformAlways youtube.
videoId, urlThe source ID YouTube uses, and the canonical watch URL.
titleThe video's public title.
authorName, channelName, channelId, channelUrlThe channel's public display name (twice, under the shared and the YouTube field name) and its ID.
publishedAtThe platform's own publish time, as YouTube reports it.
durationSec, viewCountVideo length in seconds, and the public view count.
language, languageName, isAutoGeneratedThe caption track that was returned.
transcriptSourceplatform_caption for every row this build returns.
asrModelAlways null in this build; set only when a transcript comes from speech recognition.
text, wordCountThe joined plain transcript, and its word count.
segments[]{ start, end, text } in seconds, when includeSegments is on.
segmentCountNumber of caption lines, even when segments[] is left out.
availableCaptionLanguages[]Every caption track the video offers, so you can re-run for another language.
partial, partialReason, statusTextWhether this row is incomplete, the machine-readable reason, and a sentence explaining it.
egressWhich egress produced the caption list.
collectedAtOur collection time, distinct from publishedAt.

Partial is not empty

A row is only a transcript when it carries one. Everything else is partial: true with a reason, so "no captions" is never confused with "we were refused":

partialReasonWhat happenedCharged
no_captionsThe video is public and playable but publishes no caption track.No
language_not_availableIt has captions, but not in the language you asked for. See availableCaptionLanguages.No
blockedYouTube refused the request with its bot check, twice, from two different IPs. Not a video without captions.No
unavailableDeleted, private, members-only or age-restricted: not publicly playable.No
empty_transcriptA caption track was listed but came back empty.No
invalid_inputThe line is not a YouTube video, channel or playlist link.No
listing_failed / listing_emptyA channel or playlist page could not be read, or listed no video.No
duplicate_inputThe video already appeared in this run; it was collected and charged once.No
upstream_request_capmaxUpstreamRequests was reached before this video.No
charge_limit_reachedThe maximum charge you set for the run was reached before this video.No
upstream_errorA request for this video failed.No

RUN_SUMMARY totals the run: rows written and charged, transcripts collected, partialBy counts per reason, requests sent per endpoint and per egress, bytes per egress, what each channel or playlist expanded into, and why collection stopped if it did.

Limits and boundaries

  • Public content only: the captions and metadata a public YouTube video page carries. No login, no cookies, no account of anyone's.
  • Personal data is kept to the minimum: the channel's public display name and ID. No viewer, commenter or uploader personal details.
  • Collection is honest about what it did not get. An incomplete run is marked partial with the reason; it is never reported as zero results.

Pricing

Pay per event: USD 2.99 per 1,000 result events, where one event is one row that carries a transcript. No run-start fee, and no charge for rows that carry no transcript — no_captions, blocked, unavailable, duplicate_input, invalid_input, the cap and charge-limit rows, and the run summary are all free.

Set a maximum charge per run in the Apify run options and the Actor stops before exceeding it: the videos it did not reach are written with partialReason: "charge_limit_reached" so you know exactly where it stopped.