YouTube Transcript Scraper - video, channel and playlist
Pricing
from $3.00 / 1,000 transcripts
YouTube Transcript Scraper - video, channel and playlist
Get transcripts from YouTube videos, whole channels and playlists. Every video you ask for gets a row - with the transcript, or with the exact reason there is none. Rows without a transcript are never charged.
Pricing
from $3.00 / 1,000 transcripts
Rating
0.0
(0)
Developer
Marek Hartmann
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
YouTube Transcript Scraper
Get transcripts from YouTube videos, whole channels and playlists.
Every video you ask for gets a row. Either with the transcript, or with the exact reason there is none. Rows without a transcript are never charged.
Why another YouTube transcript scraper
Because of a failure mode we measured ourselves.
The YouTube watch page still lists a video's caption tracks, but the signed URL it hands out returns HTTP 200 with a zero-length body. An Actor that sees "captions exist", downloads them, and never checks the length will report success and save an empty dataset. You pay for the run and get nothing, with a green tick in the console.
This Actor checks the length. If the body is empty, the run fails loudly instead of charging you for nothing.
That failure mode is not hypothetical. Across the YouTube transcript Actors in the Store you can find reviews like "worked less than half the time", "did not give response to the video" and "this scraper did not scrape the channels I put in" sitting next to high success rates. We do not claim to know what any particular competitor does internally — we only know what the endpoint does, because we measured it, and what it costs you when nobody checks.
What you get per video
| Field | What it is |
|---|---|
transcript | The transcript, in the format you chose — or null |
errorCode / error | Why there is no transcript, per video |
language, isAutoGenerated | Which track was actually used |
availableLanguages | What the video does have, when your language is missing |
title, channelName, viewCount | Video metadata |
channelId / playlistId | Which channel or playlist the row came from |
segmentCount, wordCount, durationSeconds | Size of the transcript |
Input
Anything that looks like a YouTube link is accepted — including a bare video ID and a single video URL, which some competing Actors refuse outright:
https://www.youtube.com/watch?v=dQw4w9WgXcQhttps://youtu.be/jNQXAC9IVRwhttps://www.youtube.com/shorts/dQw4w9WgXcQdQw4w9WgXcQhttps://www.youtube.com/@YouTubehttps://www.youtube.com/playlist?list=PL...
Options: transcript language, whether to include auto-generated
subtitles, output format (plain, timestamps, srt), and a cap on how
many videos are taken per channel.
Output formats
- plain — one continuous block of text, ready for an LLM
- timestamps —
[00:01:23] line of text, one line per caption - srt — a valid subtitle file you can use as-is
What a failure means here
The run either gives you data, or tells you why it could not. There is no third option where you pay for silence.
errorCode in the row | What it means | Charged? |
|---|---|---|
NO_TRANSCRIPT | The video has no subtitles at all | no |
LANGUAGE_NOT_AVAILABLE | Not in your language — the row lists the ones that exist | no |
VIDEO_NOT_FOUND | The ID is well-formed but the video is gone | no |
VIDEO_PRIVATE | Private, or members-only | no |
AGE_RESTRICTED | Needs a signed-in account | no |
VIDEO_UNAVAILABLE_HERE | Blocked in the proxy's country — try another one | no |
NOT_YET_AVAILABLE | A premiere or a scheduled stream that has not aired | no |
VIDEO_UNAVAILABLE | Unplayable for a reason YouTube words in a way we don't recognise | no |
CHANNEL_NOT_FOUND | The channel or playlist does not exist | no |
BAD_TARGET | We could not read that input as a YouTube link | no |
BUDGET_REACHED | Your maxTotalChargeUsd ran out before this one | no |
LIST_TRUNCATED | YouTube stopped handing us the rest of a long list — the list is not complete | no |
CHARGE_UNCONFIRMED | The Apify platform answered a charge call in a shape we don't recognise, so we stopped. Your limit was not reached — don't raise it | no |
None of those fail the run — they are properties of the input, and you get a row saying so. These do fail the run, loudly, because they are our problem:
| Situation | What happens |
|---|---|
| YouTube blocks us as a bot | Run fails after retrying from other IPs |
| YouTube changes its response format | Run fails — we do not guess |
| A signed caption URL returns an empty body | Run fails — empty is not a transcript |
If a whole run comes back with nothing but "no subtitles" rows, the Actor asks a control question first — it fetches a video it knows has subtitles. If that one fails too, the run fails instead of telling you your videos have no subtitles.
A run that extracts nothing costs you the start price and nothing else, even if the dataset has 200 rows explaining why.
One honest caveat: transcripts are charged as they are delivered, not at the end. If a long run is cut short — by us being blocked, or by a format change — the transcripts you already received stay in the dataset and stay charged. The run is marked FAILED so you can see it did not finish, and you keep what you paid for. Re-running skips nothing you already have only if you pass the same input; there is no cross-run deduplication.
What this Actor does not do
Written down because you should know before you pay, not after.
- No cross-run deduplication. Re-running the same input downloads and charges again. Within one run the same video is only ever fetched and charged once, including after a migration.
- No translation. You get the caption tracks the video actually has. If your language is missing, the row tells you which ones exist.
- Channels are capped per target, not per run. Ten channels at 100 videos
each is a thousand transcripts — set
maxVideosPerChannelor yourmaxTotalChargeUsdaccordingly. requestsFromUrlis not supported. Paste the links in directly; arequestsFromUrlentry comes back as an explained input error, not silence.- Live streams in progress have no finished transcript, so they come back
as
NOT_YET_AVAILABLE. - A run cut short keeps what it delivered. Transcripts are charged as they land, so if we get blocked at video 400 of 500, the first 399 stay in the dataset and stay charged, and the run is marked FAILED so you can see it did not finish.
Pricing
Pay per event:
- 0.00005 USD per run start — charged once per GB of memory, so the intended 1 GB run start costs exactly this; a 4 GB run start costs 4×
- 3.00 USD per 1 000 transcripts — one event per transcript actually extracted. A row without a transcript is free.
To say it the way a reviewer of a competing Actor asked and never got answered: 1 000 results means 1 000 transcripts. Not 1 000 videos attempted, not 1 000 API calls.
Proxy
YouTube blocks datacentre IPs almost immediately, so the default here is a residential proxy — measured, not assumed: through the datacentre pool the very first request comes back as "Sign in to confirm you are not a bot".
If a run does get blocked mid-way, the Actor swaps to a new proxy session and retries rather than failing on the first refusal.
Run report
Every run writes a RUN_REPORT record into the key-value store: what was
requested, what each target returned, and how many rows were actually billed.
It is written as the run goes, not only at the end, so it exists even if a
long run is cut short. Each transcript row also carries transportClient —
which strategy actually answered for that video.
Each target in the report gets an outcome:
outcome | What it means |
|---|---|
OK | Every video that had a transcript returned one |
PARTIAL | Some transcripts came back, then your maxTotalChargeUsd stopped the rest |
BUDGET_REACHED | The budget stopped this target before any transcript came back |
CHARGE_UNCONFIRMED | The platform stopped confirming charges, so this target was not fetched — your limit was not reached |
DUPLICATE | Every video here was already downloaded earlier in this same run |
MIXED | Some were already downloaded earlier in this run, the rest have no transcript |
NO_TRANSCRIPTS | None of the videos has a transcript — and the canary proved we can still read |
If a run is migrated to another machine mid-way, it picks up where it left off and does not re-download or re-charge what it already delivered.
Built by Marek Hartmann. I also build custom Apify Actors to order — if you need a scraper for a source that is not in the Store yet, get in touch.