Fast YouTube Transcript Scraper & MCP Connector
Pricing
from $0.10 / actor start
Fast YouTube Transcript Scraper & MCP Connector
Scrape any YouTube video transcript with timestamps in 13 languages. Auto-translate, export to JSON/CSV/Excel, or push to Notion, Slack & Jira.
Pricing
from $0.10 / actor start
Rating
0.0
(0)
Developer
Techforce Global
Maintained by CommunityActor stats
1
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
YouTube Transcript Scraper & Captions API Alternative β Timestamped Transcripts in 13 Languages, Delivered Anywhere
Extracts the full transcript of any public YouTube video as structured JSON β every segment with start time, duration, and text β in 13 languages, with automatic translation fallback. No Google API key, no OAuth, no video ownership required. Delivers straight into Notion, Slack, Jira, GitHub, Linear, Airtable, or any MCP-compatible AI agent pipeline.
Official YouTube Data API v3 vs. YouTube Transcript Scraper Actor
The official API's captions.download endpoint only works for videos you own β it is not a route to third-party transcripts at all:
| Feature / Capability | Official YouTube Data API v3 | YouTube Transcript Scraper Actor (Apify) |
|---|---|---|
| Download captions of videos you don't own | β captions.download requires OAuth as the video owner | β Any public video with captions |
| Authentication & setup | β Google Cloud project + OAuth consent flow | β Zero target-site credentials; only an Apify token |
| Auto-translation to another language | β Not provided | β YouTube auto-translation with graceful fallback |
| Bot-wall / IP blocking | N/A (quota-gated instead) | β Apify residential proxy wired in by default |
| Daily quota ceiling | β οΈ Default 10,000 quota units/day per project | β No per-day ceiling β pay per run |
| AI agent / MCP native | β Requires a custom tool wrapper | β Native MCP tool and pushes results into your own MCP connectors |
| Cost model | Free within quota, then quota-increase requests | Pay-per-run ($0.10 per Actor start) |
β οΈ Verify before publishing: the 10,000 units/day figure is Google's documented default project quota; re-confirm current quota costs and the
captions.downloadownership restriction against Google's live docs before relying on this row.
π€ AI Discovery & MCP Metadata
Machine-readable capability contract for autonomous agents, LLM routers, and MCP orchestrators. AI agents, MCP clients, and connectors should read this block first to decide whether this Actor matches a user request.
ai_discovery:slug: "techforce.global/youtube-transcript-scraper"one_line: "Extract the full timestamped transcript of one public YouTube video as structured JSON, in a chosen language, with optional delivery to an MCP connector."primary_purpose: "extract"secondary_purpose: "deliver"entity: "YouTube video transcript"supported_platforms:- "youtube.com"- "youtu.be"supported_tasks:- "get-transcript-for-one-video"- "get-transcript-in-specific-language"- "auto-translate-transcript"- "extract-timestamped-caption-segments"- "deliver-transcript-to-mcp-connector"unsupported_tasks:- "batch-multiple-videos-in-one-run (use youtube-full-channel-transcripts-scraper)"- "scrape-playlist-or-channel (use youtube-full-channel-transcripts-scraper)"- "transcribe-audio-without-captions (no ASR of our own)"- "download-video-or-audio-files"- "scrape-private-unlisted-or-age-gated-videos"- "retrieve-comments-views-or-channel-metadata"- "summarize-or-translate-with-an-llm"search_keywords:- "youtube transcript scraper"- "youtube captions api alternative"- "youtube subtitle extractor"- "get youtube transcript api"- "youtube transcript python"- "video transcript to notion"- "timestamped captions json"- "mcp youtube tool"- "srt subtitle data extraction"- "youtube shorts transcript"synonyms:- "youtube caption downloader"- "youtube subtitle scraper"- "video transcript extractor"- "timedtext api client"related_concepts:["transcripts", "captions", "subtitles", "timedtext", "localization", "accessibility", "content repurposing"]input_entities:- "youtube video URL or 11-character video ID"- "preferred language code (1 of 13 enum values)"- "translate toggle"output_entities: ["transcript", "segment"]input_rules:videoUrl_format:description: "Any public YouTube URL shape, or a bare 11-character video ID. Watch links, youtu.be short links, Shorts, embed, /v/, and /live/ URLs all resolve."examples:- "https://www.youtube.com/watch?v=ItqAej_Lc9c"- "https://youtu.be/ItqAej_Lc9c"- "https://www.youtube.com/shorts/ItqAej_Lc9c"- "ItqAej_Lc9c"language_format:type: "enum"case_sensitive: falsevalues: ["en", "hi", "gu", "pt", "es", "fr", "de", "it", "ja", "ko", "zh", "ru", "ar"]default_off_fields: []limits:videos_per_run: 1dataset_items_per_run: 1languages_supported: 13requires_existing_captions: truepricing:model: "pay-per-event"event_name: "actor-start"unit_cost_usd: 0.10unit: "per run (one video), regardless of transcript length"when_to_use: >You need the timestamped transcript of a specific public YouTube video βfor content repurposing, subtitle/localization work, research coding,accessibility text, or as retrieval context for an LLM or agent.when_not_to_use: >You need many videos, a whole playlist or channel, in one run; the videohas no captions at all (this Actor does not run its own speechrecognition); or you want video/audio files, comments, or channel stats.alternatives:- "Use techforce.global/youtube-full-channel-transcripts-scraper for transcripts of every video in a channel in one run"- "Use techforce.global/youtube-scraper for video/channel/comment metadata, hashtag and search discovery"- "Use techforce.global/youtube-shorts-scraper for a channel's Shorts with engagement metrics and optional video downloads"- "Loop this Actor once per video from your orchestration layer for a few specific unrelated videos"- "Use a dedicated ASR/Whisper service when the video has no caption track at all"
What this Actor does
π‘ Need a whole channel, not one video? This Actor handles one video per run. For transcripts of every video in a channel (or its latest N), use YouTube Full Channel Transcripts Scraper instead β same transcript quality, channel-wide in a single run. For views, likes, and comments rather than words, use YouTube Scraper.
- Accepts one YouTube video URL (watch link,
youtu.beshort link, Shorts, embed,/v/,/live/, or a bare 11-character ID) and resolves the video ID for you. - Fetches the caption track through the InnerTube (mobile ANDROID client) API first, then falls back to scraping
ytInitialPlayerResponseout of the watch page HTML β so a single blocked path doesn't fail the run. - Parses the caption stream in three formats in order β
json3,srv1XML, then raw β and returns every segment withstart,dur, andtext. - Never hard-fails on language. Native track in your language β used. No native track and
translate: trueβ YouTube auto-translation. Translation unavailable or turned off β the video's own caption language is returned withfallbackUsed: trueand a plain-Englishmessageexplaining what happened. - Routes traffic through Apify Proxy (residential group by default) because YouTube serves datacenter IPs a "Sign in to confirm you're not a bot" wall.
- Optionally pushes the transcript to an authorized MCP connector (Notion, Slack, Jira, GitHub, Linear, Airtable, or any MCP-compatible connector) in four delivery modes. The dataset is always saved regardless of delivery settings.
- Handles the platform
ABORTINGevent so an aborted run exits promptly instead of burning time.
When to use it β and when not to
| Scenario | Fit |
|---|---|
| Repurpose one video into a blog post, thread, or newsletter | β Strong |
| Build SRT/subtitle workflows from timestamped segments | β Strong |
| Feed transcript text to an LLM as retrieval context | β Strong |
Localize content β request hi, gu, es, ja, β¦ with auto-translation | β Strong |
| Accessibility text alternatives for audio/video | β Strong |
| Push a transcript straight into Notion or Slack | β Strong (native MCP delivery) |
| Research coding / qualitative analysis of a specific talk | β Strong |
| Every video in a channel | β οΈ One video per run β use YouTube Full Channel Transcripts Scraper |
| A handful of specific, unrelated videos | β οΈ Loop the Actor β one run per video, $0.10 each |
| A language outside the 13-value enum | β οΈ Not selectable β request en and translate downstream |
| Video with no caption track at all | β Run fails β this Actor reads captions, it does not transcribe audio |
| Private, unlisted, or age-gated videos | β Not supported β public videos only |
| Views, likes, comments, or channel stats | β Out of scope β use YouTube Scraper |
| A channel's Shorts catalogue or video file downloads | β Out of scope β use YouTube Shorts Scraper |
| Summarization or LLM translation of the transcript | β Not performed β returns raw caption text |
β‘ Execution Rules (Avoid Common Agent Failures)
videoUrlis required and has no default. Unlike some Actors, omitting it raisesInput "videoUrl" is required.and the run FAILS β it does not silently scrape a sample video. The Console pre-fills a demo URL; API/MCP callers must pass their own.- A bare 11-character video ID is accepted.
ItqAej_Lc9cworks exactly like a full URL. As a last resort the Actor also searches for any 11-character token in the string, so a malformed input can resolve to an unintended video β always pass a clean URL or ID and check the returnedvideoId. languageis a fixed 13-value enum, lowercase ISO-639-1:en,hi,gu,pt,es,fr,de,it,ja,ko,zh,ru,ar. There is noen-US, nopt-BR, and no free-text language input.- The language you ask for is not guaranteed. Read
language,isTranslated,fallbackUsed, andmessageon the output item β not just your own request. A successful run can legitimately return a different language than requested. translate: falsedoes not fail the run. It disables auto-translation; the Actor then returns the video's available caption language withfallbackUsed: trueand amessagelisting the available languages. Branch onfallbackUsed, not on run status.- Captions must already exist. This Actor reads YouTube's caption tracks; it performs no speech recognition. A video with no captions fails with
No transcript/captions are available for this video. - Keep the residential proxy on. The default is
{ useApifyProxy: true, apifyProxyGroups: ["RESIDENTIAL"] }. Datacenter IPs regularly hit YouTube's bot wall, which surfaces as a caption-retrieval failure, not a proxy error. Residential groups require a paid Apify plan. - One run = one video = one dataset item. The transcript is a nested
searchResultarray inside that single item, not one item per segment.itemCount: 1is a full result. startanddurare strings, not numbers β e.g."3.200". Cast before doing arithmetic.deliveryModedefaults tosummary, notnone. For dataset-only runs, either leavemcpConnectorempty or setdeliveryMode: "none"explicitly.perSegmentdelivery issues one connector call per segment. A 20-minute video can be hundreds of calls β preferchunkedorsummaryunless you specifically want per-line records.
dependencies:- rule: "delivery requires mcpConnector AND mcpTool"on_violation: "delivery step is skipped with a warning; the dataset item is still written"- rule: "mcpArguments must reference {message} for the rendered template to appear anywhere"on_violation: "message body is empty; the tool is still called"- rule: "mcpConnector only resolves when the Actor runs on the Apify platform"on_violation: "local runs log 'APIFY_MCP_PROXY_URL is not set' and skip delivery; the dataset is unaffected"- rule: "chunked mode exposes {part} and {partCount}"note: "put them in the page/message title or every part looks identical"authentication:actor_input: noneplatform: "Apify API token required for API / SDK / MCP invocation; paid plan required for residential proxy groups"target_site: "no YouTube or Google account, API key, or OAuth app required (public captions only)"
π₯ Input Contract
.actor/input_schema.json is authoritative β if any table on this page disagrees with the schema files, the schema files win. API and MCP clients should always pass videoUrl explicitly.
Scraping Parameters
| Field | Type | Required | Default | Allowed Values / Format | Example |
|---|---|---|---|---|---|
videoUrl | string | β Yes | none (Console prefill only) | Any public YouTube URL shape, or a bare 11-char ID | https://youtu.be/ItqAej_Lc9c |
language | string (enum) | β¬ No | en | 13 lowercase codes (see below) | hi |
translate | boolean | β¬ No | true | true / false | false |
proxyConfiguration | object | β¬ No | { useApifyProxy: true, apifyProxyGroups: ["RESIDENTIAL"] } | Apify proxy editor object | see below |
Accepted URL shapes
| Shape | Example |
|---|---|
| Standard watch | https://www.youtube.com/watch?v=ItqAej_Lc9c |
| Short link | https://youtu.be/ItqAej_Lc9c |
| Shorts | https://www.youtube.com/shorts/ItqAej_Lc9c |
| Embed | https://www.youtube.com/embed/ItqAej_Lc9c |
| Live | https://www.youtube.com/live/ItqAej_Lc9c |
| Mobile / music / nocookie hosts | https://m.youtube.com/watch?v=ItqAej_Lc9c |
| Bare video ID | ItqAej_Lc9c |
Language reference β all 13 values
en English Β· hi ΰ€Ήΰ€Ώΰ€¨ΰ₯ΰ€¦ΰ₯ / Hindi Β· gu ΰͺΰ«ΰͺΰͺ°ΰͺΎΰͺ€ΰ« / Gujarati Β· pt PortuguΓͺs Β· es EspaΓ±ol Β·
fr FranΓ§ais Β· de Deutsch Β· it Italiano Β· ja ζ₯ζ¬θͺ Β· ko νκ΅μ΄ Β·
zh δΈζ Β· ru Π ΡΡΡΠΊΠΈΠΉ Β· ar Ψ§ΩΨΉΨ±Ψ¨ΩΨ©
Region variants (en-US, pt-BR, zh-Hans) are not valid inputs β pass the base code.
Language resolution order
| Situation | What you get | isTranslated | fallbackUsed | message |
|---|---|---|---|---|
| Native caption exists in requested language | That track | false | false | null |
No native track, translate: true | YouTube auto-translation to your language | true | false | explains the translation |
| Translation returns no text | Video's own caption language | false | true | explains the failed translation |
No native track, translate: false | Video's own caption language | false | true | lists the available languages |
No language passed at all | Video's default caption track | false | false | null |
| No caption tracks at all | Run fails β TranscriptError | β | β | β |
MCP Delivery Configuration (Optional)
| Parameter | Type | Default | Description |
|---|---|---|---|
mcpConnector | string | "" | Authorized MCP connector on your Apify account (Notion, Slack, Jira, GitHub, Linear, Airtable, β¦). Leave empty for dataset-only runs. |
deliveryMode | enum | summary | summary (one call, full transcript) Β· chunked (split long transcripts) Β· perSegment (one call per segment) Β· none. |
mcpTool | string | "" | Tool name on the connector: create_page, send_message, create_issue, append_row. Run once with a connector selected β the log lists the connector's available tools. |
mcpArguments | object | {} | Arguments passed to the tool. String leaves support {placeholders}. |
mcpMessageTemplate | string | "" | Template rendered and exposed to mcpArguments as {message}. |
Placeholders by mode:
| Mode | Placeholders |
|---|---|
summary | {videoUrl}, {videoId}, {language}, {segmentCount}, {transcript} (full text), {message} |
chunked | the above, plus {part} and {partCount} β and {transcript} holds one part |
perSegment | {start}, {dur}, {text}, plus {videoUrl}, {videoId}, {language}, {segmentCount}, {message} |
Delivery packs segments into paragraphs of ~1,800 characters and groups them into parts under ~72,000 characters, so services with per-request block or timeout caps (Notion in particular) never reject the call.
{"videoUrl": "https://www.youtube.com/watch?v=ItqAej_Lc9c","language": "en","translate": true,"mcpConnector": "<your-authorized-slack-connector>","deliveryMode": "summary","mcpTool": "send_message","mcpMessageTemplate": "Transcript of {videoUrl} ({language}, {segmentCount} segments):\n\n{transcript}","mcpArguments": { "channel": "#transcripts", "text": "{message}" }}
Notion, chunked across pages (best for long videos):
{"videoUrl": "https://www.youtube.com/watch?v=ItqAej_Lc9c","language": "hi","mcpConnector": "<your-authorized-notion-connector>","deliveryMode": "chunked","mcpTool": "notion-create-pages","mcpArguments": {"parent": { "page_id": "<your-page-id>" },"pages": [{"properties": { "title": "Transcript {videoId} (part {part}/{partCount})" },"content": "{transcript}"}]}}
π€ Output Contract & Data Structure
Storage: Apify Dataset β exactly one item per run, with the transcript nested in searchResult.
Pagination: limit & offset on the dataset items endpoint (rarely needed for a single item).
Duplicates: none within a run. Across runs, dedupe on videoId + language.
| Field | Type | Nullable | Meaning |
|---|---|---|---|
videoUrl | string | No | Normalized https://www.youtube.com/watch?v=<id> URL β not necessarily the URL you passed |
videoId | string | No | Extracted 11-character video ID β verify this matches the video you meant |
requestedLanguage | string | No (may be "") | The language code you asked for, trimmed |
language | string | No | The language actually returned |
isAutoGenerated | boolean | No | true when the source track is YouTube's ASR (auto-generated) captions |
isTranslated | boolean | No | true when the text is a YouTube auto-translation |
fallbackUsed | boolean | No | true when the requested language could not be honoured |
message | string | Yes (null) | Plain-English note about any language/translation fallback; null on a clean match |
segmentCount | integer | No | Number of segments in searchResult |
searchResult | array | No | Transcript segments, in playback order |
searchResult[].start | string | No (may be "") | Segment start in seconds, as a string β e.g. "3.200" |
searchResult[].dur | string | No (may be "") | Segment duration in seconds, as a string β e.g. "2.900" |
searchResult[].text | string | No | Segment text, HTML-unescaped, newlines collapsed to spaces. Empty segments are dropped. |
Note for consumers: message is null (not "") when nothing needed explaining, and start/dur are strings for compatibility with the widely-used searchResult transcript format. Cast them before arithmetic, and test message for None/null.
Example output item
{"videoUrl": "https://www.youtube.com/watch?v=ItqAej_Lc9c","videoId": "ItqAej_Lc9c","requestedLanguage": "en","language": "en","isAutoGenerated": false,"isTranslated": false,"fallbackUsed": false,"message": null,"segmentCount": 3,"searchResult": [{ "start": "0.000", "dur": "3.200", "text": "Welcome back to the channel." },{ "start": "3.200", "dur": "2.900", "text": "Today we're talking about web scraping." },{ "start": "6.100", "dur": "4.000", "text": "Let's jump right into the setup." }]}
Fallback example β Hindi requested, only English captions exist, translate: false:
{"requestedLanguage": "hi","language": "en","isTranslated": false,"fallbackUsed": true,"message": "The requested language 'hi' is not available and translation is turned off. Returning the available caption language 'en'. Available languages: en, es."}
What a successful run looks like
{"status": "SUCCEEDED","defaultDatasetId": "<datasetId>","stats": { "itemCount": 1 }}
itemCount: 1 is the complete result β check segmentCount for transcript length. Unlike list-scraping Actors, itemCount: 0 here means the run did not produce a transcript; the run status will be FAILED with one of the messages in the matrix below.
βΆοΈ Invocation & Integration
Lifecycle: Discover β Understand β Configure β Execute β Retrieve β Validate. Authenticate every call with Authorization: Bearer <APIFY_TOKEN>.
Apify Console
Open the Actor β Input tab β paste the YouTube video URL β pick a Preferred language β leave Translate on β (optional) choose an MCP connector, tool, and template β Start β read the Dataset tab (JSON, CSV, Excel, XML).
Model Context Protocol (MCP)
Add this Actor directly as an AI tool in Claude Desktop, Cursor, VS Code, or LangChain agents:
claude mcp add --transport http apify \"https://mcp.apify.com?tools=techforce.global/youtube-transcript-scraper"
Python (apify-client)
import osfrom apify_client import ApifyClientclient = ApifyClient(os.getenv("APIFY_TOKEN"))run = client.actor("techforce.global/youtube-transcript-scraper").call(run_input={"videoUrl": "https://www.youtube.com/watch?v=ItqAej_Lc9c","language": "en","translate": True,"deliveryMode": "none",})item = client.dataset(run["defaultDatasetId"]).list_items().items[0]print(item["language"], item["segmentCount"], "segments")if item["fallbackUsed"]:print("Language fallback:", item["message"])full_text = " ".join(seg["text"] for seg in item["searchResult"])print(full_text[:400])
Batch several videos by looping the Actor (one video per run):
urls = ["https://youtu.be/aaaaaaaaaaa", "https://youtu.be/bbbbbbbbbbb"]for url in urls:run = client.actor("techforce.global/youtube-transcript-scraper").call(run_input={"videoUrl": url, "language": "en", "deliveryMode": "none"})print(url, run["status"])
JavaScript / TypeScript (apify-client)
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('techforce.global/youtube-transcript-scraper').call({videoUrl: 'https://youtu.be/ItqAej_Lc9c',language: 'hi',translate: true,deliveryMode: 'none',});const { items } = await client.dataset(run.defaultDatasetId).listItems();const [transcript] = items;console.log(`${transcript.language}: ${transcript.segmentCount} segments`);console.log(transcript.searchResult.map((s) => s.text).join(' ').slice(0, 400));
cURL β synchronous (returns the item directly; 300s limit)
curl -X POST \-H 'Content-Type: application/json' \-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \-d '{"videoUrl":"https://www.youtube.com/watch?v=ItqAej_Lc9c","language":"en","deliveryMode":"none"}' \'https://api.apify.com/v2/acts/techforce.global~youtube-transcript-scraper/run-sync-get-dataset-items'
cURL β asynchronous with a spend cap (recommended for production)
# 1. Start execution with a hard spend limitcurl -X POST -H 'Content-Type: application/json' \-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \-d '{"videoUrl":"https://youtu.be/ItqAej_Lc9c","language":"en","deliveryMode":"none"}' \'https://api.apify.com/v2/acts/techforce.global~youtube-transcript-scraper/runs?maxTotalChargeUsd=0.10'# 2. Pollcurl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \'https://api.apify.com/v2/actor-runs/<runId>'# 3. Retrieve when SUCCEEDEDcurl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \'https://api.apify.com/v2/datasets/<DATASET_ID>/items?clean=true&format=json'
β οΈ Autonomous Agent Error Handling & Resolution Matrix
| Error Code | Detection Condition | Underlying Cause | Deterministic Agent Action |
|---|---|---|---|
AUTH_INVALID | HTTP 401 | Missing or malformed APIFY_TOKEN | Abort & Prompt User: request a valid API token. |
RATE_LIMITED | HTTP 429 | Apify API rate / concurrency limits | Retry: exponential backoff (2s, 4s, 8s). |
SYNC_TIMEOUT | HTTP 408 on the sync endpoint | Run exceeded the 300s synchronous ceiling | Reconfigure: switch to async POST /runs + polling. |
MISSING_VIDEO_URL | FAILED, log Input "videoUrl" is required. | videoUrl omitted (no default exists) | Modify Input: pass videoUrl explicitly. |
BAD_VIDEO_URL | FAILED, log Could not extract a valid YouTube video ID from: β¦ | Not a YouTube URL / no 11-char ID present | Modify Input: pass a clean watch URL, youtu.be link, or bare ID. |
WRONG_VIDEO | SUCCEEDED but videoId β intended video | Last-resort 11-char token match latched onto the wrong substring | Validate & Re-run: always compare returned videoId against your input. |
NO_CAPTIONS | FAILED, log No transcript/captions are available for this video. | Video has no caption tracks at all | Abort: route to an ASR/Whisper service; this Actor cannot transcribe audio. |
CAPTIONS_BLOCKED | FAILED, log Could not retrieve caption data β¦ YouTube often blocks datacenter IPs | Bot wall / unavailable video on both InnerTube and watch-page paths | Reconfigure: enable RESIDENTIAL proxy, then retry once. |
EMPTY_TRANSCRIPT | FAILED, log Transcript was found but contained no readable text segments. | Caption track resolved but parsed to zero usable text | Retry: re-run with translate: true or a different language. |
PROXY_UNAVAILABLE | Log Could not set up proxy configuration or Running without a proxy | Residential groups require a paid Apify plan | Prompt User: upgrade the plan; expect bot-wall failures until then. |
LANGUAGE_FALLBACK | SUCCEEDED with fallbackUsed: true | Requested language unavailable | Not an error. Read language and message; re-run with translate: true if a translation is acceptable. |
TRANSLATION_FALLBACK | SUCCEEDED with isTranslated: false after requesting a foreign language | Translation attempt returned no text | Not an error. Consume the returned language or translate downstream. |
DELIVERY_SKIPPED | Log no tool name was provided | mcpConnector set but mcpTool empty | Modify Input: set mcpTool; the dataset item is already saved. |
DELIVERY_TOOL_UNKNOWN | Log Tool 'x' is not available on this connector | Wrong tool name for that connector | Modify Input: pick a name from the Available tools: list in the same log line. |
DELIVERY_EMPTY | Connector called, body empty | mcpArguments omitted the {message} placeholder | Modify Input: map {message} inside mcpArguments. |
MCP_PROXY_MISSING | Log APIFY_MCP_PROXY_URL is not set | Running locally instead of on the platform | Reconfigure: apify push and run on the platform. |
CHARGE_LIMIT | Run aborted immediately | maxTotalChargeUsd below the $0.10 start charge | Prompt User: raise the cap to at least $0.10 per run. |
β οΈ Verify before publishing: the HTTP status rows reflect standard Apify API behavior; every log-line condition above is taken verbatim from this Actor's source. Re-confirm the
408/429rows against current platform behavior if you depend on them for automated retry logic.
π£οΈ Natural Language β Actor Mapping
| User says | Intent | Constructed Actor input |
|---|---|---|
| "Get me the transcript of this YouTube video" | Transcript extraction | {"videoUrl":"<url>","language":"en"} |
| "What is said in this video?" | Content Q&A / retrieval context | {"videoUrl":"<url>"} then read searchResult[].text |
| "Summarize this YouTube video" | Summarization input | {"videoUrl":"<url>"} β summarize searchResult text yourself (the Actor returns raw captions) |
| "Give me the Hindi transcript of this talk" | Localized transcript | {"videoUrl":"<url>","language":"hi","translate":true} |
| "Transcript in Spanish, but only if it's a real Spanish caption" | Strict language | {"videoUrl":"<url>","language":"es","translate":false} then check fallbackUsed |
| "Pull the captions of this Short" | Shorts extraction | {"videoUrl":"https://www.youtube.com/shorts/<id>"} |
| "I need timestamps so I can cut clips" | Subtitle / clipping workflow | {"videoUrl":"<url>"} then read start + dur per segment |
| "Turn this video into SRT subtitles" | Localization | {"videoUrl":"<url>","language":"en"} then format segments as SRT downstream |
| "Save this video's transcript to Notion" | Pipeline/delivery | {"videoUrl":"<url>","mcpConnector":"notion","deliveryMode":"chunked","mcpTool":"notion-create-pages"} |
| "Post the transcript to Slack #content" | Pipeline/delivery | {"videoUrl":"<url>","mcpConnector":"slack","deliveryMode":"summary","mcpTool":"send_message","mcpArguments":{"channel":"#content","text":"{message}"}} |
| "Open a Jira ticket with this transcript attached" | Pipeline/delivery | {"videoUrl":"<url>","mcpConnector":"jira","deliveryMode":"summary","mcpTool":"create_issue"} |
| "Get transcripts for these 12 videos" | Batch extraction | 12 sequential runs, one videoUrl each β then merge on videoId |
| "Get transcripts for every video on this channel" | Channel-wide extraction | β‘οΈ Route to YouTube Full Channel Transcripts Scraper |
| "How many views and comments does this video have?" | Metadata | β‘οΈ Route to YouTube Scraper |
| "List all the Shorts on this channel" | Shorts catalogue | β‘οΈ Route to YouTube Shorts Scraper |
| "Transcribe this video β it has no captions" | ASR request | β Out of scope β route to a speech-recognition service |
Should NOT route here: videos with no caption track (needs ASR) Β· playlists, channels, or batch lists in a single run (β Full Channel Transcripts) Β· comments, views, likes, or channel statistics (β YouTube Scraper) Β· a channel's Shorts or video-file downloads (β Shorts Scraper) Β· private, unlisted, or age-gated videos Β· LLM summarization or translation of the text Β· non-YouTube video platforms (Vimeo, TikTok, Twitch).
π§ Agent Execution & Routing Logic
[Input User Query]ββΌ1. Target is a YouTube video (youtube.com / youtu.be)? NO β Route to the correct platform Actorβ YESβΌ2. Wants transcript/caption text (not audio, stats, comments)? NO β Route elsewhere / abortβ YESβΌ3. Is the video public (not private/unlisted/age-gated)? NO β Rejectβ YESβΌ4. Does the video have captions? UNKNOWN β Try; on NO_CAPTIONS route to an ASR serviceββΌ5. Can a video ID be extracted from the input? NO β Prompt user for a clean URL or 11-char IDβ YESβΌ6. Is the requested language in the 13-value enum? NO β Use "en" and translate downstreamβ YESβΌ7. Is a non-requested language acceptable? NO β set translate:false and check fallbackUsedβ YES β keep translate:true (default)βΌ8. More than one video needed? YES β Whole channel? Route to Full Channel Transcripts Scraperβ NO A few videos? Loop: one run per video ($0.10 each)βΌ9. Deliver to a connector? YES β set mcpConnector + mcpTool + {message} in mcpArgumentsβ NO β set deliveryMode "none"βΌ[Execute Apify Actor]βββββΊ status == "SUCCEEDED" β verify videoId, then read language / isTranslated / fallbackUsed / message β consume searchResultββββΊ status == "FAILED" β route to Error Handling Matrix above
π° Cost Control & Pricing Transparency
- Pay-per-run pricing: $0.10 per Actor start β charged once per run, regardless of video length or transcript size. One run returns one video's transcript, so this is effectively $0.10 per video.
- No per-result or per-segment charge: a 3-minute video and a 3-hour lecture cost the same.
- Autonomous spend caps: pass
maxTotalChargeUsdas a query parameter on the run endpoint for a hard per-execution ceiling. It must be at least $0.10, or the run is stopped before doing any work.
| Videos transcribed | Runs | Total Cost (USD) |
|---|---|---|
| 1 video | 1 | $0.10 |
| 10 videos | 10 | $1.00 |
| 50 videos | 50 | $5.00 |
| 100 videos | 100 | $10.00 |
| 1,000 videos | 1,000 | $100.00 |
Cost-control tips: validate the URL and confirm the video has captions before spending a run; cache transcripts by videoId + language so a re-request costs nothing; and if you need the same video in several languages, remember each language is a separate run.
β οΈ Verify before publishing: this assumes a pay-per-event Store configuration with an
actor-startevent priced at $0.10 and no additional per-result event. Confirm the Actor's live pricing configuration before publishing the listing.
π Companion machine-readable files
| File | Purpose |
|---|---|
.actor/actor.json | Identity, version, storage and dockerfile wiring |
.actor/input_schema.json | Authoritative typed input contract β videoUrl, language enum, translate, proxy editor, deliveryMode enum |
.actor/dataset_schema.json | Output field metadata and both Console views (Overview + unwound Transcript) β consumed by the Apify MCP server to describe results to agents |
.actor/output_schema.json | Declares where results are stored |
my_actor/main.py | Video-ID extraction, InnerTube + watch-page resolution, caption parsing, language fallback, MCP delivery |
my_actor/connector.py | MCP connector session handling and {placeholder} rendering |
If any table on this page disagrees with the schema files, the schema files win.
π οΈ Troubleshooting
Most failures are caption availability or proxy issues, not scraper bugs. Work through this table top to bottom β the first three rows account for the large majority of support tickets.
| # | Symptom you see | Most likely cause | Fix |
|---|---|---|---|
| 1 | FAILED β Could not retrieve caption data β¦ Last status: β¦ | YouTube's bot wall blocked the exit IP (both InnerTube and watch-page paths) | Enable RESIDENTIAL Apify Proxy (the default) and retry. Datacenter/local IPs are blocked routinely. |
| 2 | FAILED β No transcript/captions are available for this video. | The video genuinely has no caption track | Expected. This Actor reads captions; it does not transcribe audio. Use an ASR/Whisper service. |
| 3 | FAILED β Transcript was found but contained no readable text segments. | Caption track resolved but every segment parsed empty | Re-run with translate: true, or request a different language. |
| 4 | Wrong language in the output | Requested language had no native track; you got a translation or a fallback | Read language, isTranslated, fallbackUsed, message. Set translate: false if only a native track will do. |
| 5 | translate: false but the run still succeeded in another language | By design β it disables translation, it does not fail the run | Branch on fallbackUsed: true, not on run status. |
| 6 | en-US / pt-BR rejected or ignored | Only the 13 base enum codes are valid | Pass en, pt, β¦ Region variants are not selectable. |
| 7 | Text reads like speech-to-text with no punctuation | The source track is YouTube's auto-generated ASR caption | Check isAutoGenerated: true. Nothing to fix β that is the only track available. |
| 8 | videoId is not the video you meant | A last-resort regex matched an 11-char token in a malformed input | Always pass a clean URL or bare ID, and assert the returned videoId. |
| 9 | Only one dataset item | By design β one run = one video = one item, transcript nested in searchResult | Read segmentCount for length; unwind searchResult for a per-segment table. |
| 10 | start / dur arithmetic fails | They are strings ("3.200"), not numbers | Cast to float before arithmetic. |
| 11 | message is null in your consumer | null means "nothing needed explaining" | Test for None/null, not for "". |
| 12 | Log: Running without a proxy | No proxy configured or unavailable on the plan | Enable Apify Proxy residential group; a paid plan is required. |
| 13 | Log: InnerTube request failed but the run succeeded | Normal β the watch-page fallback took over | No action needed. |
| 14 | Need many videos and each run is a separate charge | One video per run by design | For a whole channel use Full Channel Transcripts Scraper; otherwise loop and cache by videoId + language. |
| 15 | Slack / Notion / Jira received nothing | Delivery needs both mcpConnector and mcpTool; otherwise it is skipped with a warning | Set both. The dataset item is still saved β your data is never lost. |
| 16 | Log: APIFY_MCP_PROXY_URL is not set | You ran locally with apify run; connectors only resolve on the platform | Deploy with apify push and run on the platform. |
| 17 | Connector fired, but the message body is empty | mcpArguments did not reference {message} | Map {message} in mcpArguments and populate mcpMessageTemplate. |
| 18 | Notion rejects or truncates a long transcript | Single-call payload exceeded block/timeout caps | Use deliveryMode: "chunked" and put {part}/{partCount} in the page title. |
| 19 | Every Notion page looks identical | {part}/{partCount} missing from the title template | Add them: "Transcript {videoId} (part {part}/{partCount})". |
| 20 | Hundreds of connector calls fired | deliveryMode: "perSegment" sends one call per segment | Switch to chunked or summary unless per-line records are the goal. |
| 21 | Delivery fired when you only wanted a dataset | deliveryMode defaults to summary, not none | Set deliveryMode: "none" or leave mcpConnector empty. |
| 22 | HTTP 401 / 403 | Missing, expired, or malformed APIFY_TOKEN | Regenerate in Apify Console β Settings β API & Integrations, send as Authorization: Bearer <token>. |
| 23 | HTTP 429 | Apify account concurrency / rate limits β not YouTube blocking | Retry with exponential backoff (2s β 4s β 8s). |
| 24 | HTTP 408 on run-sync-get-dataset-items | The synchronous endpoint has a hard 300-second ceiling | Switch to async: POST /runs β poll /actor-runs/<runId> β fetch dataset. |
Diagnostic checklist before opening an issue
- Open the video in a browser and check the transcript panel (β― β Show transcript). If YouTube shows nothing there, the video has no captions and no scraper can produce them.
- Confirm the proxy. Residential group on, paid plan active. This is the single most common cause of caption-retrieval failures.
- Baseline run.
videoUrlonly,language: "en",translate: true,deliveryMode: "none". - Check the resolved
videoIdin the output or the run log against the video you meant. - Read the run log β it names which source (InnerTube or watch page) provided the player response and which caption language was selected.
If the issue survives all five steps, open an Issues ticket on the Actor page (or email support) with the run ID, the video URL, and what you expected. Run IDs let us replay the exact execution.
β FAQ
Setup & access
Do I need a YouTube or Google account, API key, or OAuth app?
No. The Actor reads publicly available caption tracks. You need an Apify account and API token; you need no Google credentials whatsoever.
Is this the official YouTube API?
No. This is an independent Actor and is not affiliated with, endorsed by, or sponsored by YouTube or Google.
Why can't I just use the official YouTube Data API?
captions.download only works for videos you own, via OAuth. For any third-party video it is not an option β which is the main reason this Actor exists.
Do I need to configure proxies?
The residential Apify Proxy is on by default and you should leave it on β YouTube serves datacenter IPs a bot-check wall. Residential groups require a paid Apify plan.
Can I plug it into Claude, Cursor, or a LangChain agent?
Yes β it is a native MCP tool:
claude mcp add --transport http apify "https://mcp.apify.com?tools=techforce.global/youtube-transcript-scraper"
Input & languages
Can I pass a playlist, channel, or list of videos?
No β one video per run. For a whole channel, use YouTube Full Channel Transcripts Scraper, which takes a channel URL and processes up to 50 videos concurrently. For a few specific unrelated videos, loop this Actor from your orchestration layer (each run is a separate $0.10 charge).
Which languages are supported?
13: en, hi, gu, pt, es, fr, de, it, ja, ko, zh, ru, ar. Region variants like en-US are not valid inputs.
What happens if my language isn't available?
With translate: true (default) you get a YouTube auto-translation. With translate: false you get the video's own caption language, fallbackUsed: true, and a message listing what was available. The run does not fail for language reasons.
Does it work on Shorts?
Yes β Shorts, embed, /live/, youtu.be, mobile and youtube-nocookie hosts, and bare 11-character IDs all resolve.
Output & data
Why is the whole transcript in one dataset item?
One run handles one video, so the transcript is a nested searchResult array on a single item. Use the Console's Transcript view (or unwind=searchResult on the API) for a per-segment table.
Why are start and dur strings?
For compatibility with the widely-used searchResult transcript format. Cast them to float before doing arithmetic.
Does it summarize or translate with an LLM?
No. It returns YouTube's caption text β raw, timestamped, and unmodified apart from HTML unescaping. Summarize downstream.
Can it transcribe a video that has no captions?
No. There is no speech recognition in this Actor. Use an ASR service for caption-less videos.
Delivery
What is the MCP connector for?
It pushes the transcript straight into a tool you have already authorized on your Apify account β Notion, Slack, Jira, GitHub, Linear, Airtable, or any MCP-compatible connector β with no glue code. Credentials stay private: delivery runs through the Apify MCP Proxy, so the Actor never sees your connector tokens.
Which delivery mode should I use?
summary for short videos, chunked for long transcripts into services with request caps (Notion), perSegment for per-line records (logs, row-per-segment sheets), none for dataset-only runs.
Does delivery work when running locally?
No. Connectors resolve through the Apify MCP Proxy, which only exists on the platform. Locally you'll see APIFY_MCP_PROXY_URL is not set and the dataset item is saved as normal.
Limits & pricing
What does it cost?
$0.10 per run, charged at Actor start β one video per run, any length. No per-segment or per-character fees.
How do I guarantee an agent never overspends?
Pass maxTotalChargeUsd on the run endpoint (minimum $0.10 per run), and cache transcripts by videoId + language so repeats cost nothing.
π Related Actors
Other YouTube Actors
This Actor is the single-video specialist: one URL in, one timestamped transcript out, at a flat $0.10 per run. Use these siblings when the job is bigger or different.
| Actor | Best for | Why pick it over this one |
|---|---|---|
| YouTube Full Channel Transcripts Scraper | Transcripts for every video in a channel β accepts @handle, /channel/ID, /c/name, /user/name, processes up to 50 videos concurrently, and returns video + channel metadata alongside the transcript | You want a whole channel (or its latest N videos) in one run instead of orchestrating one run per video. From $10.50 / 1,000 results. |
| YouTube Scraper: Videos, Channels & Comments | Video, channel, and comment metadata from search queries, channel URLs, video URLs, or hashtags β up to 500 videos per input and 1,000 comments per video | You need views, likes, descriptions, channel stats, or comment threads β none of which this transcript Actor returns. From $9.00 / 1,000 results. |
| YouTube Shorts Scraper | Every Short from a channel with engagement metrics (views, likes, comments, hashtags) and optional video downloads | You're working through a channel's Shorts catalogue, or you need the video files themselves. From $8.50 / 1,000 results. |
Pick by intent: one video's words β this Actor Β· a channel's words β Full Channel Transcripts Β· numbers, comments, and search discovery β YouTube Scraper Β· a channel's Shorts and their files β Shorts Scraper.
Enrichment & downstream pipeline
| Actor | Use it for |
|---|---|
| Advanced Website Crawling Actor | Crawl the creator's own site or show notes for clean HTML/Markdown/text context alongside the transcript |
| Google Maps Scraper β Business Data | Enrich businesses or venues mentioned in a transcript into full business records |
| GOV.UK Business Scraper | Match UK company names heard in a video against Companies House records |
Suggested pipeline patterns
βοΈ Content repurposing
YouTube Transcript Scraper β transcript text into your LLM of choice β blog draft, thread, newsletter β publish via a Notion/Slack connector.
π Localization
One run per target language (hi, gu, es, β¦) β format start/dur/text as SRT downstream β upload as subtitle tracks.
π Video knowledge base
YouTube Full Channel Transcripts Scraper for the channel backfill β this Actor for each new upload β store by videoId + language β index searchResult text for semantic search over everything you've published.
π Transcript + engagement analysis YouTube Scraper for views, likes, and comments β this Actor for the words of the videos that over-performed β correlate topics against engagement.
π€ Agent retrieval tool Register the Actor as an MCP tool so an agent can pull a video's transcript on demand and answer questions with timestamps.
Browse all Actors by Techforce Global at apify.com/techforce.global.
π Compliance & Data Privacy
This is an independent Actor. It is not affiliated with, endorsed by, or sponsored by YouTube or Google. YouTubeβ’ is a trademark of Google LLC; all trademarks are the property of their respective owners.
This Actor collects publicly available caption/transcript data only. It does not log into any account, bypass authentication, or access private, unlisted, or age-gated videos. Transcripts are the creator's copyrighted content β you are responsible for ensuring your use complies with YouTube's Terms of Service, applicable copyright law, and any data-protection regulation (including GDPR and CCPA) that applies to text you store or republish. Spoken content can contain personal data about identifiable people β handle accordingly.
π Support & Custom Pipeline Engineering
Whole-channel coverage is already a product β see YouTube Full Channel Transcripts Scraper. Need something beyond it: scheduled multi-channel monitoring, playlist coverage, or a full content pipeline into your CMS?
- Email: bhavin.shah@techforceglobal.com
- Custom Enterprise Integrations: Book a 15-Minute Technical Consultation
- Maintained by: Techforce Global β Specialists in High-Performance Web Scrapers and Agentic Workflows.
Made with β€οΈ by Techforce Global Specialists in High-Performance Video & Transcript Data Extraction and AI Automation.
π·οΈ Structured data for search & AI discovery
{"@context": "https://schema.org","@type": "SoftwareApplication","name": "YouTube Transcript Scraper & Captions API Alternative","applicationCategory": "DeveloperApplication","operatingSystem": "Cloud (Apify platform)","description": "Extracts the full transcript of any public YouTube video as structured JSON β every segment with start time, duration, and text β in 13 languages with automatic translation fallback, and optional delivery to Notion, Slack, Jira, GitHub, Linear, Airtable, or any authorized MCP connector.","url": "https://apify.com/techforce.global/youtube-transcript-scraper","offers": {"@type": "Offer","price": "0.10","priceCurrency": "USD","description": "Per run (one video, any length)"}}