YouTube Transcript Scraper avatar

YouTube Transcript Scraper

Pricing

from $1.60 / 1,000 result items

Go to Apify Store
YouTube Transcript Scraper

YouTube Transcript Scraper

YouTube transcript scraper with no API key and no login. Get the full transcript, subtitles and timed caption segments for any video, channel or search, with human captions preferred over auto-generated ones. Monitor mode returns transcripts of new uploads on a channel.

Pricing

from $1.60 / 1,000 result items

Rating

0.0

(0)

Developer

Viktor Dubnytskiy

Viktor Dubnytskiy

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

13 hours ago

Last modified

Categories

Share

Get the subtitle text of YouTube videos as one flat row per video — the full transcript, the caption type (human-written or auto-generated) and the timed segments behind it. Feed it single videos, whole channels or a keyword search. No API key, no login, no video downloads.

Try it: the prefilled example returns 2 rows in about 10 seconds and costs about $0.004. Results cost $2 per 1,000.

What you get

Real rows from the example dataset (transcript text truncated here):

videosourcecaptionswords / segments
Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)videoUrlsen, human-written487 / 61 (213s)
Apify Agent Skills Makes It Easy To Scrape Websites!searches: "apify tutorial"en, auto-generated2588 / 359 (863s)
How to scrape anything with Apify and Make #aiautomation #nocodesearches: "apify tutorial"en, auto-generated111 / 17 (40s)

segments on the first row: [{"start": 1.36, "duration": 1.68, "text": "[♪♪♪]"}, …]; availableLanguages ["en", "de-DE", "ja", "pt-BR", "es-419"].

Full row: id / videoId, url, title, channelId, channelName, durationSec, language, languageName, isAutoGenerated, availableLanguages, segments (start, duration, text — seconds), text (all segments joined), wordCount, segmentCount, source (url / channel / search), query, scrapedAt.

Use cases

  • Monitor a channel's new uploads, weekly — put a competitor's or your own channel handle into monitor mode; each scheduled run returns transcripts only for videos published since the last check, ready for a newsletter or content calendar without re-pulling the whole channel.
  • Scheduled research or SEO feed on a keyword — run a search keyword on a weekly schedule in monitor mode to catch new videos ranking for that term as they appear, instead of re-scraping the same result page from scratch each time.
  • One-off transcript pull for a single video — grab the transcript and timed segments for one video right now, no schedule needed.

Try it in 10 seconds

One-off — hit Start/Try it, the input already works: two example videos preloaded in videoUrls, languages: ["en"], maxItems: 20, nothing required. Swap in your own URLs, a channels handle or a searches keyword and run again.

Monitor mode — save the input as a Task, then set:

{
"mode": "monitor",
"monitorStateId": "nasa-channel-watch",
"channels": ["@NASA"],
"webhookUrl": "https://your-endpoint.example.com/hook",
"telegramBotToken": "",
"telegramChatId": ""
}

and put it on a schedule (Apify → Schedules → cron 0 8 * * 1 for weekly). Each monitor run charges one monitor-check event ($0.006) and returns only transcripts that are new or changed since the previous run, each billed as one change event ($0.002) — a run with nothing new charges only the check.

How it works

  1. Video URLs / channels / searches are resolved into a list of video ids.
  2. For each video the caption track list is fetched and one track is chosen by your languages order, human-written before auto-generated (preferManual), with fallbackAnyLanguage as the last resort.
  3. The chosen track is downloaded as timed text and split into segments; text is those segments joined.
  4. YouTube shows a "sign in to confirm you're not a bot" wall to some exits, so the actor starts without a proxy and escalates one rung at a time (tier: auto).

Input

FieldMeaningDefault
videoUrlsWatch URLs, youtu.be / /shorts/ links, or bare 11-char idstwo example videos
channels@handle, channel URL or UC… id — latest videos are transcribedempty
searchesKeywords; the videos of the first result page are transcribedempty
languagesPreference order of caption languages, e.g. ["en","de"]["en"]
preferManualHuman-written track before the auto-generated onetrue
includeAutoGeneratedAllow YouTube's speech-recognition tracktrue
fallbackAnyLanguageTake any track when none of your languages existsfalse
maxVideosPerChannelLatest videos taken from each channel50
includeShortsList the Shorts tab instead of Videosfalse
tierProxy rung: auto, none, datacenter, residentialauto
maxItemsStop after this many transcripts20
modescrape or monitor (only new/changed since last run)scrape
monitorStateId, webhookUrl, telegramBotToken, telegramChatIdMonitor-mode state key and alert targetsempty

Pricing

EventPrice
result$0.002 per transcript ($2 per 1,000)
monitor-check$0.006 per monitor run
change$0.002 per new/changed transcript

Videos without a usable caption track are not pushed and not charged. They are counted in the ADAPTER_STATS record of the run's key-value store (noCaptions, unplayable, loginWalls, listingWalls, escalations, tierUsed), next to the standard RUN_SUMMARY record — so an empty run tells you whether the videos simply had no captions or whether YouTube refused the requests.

Why this actor

  • No API key, no login, no cookies — nothing to register and nothing to keep alive.
  • Timed segments come with every row, not just a wall of text, so you can cite or seek back into the video.
  • Human-written captions before auto-generated, isAutoGenerated tells you which kind you got — most competitors don't distinguish the two in the output.
  • A video with no usable captions is never pushed and never charged, so a batch of mixed videos costs only what it produced.
  • The run tells you why it was empty: ADAPTER_STATS separates "no captions" from "YouTube wall" from "video unplayable".
  • Monitor mode watches a channel or a search keyword on a schedule and returns only what's new, so a weekly check costs one monitor-check plus the transcripts that actually changed — not a full re-pull.
  • Starts with no proxy and escalates only when YouTube actually walls the exit, so most runs carry no proxy cost.

Limits

  • Auto-generated tracks are speech recognition: no punctuation to speak of, occasional wrong words, and word timings grouped into short lines. isAutoGenerated tells you which kind you got.
  • No machine translation: you get the tracks the video actually publishes, never a translated one.
  • Videos with captions disabled, private, removed or age-restricted videos return nothing (and cost nothing).
  • YouTube shows a "sign in to confirm you're not a bot" wall to some exit IPs. The actor starts without a proxy and escalates to datacenter and then residential proxy when it sees the wall; residential traffic is billed by Apify on top of the per-result price.
  • Member-only and unlisted videos are not supported.

FAQ

Does it need a YouTube API key or a login? No. There is no key field and no cookie field. Captions are read from the public player payload.

What happens to videos that have no subtitles? They are skipped: no row, no charge. The count lands in noCaptions inside the ADAPTER_STATS record of the run's key-value store.

Can I get a transcript in a language the video does not publish? No. The actor never machine-translates. Ask for your languages in languages, and set fallbackAnyLanguage to true if you would rather have the video's own language than nothing.

How do I get alerted only when a channel posts something new? Save the input as a Task with channels set, mode: "monitor" and a monitorStateId, put it on a weekly schedule, and add a webhookUrl or Telegram target — see "Try it in 10 seconds" above.

Changelog

  • 0.1: initial release — transcripts from video URLs, channels and search; language preference, manual/auto track choice, timed segments.

If this actor saved you time, a short review on its Store page genuinely helps other people find it. Found a bug or need a field that is missing? Open a ticket on the Issues tab.