YouTube Transcript Scraper
Pricing
from $4.00 / 1,000 results
YouTube Transcript Scraper
Extracts full transcripts and metadata from YouTube videos. Supports single videos, channels, and playlists — returns timestamped segments, plain text, SRT, or VTT with video title, channel name, duration, and language info. No API key or proxy needed.
Pricing
from $4.00 / 1,000 results
Rating
0.0
(0)
Developer
Meherab Hossain
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
An Apify Actor that extracts transcripts (captions/subtitles) from YouTube videos, channels, and playlists. It tries the lightweight YouTube Innertube/timedtext API first (HTTP-only, no browser), and falls back to Playwright headless browser when the API path fails.
Pricing: $0.01 per successfully extracted transcript (Pay-Per-Event).
Features
- Video, channel, and playlist support — paste any YouTube URL
- Timed segments — each transcript comes with start time, duration, and text
- Multiple output formats — segments (default), plain text, SRT, VTT
- Language preferences — specify preferred languages in order
- Translation — fetch transcripts translated into another language via YouTube's
tlangparameter - Auto-generated captions — optionally include or exclude ASR captions
- Smart proxy strategy — starts without proxy, switches to residential proxy after 3 consecutive IP blocks
- Browser fallback — Playwright Chromium used when the HTTP API path fails
- PPE pricing — only charged on success, no charge for failures
Input
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
source | string | yes | — | YouTube video/channel/playlist URL or bare ID |
sourceType | enum | no | auto | Force source interpretation: auto, video, channel, playlist |
maxVideos | integer | no | 50 | Max videos for channels/playlists (0 = unlimited, capped at 500) |
languages | string[] | no | [] | Ordered language preference (e.g. ["en", "es"]) |
translateTo | string | no | "" | Translation target language code (e.g. "es") |
format | enum | no | segments | Output format: segments, plain, srt, vtt |
includeAutoGenerated | boolean | no | true | Include ASR captions |
useProxy | enum | no | auto | Proxy strategy: auto, always, never |
useBrowserFallback | boolean | no | true | Enable Playwright fallback |
Example input
{"source": "https://www.youtube.com/watch?v=dQw4w9WgXcQ","languages": ["en"],"format": "segments"}
Output
Each result is a JSON object with:
| Field | Type | Description |
|---|---|---|
videoId | string | 11-char YouTube video ID |
videoUrl | string | Full watch URL |
title | string | Video title |
channelName | string | Channel/uploader name |
channelId | string | Channel ID (UC...) |
publishedAt | string | ISO 8601 publish date |
durationSeconds | integer | Video duration in seconds |
language | string | Language code of the fetched caption track |
isAutoGenerated | boolean | True if ASR captions |
isTranslated | boolean | True if a translation was fetched |
transcript | string | Full transcript text (for plain/srt/vtt formats; empty for segments) |
segments | array | Timed segments: {start, duration, text} (for segments format) |
extractionMethod | string | innertube_api, playwright, or failed |
error | string | Error message if extraction failed |
Example output
{"videoId": "dQw4w9WgXcQ","videoUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ","title": "Rick Astley - Never Gonna Give You Up (Official Video)","channelName": "Rick Astley","language": "en","isAutoGenerated": false,"isTranslated": false,"transcript": "","segments": [{"start": 0.0, "duration": 4.5, "text": "We're no strangers to love"},{"start": 4.5, "duration": 3.2, "text": "You know the rules and so do I"}],"extractionMethod": "innertube_api","error": ""}
Architecture
Actor.main()│├─ 1. Parse & validate input├─ 2. Resolve source → list of video IDs│ ├─ video URL → [1 video ID]│ ├─ channel URL → scrape /videos → N video IDs│ └─ playlist URL → scrape playlist → N video IDs├─ 3. For each video ID:│ ├─ TRY: Innertube API (HTTP-only)│ │ ├─ Fetch watch page HTML│ │ ├─ Extract ytInitialPlayerResponse│ │ ├─ Parse captionTracks│ │ ├─ Select best track (language pref)│ │ └─ GET baseUrl → parse JSON3 → segments│ ├─ IF API FAILS & browser fallback enabled:│ │ └─ TRY: Playwright headless browser│ └─ IF BOTH FAIL: output with extractionMethod=failed├─ 4. Push results to dataset└─ 5. Charge $0.01 per successful transcript (PPE)
Proxy Strategy
useProxy | Behavior |
|---|---|
auto (default) | Start with direct requests. If 3 consecutive IP-block errors (403/429), switch to Apify residential proxy. |
always | Use Apify residential proxy from the start. |
never | Never use proxy. If IP is blocked, the video fails (browser fallback still tried without proxy). |
Local Development
Install dependencies
pip install -r requirements.txtplaywright install --with-deps chromium
Run locally
# Single videopython -m src.main dQw4w9WgXcQ# With JSON inputecho '{"source": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "format": "plain"}' | python -m src.main# Run testspytest tests/ -v
Building for Apify
$apify push
Cost Estimation
| Scenario | Videos | Success rate | Cost |
|---|---|---|---|
| Single video | 1 | 95% | ~$0.01 |
| Channel (50 videos) | 50 | 80% | ~$0.40 |
| Playlist (100 videos) | 100 | 85% | ~$0.85 |
Tech Stack
- Language: Python 3.12+
- SDK: Apify SDK for Python (v2.x)
- HTTP client: httpx
- Browser: Playwright (Chromium) — fallback only
- Base image:
apify/actor-python:3.12