YouTube Transcript Scraper — RAG-Ready avatar

YouTube Transcript Scraper — RAG-Ready

Pricing

from $5.00 / 1,000 transcripts

Go to Apify Store
YouTube Transcript Scraper — RAG-Ready

YouTube Transcript Scraper — RAG-Ready

Turn YouTube into RAG-ready transcripts: chapter-grouped, chunk-ready paragraphs for LLM and search pipelines. Re-runs skip already-delivered videos to keep a corpus fresh, and failed videos are never billed. Accepts mixed video, playlist, and channel URLs. Unofficial; public data only.

Pricing

from $5.00 / 1,000 transcripts

Rating

0.0

(0)

Developer

Blackcube Agency AB

Blackcube Agency AB

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

36 minutes ago

Last modified

Share

More from this account: Website Contact & Email Suite · Career Site & ATS Jobs Suite · Google News Suite · Keyword Research Suite · Shopify Store Intelligence Suite · eBay Data Suite · Amazon Reviews Suite · Reddit · Meta Ad Library · Vinted

RAG-ready YouTube transcripts — chapter-grouped, chunk-ready paragraphs.

Point it at YouTube videos, playlists, or channels and get back structured JSON that drops straight into a retrieval or LLM pipeline: caption text merged into clean paragraphs, grouped under the video's own chapters, with millisecond timing on every segment.

Unofficial — not affiliated with, endorsed by, or connected to YouTube or Google. This actor works only with data that YouTube already serves publicly. No YouTube logo or trademark is used in its name or branding.


Why this one

1. Chapter-grouped, LLM-ready paragraphs

Raw caption tracks are a wall of 2–5 word cues with no sentence or topic boundaries — useless for chunking. This actor merges those cues into readable paragraphs (breaking on pauses and sentence endings, targeting ~500–1,500 characters) and groups them under the video's chapters, so each chunk already carries its topic and its timestamp.

// one chapter from a real run (abridged)
{
"title": "Introduction",
"startMs": 0,
"endMs": 112480,
"paragraphs": [
{
"startMs": 0,
"endMs": 34640,
"text": "In this course, I'm going to teach you everything you need to know to get started programming in Python. Now, Python is one of the most popular programming languages out there…"
},
{
"startMs": 81200,
"endMs": 112480,
"text": "We're going to talk about all the core concepts in Python. We're going to look at everything you need to know to start programming in Python…"
}
]
}

Videos without chapters still come back grouped — as a single group with a null title — so downstream code has one shape to handle. See .actor/sample-output.json for two complete records from a real run.

2. Freshness re-runs skip what you already have

Turn on Only new videos and give the run a state label. Every delivered transcript is remembered under that label, so a scheduled re-run over the same channel or playlist fetches — and bills — only the new uploads. Keep a corpus current without re-paying for videos you already have.

3. Failures are free

Billing is per delivered transcript — one charge for each caption track this actor actually hands you. Every failure mode — captions disabled, region-locked, members-only, a dead playlist entry, a bot-check block — is pushed as a documented error item at no charge. You pay only for transcripts you receive; errors are transparent and cost nothing.

Supported input scope: a single run accepts a mixed list of video, playlist, channel, and @handle URLs — each playlist or channel is expanded into its videos automatically, then de-duplicated across sources.


Input

FieldTypeDefaultWhat it does
urls (required)array of stringsMixed list of YouTube URLs: individual videos (watch?v=, youtu.be/, /shorts/, /embed/, /live/), playlists (list=), channels (/channel/UC…, /@handle, /c/…, /user/…), and channel tab URLs. Playlists and channels are expanded to their videos. A watch?v=…&list=… URL is treated as the single video.
languagesarray of strings(empty)Ordered language preference (BCP-47 tags or prefixes, e.g. en, pt-BR). First available match wins. Empty → the video's default caption track.
allLanguagesbooleanfalseReturn every caption track instead of the best match. ⚠️ This emits one dataset item per track, and each track is billed as one transcript. Ignores the languages list.
includeShortsbooleanfalseWhen expanding a channel, also include Shorts. Off = long-form uploads only.
maxVideosPerSourceinteger100Cap on videos taken from each playlist or channel URL (1–5000), applied per source. Direct video URLs are unaffected.
includeChaptersbooleantrueExtract chapter markers and the upload date. Turning it off saves one request per video but leaves uploadDate null (they share the same source call). Transcripts are still grouped — under one null-title chapter.
formatsarray(empty)Extra rendered formats to add to each item: text (plain text), srt, vtt. Structured JSON segments and paragraphs are always included.
onlyNewVideosbooleanfalseSkip videos already delivered by previous runs sharing the same state label. For scheduled re-runs that should pick up only new uploads.
stateLabelstringdefaultNames the persistent delivered-video memory used by Only new videos. Runs sharing a label share that memory.
proxyConfigurationobjectApify ProxyProxy settings for YouTube requests. YouTube blocks most cloud IPs, so a residential proxy is recommended for caption fetching; you may also supply your own proxy URLs.

Overlapping schedules: Only new videos state is read at run start and written per delivery (best-effort). Two runs sharing a state label that overlap in time may both deliver the same brand-new video. Schedule runs on the same label so they don't overlap.


Output

Every result is one JSON record in the run's dataset. A delivered transcript looks like this:

FieldTypeNotes
videoIdstringe.g. jNQXAC9IVRw.
urlstringCanonical watch URL.
title, channel, channelIdstringVideo and channel identity.
uploadDatestring | nullYouTube's own absolute date string (hl=en, e.g. "Jul 11, 2018"). null when includeChapters is off.
durationSecondsnumberVideo length.
languagestringLanguage tag of the delivered track.
matchedLanguageTagstringThe track's BCP-47 language tag. Under allLanguages, duplicate same-language tracks get a #2/#3 suffix to stay distinct; use language for the clean code.
isAutoGeneratedbooleantrue for ASR (auto) captions, false for a manual track.
availableLanguagesarrayEvery caption track on the video: { languageCode, name, autoGenerated }.
sourceUrlsarrayEvery input URL that produced this video (a video reached from two playlists lists both).
sourcePositionnumber | nullZero-based position within its expanded playlist/channel; null for direct video URLs.
segmentsarrayRaw caption cues in order: { startMs, durMs, text }.
chaptersarrayThe RAG wedge: { title, startMs, endMs, paragraphs: [{ startMs, endMs, text }] }. Always present; one null-title group when the video has no chapters.
plainTextstring | nullFull transcript as text. Present only when formats includes text.
srt, vttstring | nullSubtitle renderings. Present only when requested in formats.

A failed video is a record with errorReason set and the transcript fields empty. It carries errorReason, rawReason (the raw upstream detail, for debugging), the offending input or videoId, and sourceUrls.

Dataset views

The dataset ships two views in the Apify Console:

  • Transcripts — the transcript columns.
  • Errorsinput, videoId, errorReason, rawReason, sourceUrls.

Views project columns, they do not filter rows. Both delivered transcripts and error items appear in both views (with the other view's columns blank). To separate them in your own code, split on errorReason: it is null on a delivered transcript and set on a failure.

See .actor/sample-output.json for two full records from a real run (freeCodeCamp's Learn Python course and Me at the zoo).


Failure modes

Every failure is a free error item — you are never billed for one. The errorReason is a stable machine-readable label; rawReason carries YouTube's own (locale-sensitive) detail.

errorReasonMeaningBilled?
captionsDisabledThe video has no caption tracks at all (captions turned off by the uploader).No — free
noCaptionsCaption tracks exist, but none match the languages you requested.No — free
regionRestrictedThe video isn't available in the region the request came from.No — free
membersOnlyThe video is restricted to channel members.No — free
ageRestrictedThe video is age-gated and needs a signed-in account.No — free
videoUnavailableThe video was removed, deleted, made private, or never existed (includes [Private video] / [Deleted video] playlist entries).No — free
notYetAvailableAn upcoming premiere or offline live stream — no transcript yet.No — free
invalidUrlThe input isn't a recognizable YouTube video, playlist, or channel URL.No — free
expansionFailedA playlist or channel URL couldn't be listed (its videos couldn't be enumerated).No — free
emptyTranscriptA track was found but holds only music/noise markers — no spoken text.No — free
potRequiredYouTube demanded a proof-of-origin token for this track; it can't be fetched on the current path.No — free
blockedThe request was bot-checked or returned empty and kept failing after retries on fresh IPs.No — free
unknownAn uncategorized failure — the raw upstream reason is captured in rawReason for debugging.No — free

Language support

  • BCP-47 prefix matching. A request for en matches en, en-US, and en-GB (but never eng); pt-BR matches only Brazilian Portuguese. Your languages list is tried in order — the first entry with any available match wins.
  • Manual beats auto. Within a matched language, a human-made caption track is preferred over an auto-generated (ASR) one, and an exact tag beats a prefix match.
  • See what's on offer. Every delivered item lists all real caption tracks in availableLanguages (manual + auto, never machine-translation targets), so you can widen your languages list or switch on allLanguages with full knowledge of what exists.

Unofficial project. Uses only publicly available YouTube data. Not affiliated with YouTube or Google.

Run it without configuring anythingGet the transcript of a YouTube video, a ready-made example you can start as-is or copy.

Use cases

  • Build a RAG corpus. Turn a channel, playlist or URL list into chunk-ready paragraphs with the source video and timestamp on every row — ready to embed.
  • Repurpose long video. Pull the spoken text of a talk or podcast and turn it into a post, a newsletter or a clip list without watching it.
  • Search what was said. Make a back catalogue greppable: find every mention of a product, a name or a claim across hundreds of videos.
  • Keep a corpus fresh. Schedule it and re-runs skip videos already delivered, so you pay for new material only.

Run it on a schedule

A one-off pull answers a question; a schedule answers it every day without you. Open Schedules in the Apify Console, point a cron at this Actor, and the dataset keeps filling on its own — no server, no cron box, no babysitting. Everything here is built to be re-run: you are billed per transcript delivered, so a scheduled run that finds nothing new costs nothing.

FAQ

Do I need a YouTube API key?

No. No key, no login, no OAuth and no YouTube quota to manage — you give it a URL and it returns text.

Can I export transcripts to CSV, JSON or Excel?

Yes. Every run writes a dataset you can export in one click from the Console, or pull straight from the API in JSON, CSV, XLSX or JSONL.

What happens to a video with no captions?

It comes back as a free row that says so, rather than failing the run. You are never charged for a video that returned no transcript.

Can I transcribe a whole channel or playlist at once?

Yes — pass the channel or playlist URL and it walks the uploads for you. There are dedicated Actors in this suite for both.


Something wrong, or a field you need that is missing? Open an issue on the Issues tab — it is read and it gets fixed. If this saved you time, a rating on the Store page helps the next person find it.