YouTube Transcript Fast
Pricing
$0.80 / 1,000 transcript scrapeds
YouTube Transcript Fast
Fast HTTP-only YouTube transcript extraction: watch page + timedtext JSON3, no Playwright.
Pricing
$0.80 / 1,000 transcript scrapeds
Rating
0.0
(0)
Developer
Mark
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
What it does
HTTP-only YouTube transcript extraction — no Playwright/browser. For each
video: fetches the watch page, pulls captions.playerCaptionsTracklistRenderer.captionTracks
out of the inline ytInitialPlayerResponse, picks a track (manual caption in
the requested language, else auto-generated in that language, else any manual
track, else any track), fetches that track with &fmt=json3, and assembles
the full transcript text plus timestamped segments.
Input
| Field | Type | Required | Description |
|---|---|---|---|
videoUrls | string[] | one of videoUrls/videoIds | Full watch/shorts/youtu.be URLs. |
videoIds | string[] | one of videoUrls/videoIds | Bare 11-char video IDs. |
language | string | no (default en) | Preferred caption language code. |
includeTimestamps | boolean | no (default true) | Include the per-segment segments array alongside the full transcript text. |
Output example
One row per video in the default dataset:
{"videoId": "dQw4w9WgXcQ","title": "Rick Astley - Never Gonna Give You Up","channel": "Rick Astley","duration": 213,"language": "en","isAutoCaption": false,"transcript": "We're no strangers to love ...","segments": [ { "start": 0.5, "dur": 2.1, "text": "We're no strangers to love" } ]}
A video with no caption tracks pushes:
{ "videoId": "...", "title": "...", "transcript": null, "reason": "no-captions" }
No charge event fires for that row.
Pricing
Pay-per-event. One transcript-scraped event fires per successfully pushed
transcript row, via Actor.charge({ eventName: 'transcript-scraped' }).
Configure in the Apify Console: $0.0008 per transcript-scraped event
(docs/CANDIDATES.md entry 2 — 12x under the 3.72-rated market leader's
$0.01/item). No-caption rows are never charged.
Known gap — BLOCKED from this Mac, not worked around
The watch-page fetch and ytInitialPlayerResponse extraction work (200 OK,
tracks parsed correctly, verified against dQw4w9WgXcQ and others). The
second call — fetching the caption track itself
(https://www.youtube.com/api/timedtext?...&fmt=json3) — consistently comes
back HTTP 200 with an empty body (content-length: 0,
server: video-timedtextfetch/undici, Python urllib, curl) and with/without
Referer/Origin/Accept-Language headers, both immediately following the
watch-page fetch in the same process and standalone. No 4xx/429 is returned —
YouTube silently zeroes the body instead. Per the build brief, this is
reported plainly rather than routed around with a proxy: smoke.sh did not
pass from this Mac. The code is written to the spec and is
npx tsc --noEmit clean; whether it passes depends on running it from an
Apify platform IP range (the CANDIDATES.md entry already budgets a datacenter
proxy fallback if YouTube rate-limits/blocks the Apify range) or a residential
egress, neither of which was tested here.
Limits
Free-plan compute only (policy/RULES.md rule 4). No proxy configured (rule
1 — target needs no residential proxy in the common case; see gap above for
the one endpoint that may need it). No personal data beyond public
channel/title/video metadata already documented in docs/CANDIDATES.md.