YouTube Channel Transcripts Scraper avatar

YouTube Channel Transcripts Scraper

Pricing

from $10.50 / 1,000 results

Go to Apify Store
YouTube Channel Transcripts Scraper

YouTube Channel Transcripts Scraper

Bulk YouTube channel transcript scraper. Extract subtitles/captions and video + channel metadata from all videos of a channel. Export or push to Notion, Slack & more.

Pricing

from $10.50 / 1,000 results

Rating

0.0

(0)

Developer

Techforce Global

Techforce Global

Maintained by Community

Actor stats

0

Bookmarked

5

Total users

2

Monthly active users

11 days ago

Last modified

Share

YouTube Channel Transcript Scraper

Apify Actor MCP Ready Pricing Scope Public data only Target

Point it at a channel, get every video's transcript. One dataset row per video — full plain text for embedding, or timestamped {text, start, duration} segments for deep-linking, plus whichever of 19 optional metadata fields you switch on. No Google API key, no OAuth, no video ownership, no quota. Built for RAG corpora, content analysis and searchable video archives, with optional delivery into Notion, Slack, Linear, Jira, GitHub or Airtable over MCP.

🔐 Trust & compliance at a glance

CredentialsNone required. The Actor never needs a Google or YouTube account. The optional cookies field is stored as a secret input, and MCP delivery runs through the Apify MCP Proxy, so the Actor never sees your connector tokens.
Data scopePublic caption tracks and public metadata only. No private or members-only videos, and no comment text — only the comment count, and only if you toggle it on.
GDPR / UK GDPR / CCPAA transcript is a person's speech, so it can be personal data about the speaker and anyone named aloud. The Compliance section sets out minimisation, retention and special-category handling in full.
Attribution safetytranscriptIsGenerated: true flags machine-written text — check it before quoting anyone verbatim.
Honest gapsA video with no retrievable transcript still gets a row, carrying transcriptError. Nothing vanishes silently.

Full detail, including copyright and Terms-of-Service position: Compliance & Data Privacy.


Official YouTube Data API v3 vs. YouTube Channel Transcript Scraper Actor

The official API's captions.download endpoint only works for videos you own, so there is no sanctioned route to a third-party channel's transcripts at all:

Feature / CapabilityOfficial YouTube Data API v3YouTube Channel Transcript Scraper (Apify)
Transcripts for videos you don't owncaptions.download requires OAuth as the video owner✅ Any public video with captions
A whole channel in one call❌ List uploads, then one caption call per video — all owner-gated✅ One run covers the channel, or its newest N
Authentication & setup❌ Google Cloud project + OAuth consent flow✅ Zero target-site credentials; only an Apify token
Timestamped segments⚠️ Owner-only, and format handling is yours{text, start, duration} objects, ready to use
Tells you what you actually got❌ N/AtranscriptLanguage, transcriptIsGenerated, transcriptError per video
Daily quota ceiling⚠️ Per-project daily quota; exceeding it blocks you until reset✅ No per-day ceiling
Bot-wall / IP blockingN/A (quota-gated instead)✅ Apify residential proxy wired in by default, plus optional cookies
AI agent / MCP native❌ Requires a custom tool wrapper✅ Native MCP tool and pushes results into your own MCP connectors

The captions.download ownership restriction and quota costs are Google's to change — check Google's current docs if this comparison is load-bearing for your decision.


🤖 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-full-channel-transcripts-scraper"
actor_id: "youtube-full-channel-transcripts-scraper"
one_line: >
Scrapes the transcript of every video on one or more YouTube channels - as plain text,
timestamped segments, or both - alongside 19 optional video and channel metadata fields,
each individually toggleable. No API key required. Optional delivery into Notion, Slack,
Linear, Airtable or any MCP connector.
primary_purpose: "extract"
secondary_purpose: "deliver"
entity: "YouTube video transcript"
category: "video-transcripts / rag-ingestion / content-analysis / media-research"
supported_platforms:
- "youtube.com"
- "youtu.be"
supported_tasks:
- "get-transcripts-for-every-video-on-a-channel"
- "get-transcripts-for-the-newest-n-videos"
- "get-timestamped-transcript-segments"
- "build-a-rag-corpus-from-a-channel"
- "compare-topics-across-several-channels"
- "audit-transcript-language-and-quality"
- "deliver-transcripts-to-mcp-connector"
unsupported_tasks:
- "scrape-comment-text (use youtube-scraper; only the comment COUNT is available)"
- "search-terms-or-hashtags-as-input (use youtube-scraper)"
- "download-video-or-audio-files (use youtube-shorts-scraper for Shorts media)"
- "transcribe-audio-without-captions (no ASR of our own)"
- "translate-transcripts"
- "creator-analytics-watch-time-retention-revenue (not public)"
- "scrape-private-unlisted-or-members-only-videos"
search_keywords:
# First entry is the H1 / meta-description target. The rest are deliberately broader for
# agent-side semantic matching and are NOT a ranking strategy - see the skill's SEO notes.
- "youtube channel transcript scraper"
- "bulk youtube transcripts"
- "all videos transcript download"
- "youtube transcript api alternative"
- "video corpus for rag"
- "youtube subtitle extractor channel"
- "timestamped captions json"
- "content analysis youtube channel"
- "video knowledge base ingestion"
- "mcp youtube transcripts tool"
synonyms:
- "channel-wide caption downloader"
- "youtube subtitle scraper"
- "video transcript extractor"
related_concepts:
["transcripts", "captions", "RAG ingestion", "semantic search", "content analysis", "media research"]
input_entities:
- "channelUrls (required; array. @handle, /channel/ID, /c/name, /user/name, or a video URL)"
- "maxVideos (per channel; 0 = ALL videos)"
- "maxConcurrency (1-50 videos in parallel)"
- "transcriptLanguages (priority order, falls back to any available)"
- "includeTranscriptText / includeTranscriptSegments"
- "proxyConfiguration (residential by default)"
- "cookies (optional, secret, Netscape format)"
- "19 include* toggles for metadata fields"
output_entities_always:
- "videoId"
- "videoUrl"
- "title"
output_entities_transcript:
- "transcript"
- "transcriptSegments"
- "transcriptLanguage"
- "transcriptIsGenerated"
- "transcriptError"
output_entities_toggleable_video:
- "channelName"
- "channelId"
- "dateText"
- "relativeDateText"
- "datePublished"
- "viewCount"
- "likes"
- "comments"
- "keywords"
- "thumbnail"
- "description"
output_entities_toggleable_channel:
- "channelHandle"
- "subscriberCount"
- "channelCreationDate"
- "channelCountry"
- "channelTotalViewCount"
- "channelTotalVideoCount"
language_fallback_is_silent: >
CRITICAL: transcriptLanguages is a PREFERENCE list, not a filter. If no preferred language
exists the Actor returns any available transcript, including auto-generated. It does not
fail or warn per video. Always read transcriptLanguage on each row before treating a corpus
as monolingual.
auto_generated_transcripts_are_flagged: >
transcriptIsGenerated is true when YouTube machine-transcribed the audio. Auto-generated
text carries recognition errors, no punctuation reliability and mangled proper nouns. Filter
on it if transcript quality matters.
transcript_error_presence_is_the_signal: >
transcriptError appears ONLY when retrieval failed. Its absence means success. Videos with
transcripts disabled, or none in any language, produce a row with a null transcript and this
field set - the row is still saved so the channel inventory stays complete.
toggled_off_fields_are_absent_keys: >
A field whose toggle is off is not written at all - it is an ABSENT KEY, not a null. Consumers
must use .get()/optional access rather than indexing.
maxVideos_zero_means_all: >
maxVideos 0 scrapes EVERY video on each channel. On a large channel that is thousands of
videos, each needing a transcript fetch. Always pair 0 with a spend cap.
request_cost_classes: >
Three cost tiers, and they are NOT what the field names suggest. (1) Free, already in the
channel listing: channelName, channelId, viewCount, thumbnail. (2) One extra request PER
VIDEO, triggered by enabling ANY of includeLikes, includeComments, includeKeywords,
includeDescription, includeDateText or includeRelativeDateText - the single largest cost
lever after maxVideos; enabling all six costs the same as enabling one. (3) One extra fetch
PER CHANNEL, shared by all six extended channel toggles together - enabling all six costs no
more than enabling one, and includeSubscriberCount is ON by default so that fetch already
happens unless you turn all six off.
date_published_caveat: >
datePublished is derived from whatever the listing returned. The channel listing frequently
omits the timestamp, so datePublished can be null unless a per-video fetch is triggered by
one of the six toggles in cost tier 2.
channels_are_sequential_videos_are_parallel: >
Multiple channelUrls are processed one channel at a time; within a channel, videos run in
parallel up to maxConcurrency.
no_comments_here: >
This Actor does NOT scrape comments. Use the sibling YouTube Scraper
(techforce.global/youtube-scraper) for comment threads.
compliance:
credentials_required: "none - no Google/YouTube account needed; the optional cookies field is a secret input"
data_scope: "public caption tracks and public metadata only"
connector_token_handling: "MCP delivery runs through the Apify MCP Proxy; the Actor never sees your connector tokens"
personal_data_note: "a transcript is a person's speech and can be personal data about the speaker and anyone named aloud - GDPR / UK GDPR / CCPA-CPRA obligations sit with the caller"
attribution_flag: "transcriptIsGenerated true means the text is machine-written; do not attribute it as a verbatim quote"
affiliation: "independent Actor; not affiliated with, endorsed by, or sponsored by YouTube or Google"
known_limitations:
not_every_video_has_a_transcript: "creators can disable them; some languages have none"
auto_generated_quality: "machine transcripts contain errors, especially with names and jargon"
no_translation: "returns what YouTube publishes, untranslated"
no_comments: "comment threads are not collected - only the comment COUNT, and only if toggled"
no_creator_analytics: "watch time, retention and revenue are not public"
no_video_files: "transcripts and metadata only - nothing is downloaded"
row_count_can_trail_video_count: "a video whose record fails to build is logged and skipped, so the dataset can hold fewer rows than the 'Found N video(s)' log line"
snapshot_only: "view and like counts are true as of the run"
pricing:
model: "usage-based"
billing_unit: "Apify platform usage consumed by the run"
note: "Current rates are shown on the Actor's Apify Store page; the Console shows a live total mid-run. A hard per-run ceiling can be set with maxTotalChargeUsd."
hard_ceiling_parameter: "maxTotalChargeUsd"
when_to_use: >
You want everything a channel has said, as data - a RAG corpus, a searchable archive, a
content-strategy analysis, or a multi-channel topic comparison.
when_not_to_use: >
You need comment threads, search or hashtag discovery, creator analytics, the video files, a
translated transcript, or a guaranteed transcript for every video regardless of whether the
creator enabled one.
mcp_delivery:
modes: ["summary", "chunked", "perSegment", "none"]
default: "summary"
delivery_is_per_video: >
Delivery fires once per video as its record is saved, not once per run. chunked multiplies
that by the number of parts, and perSegment by the number of segments.
all_mode_placeholders: ["{videoUrl}", "{videoId}", "{title}", "{channelName}", "{channelId}", "{datePublished}", "{viewCount}", "{subscriberCount}", "{language}", "{segmentCount}", "{transcript}", "{message}"]
chunked_only_placeholders: ["{part}", "{partCount}"]
per_segment_placeholders: ["{start}", "{dur}", "{duration}", "{text}"]
per_segment_without_segments_falls_back: >
perSegment needs includeTranscriptSegments enabled. Without segments it does NOT fail and
does NOT go silent - it logs a warning and sends one summary call for that video instead.
never_blocks_the_dataset: >
Delivery runs after the record is saved. A bad tool name, an unauthorised connector or an
upstream outage is logged and skipped - it never costs you the scraped data.
alternatives:
- "Use techforce.global/youtube-transcript-scraper for a single video's transcript"
- "Use techforce.global/youtube-scraper for search, hashtags, video metadata and comment threads"
- "Use techforce.global/youtube-shorts-scraper for a channel's Shorts with engagement and optional media download"
- "Use a dedicated ASR/Whisper service when videos have no caption track at all"

{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "YouTube Full Channel Transcripts Scraper",
"alternateName": "YouTube Channel Transcript Scraper",
"applicationCategory": "DeveloperApplication",
"operatingSystem": "Cloud (Apify platform)",
"description": "Scrapes the transcript of every video on one or more YouTube channels — as a single plain-text string, as timestamped {text, start, duration} segments, or both — alongside 19 individually toggleable video and channel metadata fields, without a Google API key, OAuth, or video ownership. Resolves a channel from an @handle, /channel/ID, /c/, /user/ path or any video URL. Reports the language actually retrieved, whether the transcript was auto-generated, and a per-video error when none was available, so gaps are recorded rather than silently dropped. Public captions only, with GDPR/CCPA and speaker-identifiability guidance included. Residential proxy by default with optional cookie support, and optional delivery into Notion, Slack, Linear, Airtable or any MCP connector with chunking for long transcripts.",
"url": "https://apify.com/techforce.global/youtube-full-channel-transcripts-scraper",
"offers": {
"@type": "Offer",
"priceCurrency": "USD",
"category": "Pay per platform usage",
"description": "Usage-based: billed for the compute time and resources a run consumes, not per row. Current rates are shown on the Actor's Apify Store page."
}
}

What this Actor does

💡 Need one video, not a channel? YouTube Transcript Scraper does a single video in one run, with 13-language auto-translation. For views, likes, comments, search and hashtags, use YouTube Scraper; for a channel's Shorts and their video files, use YouTube Shorts Scraper.

  • Resolves a channel from almost any URL you have. @handle, /channel/ID, /c/name, /user/name — or even a single video URL, from which the channel is worked out for you.

  • Covers the whole channel, or the newest N. maxVideos: 0 takes everything; anything else caps it, newest first. Several channels in one run: channelUrls is an array.

  • Returns the spoken content, two ways. transcript as one plain-text string for embedding and search; transcriptSegments as {text, start, duration} objects when you need to jump to a timestamp. Enable either, or both.

  • Tells you how good each transcript is. transcriptLanguage says what you actually got, transcriptIsGenerated says whether a machine wrote it, and transcriptError appears only when retrieval failed. Three fields that turn "here's a corpus" into "here's a corpus you can assess".

  • Records the gaps instead of hiding them. A video whose transcript can't be retrieved still produces a row, so you get a complete channel inventory with the holes marked.

  • Lets you pay for exactly the metadata you want. 19 individual toggles across three distinct cost tiers — see Input Contract, because the cheap-looking ones aren't the cheap ones.

  • Handles the bot check. Residential proxy by default, a fresh proxy IP per video, plus an optional secret cookies field for channels a proxy alone can't reach.

  • Saves as it goes. Each video is written to the dataset as it finishes, so an aborted or timed-out run keeps everything collected up to that point.

  • Optionally delivers into your tools. Each video's transcript can go straight to Notion, Slack, Linear, Jira, GitHub or Airtable — with a chunked mode for transcripts too long for one page.


Which YouTube Actor do I want?

You want…Actor
Transcripts of every video on a channelThis Actor
One video's transcript, with auto-translationYouTube Transcript Scraper
Long-form video metadata, search, hashtags, comment threadsYouTube Scraper
A channel's Shorts, with engagement and optional file downloadYouTube Shorts Scraper

None of them need a YouTube Data API key or a quota. They're complementary, not alternatives.


When to use it — and when not to

ScenarioFit
Every video's transcript from a channel✅ Strong — the core use case
Transcripts as plain text for RAG or search✅ Strong — includeTranscriptText
Timestamped segments for deep-linking✅ Strong — includeTranscriptSegments
Building a searchable archive of a creator's back catalogue✅ Strong — maxVideos: 0 plus a spend cap
Comparing topics across several channels✅ Strong — channelUrls is an array
Knowing whether a transcript is auto-generated✅ Strong — transcriptIsGenerated
A complete inventory including videos with no transcript✅ Strong — those rows carry transcriptError
Only the fields you actually want✅ Strong — 19 toggles
Transcripts pushed into Notion / Slack✅ Strong — MCP delivery, with chunking
A specific transcript language⚠️ Preference only — falls back silently, check transcriptLanguage
A precise publish date on every row⚠️ datePublished can be null unless a per-video fetch is triggered — see Input Contract
Comment threads❌ Count only — use the YouTube Scraper
Search terms or hashtags as input❌ Channels only — the sibling does search
Translated transcripts❌ Returns what YouTube publishes, untranslated — the single-video Actor does translation
A transcript for videos that have none❌ No speech recognition here — route to an ASR service
Downloading video or audio❌ Transcripts and metadata only
Private, unlisted or members-only videos❌ Public content only
Creator analytics — watch time, retention, revenue❌ Not public
Uploading, editing or posting❌ Read-only

⚡ Execution Rules (Avoid Common Agent Failures)

  1. channelUrls is required and is an array. Any of @handle, /channel/ID, /c/name, /user/name, or a video URL works — a video URL resolves to its channel. Objects ([{"url": "…"}]) and bare strings (["…"]) are both accepted.

  2. transcriptLanguages is a preference, not a filter. If none of your codes exist for a video, the Actor returns any available transcript, including auto-generated, and doesn't warn per video. Read transcriptLanguage on every row before treating the output as monolingual. Filter after the fact if you need strictly one language.

  3. maxVideos: 0 means every video on each channel. On a large channel that's thousands of videos, each needing its own transcript fetch. Always pair 0 with a spend cap. Default is 10.

  4. The expensive toggles are the video ones, not the channel ones. Enabling any of includeLikes, includeComments, includeKeywords, includeDescription, includeDateText or includeRelativeDateText triggers one extra request per video. The six extended channel toggles share one fetch per channel between them. Enabling all six of either group costs no more than enabling one of it.

  5. datePublished can be null on the cheap path. It comes from whatever the channel listing returned, and the listing often omits the timestamp. If you need reliable dates, enable one of the six per-video toggles in rule 4 — the full fetch fills it in.

  6. A field you toggled off is an absent key, not null. Use row.get("viewCount"), not row["viewCount"].

  7. transcriptError's presence is the failure signal. No transcriptError key means the transcript was retrieved. When it is present, transcript is null and the field says why.

  8. Check transcriptIsGenerated before trusting the text. Auto-generated transcripts have recognition errors, unreliable punctuation and mangled proper nouns. For anything quality-sensitive, filter to human-authored, or expect to clean.

  9. Turning off both transcript toggles gives you metadata-only rows. No transcript, no transcriptSegments, and no transcriptLanguage / transcriptIsGenerated / transcriptError keys at all.

  10. Keep the residential proxy. The default is {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}. Datacenter IPs get the bot check. If you pass proxyConfiguration as empty or omit it in a hand-built input object, the run uses no proxy at all — pass it explicitly from API and MCP callers. Residential groups require a paid Apify plan. If you're still blocked, supply cookies.

  11. The row count can be lower than the video count. A video whose record can't be built is logged (Failed to build record for <id>) and skipped. Compare the dataset size against the Found N video(s) log line rather than assuming they match.

  12. Channels run one at a time; videos run in parallel. maxConcurrency (default 10, range 150) applies within a channel. 812 is the sensible band; drop to 13 if you're being blocked.

  13. Delivery fires per video, not once per run. Ten videos in summary mode is ten connector calls; chunked multiplies that by the number of parts, perSegment by the number of segments.

  14. deliveryMode defaults to summary, not none. For dataset-only runs, either leave mcpConnector empty or set deliveryMode: "none" explicitly.

  15. No comments here. This Actor returns the comment count (if toggled), never the comment text. That's the sibling Actor's job.

dependencies:
- rule: "delivery requires mcpConnector AND mcpTool"
on_violation: "delivery is skipped with a warning; every dataset row 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: "perSegment needs includeTranscriptSegments"
on_violation: "logs a warning and sends ONE summary call for that video instead - not a silent no-op"
- rule: "chunked mode exposes {part} and {partCount}"
note: "put them in the page/message title or every part looks identical"
authentication:
actor_input: "none required; optional cookies field is a secret input"
platform: "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.

Scraping parameters

ParameterTypeRequiredDefaultAllowed values / formatExample
channelUrlsarray✅ Yesnone (Console prefill only)@handle, /channel/ID, /c/name, /user/name or a video URL. Objects or bare strings.[{"url":"https://www.youtube.com/@handle"}]
maxVideosinteger⬜ No100 = ALL videos per channel; otherwise the cap, newest first100
maxConcurrencyinteger⬜ No10150. 812 is the sweet spot8
transcriptLanguagesarray<string>⬜ No["en"]Priority order. Falls back to any available if none match["hi","en"]
includeTranscriptTextboolean⬜ NotrueTranscript as one plain-text stringtrue
includeTranscriptSegmentsboolean⬜ NofalseTranscript as {text, start, duration} objectstrue
proxyConfigurationobject⬜ No{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}Apify proxy editor object. Pass it explicitly from the API.see below
cookiesstring (secret)⬜ NoNetscape cookies.txt from a logged-in session. Helps when a proxy alone isn't enough.

Accepted channel input shapes

ShapeExample
Handlehttps://www.youtube.com/@handle
Channel ID pathhttps://www.youtube.com/channel/UCxxxxxxxxxxxxxxxxxxxxxx
Legacy custom pathhttps://www.youtube.com/c/name
Legacy user pathhttps://www.youtube.com/user/name
Any video URL from the channelhttps://www.youtube.com/watch?v=dQw4w9WgXcQ
A tab URLhttps://www.youtube.com/@handle/videos — tab suffixes are honoured as given

Metadata toggles — and what each one actually costs

There are three cost tiers, and they are not what the field names suggest. Read this before switching things on.

Tier 1 — free. Already present in the channel listing; toggling them only changes what gets written.

ToggleFieldDefault
includeChannelNamechannelName✅ on
includeChannelIdchannelId✅ on
includeViewCountviewCount✅ on
includeThumbnailthumbnailoff
includeDatePublisheddatePublished (ISO)✅ on — but see the caveat below

Tier 2 — one extra request per video. Enabling any single one of these triggers a full per-video metadata fetch; enabling all six costs the same as enabling one. This is the largest cost lever after maxVideos.

ToggleFieldDefault
includeLikeslikesoff — often null, creators hide it
includeCommentscomments (the count)off
includeKeywordskeywordsoff
includeDescriptiondescriptionoff
includeDateTextdateTextoff
includeRelativeDateTextrelativeDateTextoff

datePublished caveat. It is derived from whatever the listing returned, and the channel listing frequently omits the timestamp — so on a run with no Tier 2 toggle enabled, datePublished can come back null. Enabling any Tier 2 toggle triggers the full fetch and fills it in.

Tier 3 — one extra fetch per channel, shared by all six. Enabling all six costs no more than enabling one. includeSubscriberCount is on by default, so this fetch already happens unless you turn all six off.

ToggleFieldDefault
includeSubscriberCountsubscriberCount✅ on — null if hidden
includeChannelHandlechannelHandleoff
includeChannelCreationDatechannelCreationDateoff
includeChannelCountrychannelCountryoff
includeChannelTotalViewCountchannelTotalViewCountoff
includeChannelTotalVideoCountchannelTotalVideoCountoff

Delivery (optional)

ParameterTypeDefaultDescription
mcpConnectorstring""An MCP connector you have authorised on your Apify account — Notion, Slack, Linear, Jira, GitHub, Airtable, or any MCP-compatible connector. The Console offers a picker. Leave empty for dataset-only runs.
deliveryModestring (enum)"summary"summary (one call per video) · chunked (split a long transcript across calls/pages) · perSegment (one call per segment) · none.
mcpToolstring""Tool to call — e.g. create_page, send_message, create_issue. Required when a connector is set. Run once with a connector selected and the log lists the connector's available tools.
mcpArgumentsobject{}Arguments for the tool. String leaves support {placeholder} tokens.
mcpMessageTemplatestring""Template rendered and exposed to mcpArguments as {message}.

Placeholders by mode:

ModePlaceholders
all modes{videoUrl} {videoId} {title} {channelName} {channelId} {datePublished} {viewCount} {subscriberCount} {language} {segmentCount} {transcript} {message}
chunkedplus {part} {partCount}{transcript} holds one part
perSegmentplus {start} {dur} / {duration} {text}needs includeTranscriptSegments; without it, one summary call is sent for that video and a warning is logged

Unknown tokens render as an empty string rather than erroring. The delivered {transcript} is repacked into paragraphs of roughly 1,800 characters and grouped into parts under roughly 72,000 characters, so services with per-block or timeout caps (Notion in particular) never reject the call.


📤 Output Contract & Data Structure

Storage: Apify Dataset — one item per video, written as each video finishes. Absent vs null: fields whose toggle is off are absent keys, not nulls. Order: completion order, not chronological — videos run in parallel. Sort client-side. Duplicates: none within a run. Across runs, dedupe on videoId.

Always present

FieldTypeNullableMeaning
videoIdstringNoYouTube's 11-character ID. The stable key for joining runs.
videoUrlstringNoCanonical watch URL.
titlestringYesVideo title.

Transcript fields — present when either transcript toggle is on

FieldTypeNullableToggle / controlled byMeaning
transcriptstringYesincludeTranscriptTextFull transcript as one string. Null when retrieval failed.
transcriptSegmentsarrayYesincludeTranscriptSegments{text, start, duration} objects; start/duration are numbers, rounded to 3 decimals. [] on failure.
transcriptLanguagestringYestranscriptLanguagesWhat you actually got — may differ from your preference list.
transcriptIsGeneratedbooleanYes— (source track)true = machine-transcribed. Expect recognition errors.
transcriptErrorstring— (video state)Present only on failure, and says why (e.g. No transcript available). Its absence means success.

Toggleable video metadata

FieldTypeToggleCost tier
channelName / channelIdstringon by defaultFree
viewCountintegeron by defaultFree
thumbnailstringoffFree
datePublishedstring (ISO)on by defaultFree — but often null without a Tier 2 toggle
dateText / relativeDateTextstringoffPer video
likesintegeroff — often null, creators hide itPer video
commentsintegeroff — the count; text is not scrapedPer video
keywordsarrayoffPer video
descriptionstringoffPer video

Toggleable channel metadata

All six share one fetch per channel.

FieldTypeToggle
subscriberCountintegeron by default — null if hidden
channelHandlestringoff
channelCreationDatestring (ISO date, or the raw text if unparseable)off
channelCountrystringoff
channelTotalViewCountintegeroff
channelTotalVideoCountintegeroff

Example output object (defaults, plus segments)

{
"videoId": "aBcDeFgHiJk",
"videoUrl": "https://www.youtube.com/watch?v=aBcDeFgHiJk",
"title": "How We Rebuilt Our Ingestion Pipeline",
"transcript": "So the first thing we noticed was that our queue depth kept growing…",
"transcriptSegments": [
{ "text": "So the first thing we noticed", "start": 0.32, "duration": 2.1 },
{ "text": "was that our queue depth kept growing", "start": 2.42, "duration": 2.8 }
],
"transcriptLanguage": "en",
"transcriptIsGenerated": false,
"channelName": "Practical Systems",
"channelId": "UC000000000000000000000",
"datePublished": "2026-06-14",
"viewCount": 48211,
"subscriberCount": 128000
}

A video whose transcript could not be retrieved:

{
"videoId": "lMnOpQrStUv",
"videoUrl": "https://www.youtube.com/watch?v=lMnOpQrStUv",
"title": "Members-only Q&A",
"transcript": null,
"transcriptLanguage": null,
"transcriptIsGenerated": null,
"transcriptError": "No transcript available",
"channelName": "Practical Systems",
"channelId": "UC000000000000000000000",
"datePublished": "2026-07-02",
"viewCount": 3102,
"subscriberCount": 128000
}

Values illustrate shape and formatting — the channel and videos are invented. Note that the failed row is still saved: you get a complete inventory of the channel, with transcriptError marking the gaps rather than the video silently vanishing.

What a successful run looks like

  • Status: SUCCEEDED
  • Dataset: one item per video, including videos whose transcript failed
  • Log: a startup line echoing maxVideos, concurrency, languages, proxy and cookie state; then the resolved channel and video count; then a [n/total] Done: <videoId> line per video
  • Zero results is also a success. A bot-block, a channel with no public videos, or an unresolvable URL all return an empty dataset with SUCCEEDED. Check the log.
  • Rows with transcriptError are not failures of the run — they're an honest record that the video has no retrievable transcript.
  • Fewer rows than the "Found N" line means some records failed to build; those are logged individually.

Dataset views

ViewShows
TranscriptsTitle, video link, channel, date, views, subscribers and the transcript text
Transcript HealthLanguage, auto-generated flag and error per video — check this before trusting a corpus
Video MetadataEngagement and publishing columns without the transcript text
Channel MetadataChannel-level columns repeated per row

▶️ Invocation & Integration

Lifecycle: Discover → Understand → Configure → Execute → Retrieve → Validate. Authenticate every call with Authorization: Bearer <APIFY_TOKEN>.

Apify Console

Open the Actor pageInput tab → paste a channel URL → set Maximum videos → leave the proxy at its residential default → (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-full-channel-transcripts-scraper"

Then ask your agent for "transcripts of the last 20 videos from this channel".

Python (apify-client)

import os
from apify_client import ApifyClient
client = ApifyClient(os.getenv("APIFY_TOKEN"))
run = client.actor("techforce.global/youtube-full-channel-transcripts-scraper").call(run_input={
"channelUrls": [{"url": "https://www.youtube.com/@handle"}],
"maxVideos": 50,
"transcriptLanguages": ["en"],
"includeTranscriptText": True,
"deliveryMode": "none",
"proxyConfiguration": {
"useApifyProxy": True,
"apifyProxyGroups": ["RESIDENTIAL"],
},
})
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
# Assess the corpus BEFORE using it.
ok = [r for r in rows if not r.get("transcriptError")]
failed = [r for r in rows if r.get("transcriptError")]
generated = [r for r in ok if r.get("transcriptIsGenerated")]
langs = {r.get("transcriptLanguage") for r in ok}
print(f"{len(ok)}/{len(rows)} transcripts | {len(generated)} auto-generated | languages: {langs}")
if len(langs) > 1:
print(" ⚠ mixed languages — the preference list fell back on some videos")
for r in failed[:5]:
print(f" no transcript: {r['title']!r}{r['transcriptError']}")
# Toggled-off fields are ABSENT keys — always use .get().
print("dates present:", sum(1 for r in rows if r.get("datePublished")))

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-full-channel-transcripts-scraper').call({
channelUrls: [{ url: 'https://www.youtube.com/@handle' }],
maxVideos: 100,
includeTranscriptSegments: true, // timestamps for deep-linking
includeTranscriptText: true,
deliveryMode: 'none',
proxyConfiguration: { useApifyProxy: true, apifyProxyGroups: ['RESIDENTIAL'] },
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
// Build deep links to the moment a term is mentioned.
const TERM = 'kubernetes';
for (const row of items) {
for (const seg of row.transcriptSegments ?? []) {
if (seg.text.toLowerCase().includes(TERM)) {
console.log(`${row.title}${row.videoUrl}&t=${Math.floor(seg.start)}s`);
}
}
}

cURL — synchronous (waits, returns the dataset)

curl -X POST \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
-d '{
"channelUrls": [{ "url": "https://www.youtube.com/@handle" }],
"maxVideos": 10,
"deliveryMode": "none",
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}' \
'https://api.apify.com/v2/acts/techforce.global~youtube-full-channel-transcripts-scraper/run-sync-get-dataset-items'

cURL — asynchronous with a spend cap (required for maxVideos: 0)

# 1. Start execution with a hard spend limit
curl -X POST -H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
-d '{
"channelUrls": [{ "url": "https://www.youtube.com/@handle" }],
"maxVideos": 0,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}' \
'https://api.apify.com/v2/acts/techforce.global~youtube-full-channel-transcripts-scraper/runs?maxTotalChargeUsd=10'
# 2. Poll
curl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
'https://api.apify.com/v2/actor-runs/<runId>'
# 3. Retrieve when SUCCEEDED
curl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
'https://api.apify.com/v2/datasets/<DATASET_ID>/items?clean=true&format=json'

maxVideos: 0 scrapes the entire channel. maxTotalChargeUsd is the only hard ceiling — never run 0 without it.

Minimal RAG-ingestion configuration

{
"channelUrls": [{ "url": "https://www.youtube.com/@handle" }],
"maxVideos": 0,
"includeTranscriptText": true,
"includeTranscriptSegments": false,
"includeChannelName": true,
"includeDatePublished": true,
"includeViewCount": false,
"includeSubscriberCount": false,
"deliveryMode": "none",
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

Transcript, title, channel and date — the four things a retrieval index actually needs. Every Tier 2 and Tier 3 toggle off, so there is no extra request per video and none per channel. Note that with no Tier 2 toggle on, datePublished may be null; if the date is essential to your index, accept one extra request per video by enabling includeDateText. Pair with a spend cap.

Timestamped segments for clip-finding

{
"channelUrls": [{ "url": "https://www.youtube.com/@handle" }],
"maxVideos": 100,
"includeTranscriptText": false,
"includeTranscriptSegments": true,
"deliveryMode": "none",
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

Segments only, no duplicated plain text — a smaller dataset when you're searching for moments rather than embedding whole documents.

Several channels at once

{
"channelUrls": [
{ "url": "https://www.youtube.com/@channelA" },
{ "url": "https://www.youtube.com/@channelB" },
{ "url": "https://www.youtube.com/@channelC" }
],
"maxVideos": 50,
"includeChannelName": true,
"deliveryMode": "none",
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

Channels are processed one after another; videos within each run in parallel. Every row carries channelName and channelId, so the combined dataset stays separable.

With MCP delivery — one Notion page per transcript part

{
"channelUrls": [{ "url": "https://www.youtube.com/@handle" }],
"maxVideos": 20,
"includeTranscriptText": true,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] },
"mcpConnector": "<your-authorized-notion-connector>",
"mcpTool": "create_page",
"deliveryMode": "chunked",
"mcpArguments": {
"parent": { "page_id": "<YOUR_NOTION_PAGE_ID>" },
"title": "{title} (part {part}/{partCount})",
"content": "{videoUrl} — {language}, {segmentCount} segments\n\n{transcript}"
}
}

chunked is the right default for transcripts — a long video's text will not fit in one Notion page. Avoid perSegment unless you want a record per line: it is one call per segment, per video.

Scheduling for a growing archive

Put a fixed input on a schedule with a modest maxVideos. New uploads appear at the top of a channel's video list, so each run picks them up; de-duplicate against your store on videoId.


⚠️ Autonomous Agent Error Handling & Resolution Matrix

Read this first: almost nothing about the content fails the run. A channel that won't resolve, a video with transcripts disabled, and a record that can't be built are all logged and skipped while the run continues to SUCCEEDED. An agent that checks run status alone will read an empty or short dataset as success-with-data — check the row count and each row's transcriptError.

The CONDITION labels below are documentation handles for observable states. This Actor does not write an error code into the dataset; detect conditions from the run status, the log or the rows.

ConditionWhat you observeUnderlying causeDeterministic agent action
MISSING_CHANNEL_URLSRun rejected at input validationchannelUrls absent — it is required in the schemaModify Input: supply at least one URL.
EMPTY_CHANNEL_URLSSUCCEEDED, empty dataset; log: No channel URLs provided in input. Exiting.The array was present but contained nothing usableModify Input: pass at least one non-empty URL.
CHANNEL_UNRESOLVEDSUCCEEDED; log: Failed to list videos for <url> and that channel contributes no rowsURL isn't a resolvable channel, or the listing was blockedModify Input: use @handle or /channel/ID, or paste any video URL from the channel. Then retry with the residential proxy.
PARTIAL_CHANNEL_FAILUREMulti-channel run with rows from some channels onlyOne channel's listing failed; the loop continuedExpected, partial. Re-run just the failed channel.
BOT_CHECK_BLOCKEDEmpty or thin dataset; sign-in-to-confirm errors in the logDatacenter IP, no proxy passed, or proxy alone insufficientModify Input: RESIDENTIAL group, then add cookies. Lower maxConcurrency to 3.
NO_PROXY_APPLIEDLog startup line shows proxy=disabledproxyConfiguration omitted or empty in a hand-built inputModify Input: pass the proxy object explicitly.
TRANSCRIPT_ERROR_ROWSRows with transcriptError, null transcriptCreator disabled transcripts, or none in any languageExpected, not a failure. The row is a record of the gap. Route to ASR if you must have text.
WRONG_LANGUAGEtranscriptLanguage isn't what you asked forPreference list didn't match; silent fallbackFilter output on transcriptLanguage, or accept the fallback.
AUTO_GENERATED_QUALITYTranscript text has errors, odd punctuationtranscriptIsGenerated: trueFilter on that flag, or clean downstream.
ROW_COUNT_BELOW_VIDEO_COUNTDataset smaller than the Found N video(s) line; log: Failed to build record for <id>Individual records failed to assembleExpected, partial. Re-run those IDs if they matter.
MISSING_FIELD_KEYERRORConsumer crashes on a missing keyThat toggle was off — key is absent, not nullFix consumer: use .get(). Or enable the toggle.
NULL_DATE_PUBLISHEDdatePublished null across rowsNo per-video fetch was triggered, and the listing omitted the timestampModify Input: enable a Tier 2 toggle (e.g. includeDateText) — costs one request per video.
NULL_LIKESlikes null despite the toggleCreator hides likesExpected. Null ≠ zero.
NULL_SUBSCRIBER_COUNTsubscriberCount nullChannel hides it, or the channel fetch failed — log: Could not fetch extended channel metadataExpected. Retry once if the log shows a fetch failure.
RUN_MUCH_LONGER_THAN_EXPECTEDRun still going well past estimatemaxVideos: 0 on a large channel, or many channelsAbort and re-run with a real maxVideos, or wait with a spend cap in place. Rows already saved are kept.
RATE_LIMITED_BY_YOUTUBEIncreasing failures partway throughmaxConcurrency too highModify Input: drop to 38 and retry.
PERSEGMENT_FELL_BACKOne summary call per video instead of per-segment calls; log: perSegment delivery requested for <id> but no timestamped segments are availableincludeTranscriptSegments is offModify Input: enable it, or switch to chunked. Not a failure.
CONNECTOR_RATE_LIMITEDConnector errors partway throughDelivery is per video — perSegment or chunked multiplies the callsModify Input: switch to summary, or lower maxVideos.
CONNECTOR_TOOL_MISSINGLog: A connector is selected but no tool name was providedmcpTool emptyModify Input: set mcpTool. Dataset already saved.
CONNECTOR_TOOL_NOT_FOUNDLog: Tool 'x' is not available on this connector. Available tools: …mcpTool name is wrongModify Input: copy an exact name from that log line. Dataset unaffected.
CONNECTOR_UNREACHABLELog: Could not reach the connector: …Connector not authorised, or the run isn't on the Apify platformAuthorise it in Apify, or set deliveryMode: "none". Data already saved.
MCP_PROXY_MISSINGLog: APIFY_MCP_PROXY_URL is not setRunning locally with apify runReconfigure: apify push and run on the platform.
PROXY_UNAVAILABLELog shows the proxy could not be set upResidential groups require a paid Apify planPrompt user: upgrade the plan; expect bot-wall failures until then.
AUTH_INVALIDHTTP 401Missing or malformed APIFY_TOKENAbort & prompt user: request a valid API token.
RATE_LIMITEDHTTP 429Apify API rate / concurrency limitsRetry: exponential backoff (2s, 4s, 8s).
SYNC_TIMEOUTHTTP 408 on the sync endpointRun exceeded the synchronous ceilingReconfigure: switch to async POST /runs + polling.

Provenance of this table: every log line, status and dataset condition above is taken from this Actor's own source and verified against it. The three HTTP rows (401, 408, 429) describe the Apify API transport layer, not this Actor — confirm them against the Apify API reference before wiring them into automated retry logic.


🗣️ Natural Language → Actor Mapping

A user says…IntentConstructed Actor input
"Get transcripts from this channel"Core{"channelUrls":[{"url":"<url>"}],"maxVideos":10}
"Every video this channel ever posted"Full archive{"channelUrls":[{"url":"<url>"}],"maxVideos":0} + spend cap
"Last 100 videos with transcripts"Recent slice{"channelUrls":[{"url":"<url>"}],"maxVideos":100}
"I need timestamps so I can link to the moment"Segments{"channelUrls":[{"url":"<url>"}],"includeTranscriptSegments":true}
"Build a searchable index of their content"RAG ingestionMinimal config above, maxVideos: 0
"Transcripts in Hindi if available"Language preference{"transcriptLanguages":["hi","en"]} — then check transcriptLanguage
"Only human-written transcripts"Quality filterScrape, then filter transcriptIsGenerated == false
"Which of their videos have no transcript?"Gap auditScrape, then filter rows that have transcriptError
"Compare three channels' topics"Multi-channel{"channelUrls":[{"url":"A"},{"url":"B"},{"url":"C"}],"maxVideos":50}
"Transcripts plus likes and descriptions"Rich metadataEnable includeLikes + includeDescription — one extra request per video
"Full channel stats too"Extended metadataEnable the Tier 3 channel toggles — one shared fetch per channel
"Just a quick sample"Cheap probe{"channelUrls":[{"url":"<url>"}],"maxVideos":3}
"It returned nothing"BlockedRESIDENTIAL proxy, add cookies, maxConcurrency: 3
"Put each transcript in Notion"Scrape + deliverAbove, plus mcpConnector, mcpTool, deliveryMode: "chunked"
"Just this one video's transcript"Single video➡️ Route to YouTube Transcript Scraper
"What are people saying in the comments?"Comment text➡️ Route to YouTube Scraper
"Download their videos"Media➡️ Route to YouTube Shorts Scraper for Shorts; long-form files are out of scope

Should NOT route here: comment threads (→ YouTube Scraper) · search terms or hashtags as input · a single video (→ Transcript Scraper) · creator analytics — watch time, retention, revenue, demographics · downloading video or audio files · translated transcripts · transcripts for videos where the creator disabled them · private, unlisted or members-only videos · uploading or any write operation.


🧭 Agent Execution & Routing Logic

Does the user want what was SAID in YouTube videos?
├── NO → not this Actor.
│ comment threads → YouTube Scraper
│ search / hashtag input → YouTube Scraper
│ a channel's Shorts/files → YouTube Shorts Scraper
│ watch time / revenue → creator's own account only
└── YES
├── One video, or a channel?
│ ├── one video → YouTube Transcript Scraper (also does translation)
│ └── channel → this Actor
├── channelUrls — REQUIRED, an ARRAY.
│ @handle / /channel/ID / /c/ / /user/ / any video URL from the channel
│ several channels? → put them all in the array (processed sequentially)
├── ALWAYS pass proxyConfiguration explicitly at RESIDENTIAL
│ └── still blocked? → add `cookies`, and drop maxConcurrency to 3
├── What transcript shape?
│ ├── embedding / search → includeTranscriptText (default on)
│ ├── deep-links / clips → includeTranscriptSegments (default OFF)
│ └── both → enable both
├── How many videos?
│ ├── a probe → 3
│ ├── a slice → 10-100
│ └── the archive → 0 + ALWAYS a spend cap (can be thousands)
├── Which metadata? (THREE cost tiers — check before toggling)
│ ├── free → channelName, channelId, viewCount, thumbnail
│ ├── per VIDEO → likes, comments, keywords, description, dateText,
│ │ relativeDateText (any one triggers the fetch; all six cost the same)
│ └── per CHANNEL → the six channel toggles share ONE fetch
│ └── need none of them? turn subscriberCount OFF too — it is on by default
├── Language matters?
│ └── set transcriptLanguages, then FILTER on transcriptLanguage afterwards
│ (the list is a preference — fallback is silent)
└── Should transcripts land in another app?
├── yes → mcpConnector + mcpTool + {message} in mcpArguments
│ transcripts are LONG → chunked (recommended)
│ one message each → summary
│ record per line → perSegment (needs segments on; huge call count)
└── no → deliveryMode "none", or leave mcpConnector empty
[Execute Actor]
├──► SUCCEEDED, rows == videos found → assess Transcript Health, then consume
├──► SUCCEEDED, rows < videos found → some records failed to build; read the log
└──► SUCCEEDED, 0 rows → channel unresolved / blocked / no public videos

💰 Cost Control & Pricing Transparency

Billing model: usage-based. This Actor bills for platform usage — the compute time and resources a run consumes — not per row. Current rates are on the Actor's Apify Store page, and the Console shows the live total while a run is in progress.

ChoiceEffect on cost
maxVideosThe main driver. Each video is at least a transcript fetch. 0 is unbounded.
Number of channelsMultiplies everything, and channels run sequentially.
Tier 2 togglesThe second-biggest lever: one extra request per video. Enabling one costs the same as enabling all six.
Tier 3 (channel) togglesOne shared fetch per channel. Negligible for one channel, real for fifty. On by default via includeSubscriberCount.
Tier 1 togglesFree. The data is already fetched; toggling only changes what's written.
maxConcurrencyHigher finishes sooner if you aren't rate-limited. Being limited makes it slower.
includeTranscriptSegmentsNegligible extra fetch cost, but a much larger dataset.
Being blockedCosts run time and returns nothing. A datacenter proxy is the most expensive setting on this page.

Worked examples — relative run shape

Multiply by your account's usage rate from the Store page to get a currency figure.

ScenarioVideosRequests per videoRelative costNotes
Probe — 3 videos, defaults31 transcriptBaselinePlus one channel fetch (subscriber count).
RAG slice — 100 videos, all Tier 2/3 off1001 transcript≈ 33 × baselineThe cheapest shape per video.
Same 100 videos, includeDescription on1001 transcript + 1 metadata≈ 2 × the row aboveOne Tier 2 toggle doubles per-video requests.
Same 100 videos, all six Tier 2 toggles on1001 transcript + 1 metadataSame as the row aboveSix toggles, one fetch — no extra cost.
100 videos with all Tier 3 channel toggles100unchanged≈ RAG slice + one channel fetchChannel toggles are shared and cheap.
Segments instead of text100unchanged≈ RAG slice, larger datasetStorage grows, requests don't.
Three channels × 50 videos1501 transcript≈ 50 × baselinePlus three channel fetches.
Whole channel, maxVideos: 0all of them1 transcriptScales linearly, unboundedNever without maxTotalChargeUsd.
Blocked run (datacenter IP)0 usefulWasted run time, zero rowsThe worst value on this page.

Keeping runs predictable:

  1. First run: one channel, maxVideos: 3. Confirm transcripts are coming back and in the language you expect.
  2. Check the Transcript Health view before scaling. If most rows are auto-generated or in the wrong language, scaling multiplies a corpus you may not want.
  3. Decide the Tier 2 question up front. Either you need per-video metadata and pay one extra request per video, or you don't and you shouldn't enable any of the six.
  4. Turn off Tier 3 entirely if you don't need channel stats — including includeSubscriberCount, which is on by default.
  5. maxVideos: 0 only with a spend cap. A prolific channel is thousands of transcript fetches.
  6. Prefer scheduled incremental runs over one giant archive run — a modest maxVideos on a schedule, de-duplicated on videoId, is cheaper and more resilient than one long run.

🛠️ Troubleshooting

Most problems are transcript availability, proxy, or toggle semantics — not scraper bugs. Work through this table top to bottom; the first three rows account for the large majority of support tickets.

#Symptom you seeMost likely causeFix
1SUCCEEDED but the dataset is emptyThe channel didn't resolve, has no public videos, or the listing was bot-blockedRead the log — Failed to list videos for <url> names it. Use an @handle or /channel/ID, and keep the residential proxy on.
2Thin or empty results that used to workBot check — datacenter IP, or no proxy passed at allConfirm the startup log says proxy=enabled. Pass {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]} explicitly, then add cookies.
3Many rows have transcriptErrorThose creators disabled transcripts, or no track exists in any languageExpected. This Actor reads captions; it does not transcribe audio. Check the Transcript Health view for the overall ratio.
4Transcripts came back in the wrong languagetranscriptLanguages is a preference — the fallback is silentRead transcriptLanguage per row and filter. There is no strict-language mode.
5Text reads like speech-to-text with no punctuationThe source track is YouTube's auto-generated captionCheck transcriptIsGenerated: true. Filter it out, or clean downstream.
6KeyError / undefined on a fieldThat toggle was off — the key is absent, not nullUse .get() / optional access, or enable the toggle.
7datePublished is null everywhereNo per-video fetch was triggered, and the listing omitted the timestampEnable a Tier 2 toggle such as includeDateText — it costs one extra request per video.
8likes is null despite enabling itThe creator hides the like countExpected. Null ≠ zero.
9subscriberCount is nullThe channel hides it, or the channel fetch failed (Could not fetch extended channel metadata)Retry once; if it persists, the channel hides the number.
10Fewer rows than the Found N video(s) lineSome records failed to build — logged as Failed to build record for <id>Partial, not fatal. Re-run those IDs if they matter.
11The run is far slower than expectedmaxVideos: 0, several channels, or a Tier 2 toggle doubling per-video requestsCap maxVideos, or accept the cost. Rows saved so far are kept if you abort.
12Failures increase partway through a big runYouTube is rate-limiting the concurrencyDrop maxConcurrency to 38 and re-run.
13Rows aren't in upload orderVideos are processed in parallel and saved as they finishSort by datePublished client-side (enable a Tier 2 toggle so the date is populated).
14Only one channel produced rows in a multi-channel runOne channel's listing failed; the loop moved onRe-run just that channel with a full URL and the residential proxy.
15You wanted the comments, not the countOnly comments (the count) is availableUse the YouTube Scraper for comment threads.
16You expected translated textThe Actor returns YouTube's published captions untranslatedUse the single-video Transcript Scraper for auto-translation, or translate downstream.
17perSegment produced one message per video instead of per segmentincludeTranscriptSegments was off — the Actor warns and falls back to a summary callEnable segments, or switch to chunked if that was what you wanted.
18Slack / Notion / Linear received nothingDelivery needs both mcpConnector and mcpTool; otherwise it is skipped with a warningSet both. Every dataset row is still saved — your data is never lost.
19Log: Tool 'x' is not available on this connectorWrong tool name for that connectorCopy an exact name from the Available tools: list in the same log line.
20Connector fired, but the message body is emptymcpArguments did not reference {message}Map {message} in mcpArguments and populate mcpMessageTemplate.
21Notion rejects or truncates a long transcriptSingle-call payload exceeded block/timeout capsUse deliveryMode: "chunked" and put {part}/{partCount} in the page title.
22Every Notion page looks identical{part}/{partCount} missing from the title templateAdd them: "{title} (part {part}/{partCount})".
23Far more connector calls than expectedDelivery is per video, and chunked/perSegment multiply itUse summary, or lower maxVideos.
24Delivery fired when you only wanted a datasetdeliveryMode defaults to summary, not noneSet deliveryMode: "none" or leave mcpConnector empty.
25Log: APIFY_MCP_PROXY_URL is not setYou ran locally with apify run; connectors only resolve on the platformDeploy with apify push and run on the platform.
26HTTP 401 / 403Missing, expired, or malformed APIFY_TOKENRegenerate in Apify Console → Settings → API & Integrations, send as Authorization: Bearer <token>.
27HTTP 429Apify account concurrency / rate limits — not YouTube blockingRetry with exponential backoff (2s → 4s → 8s).
28HTTP 408 on run-sync-get-dataset-itemsThe synchronous endpoint has a hard time ceilingSwitch to async: POST /runs → poll /actor-runs/<runId> → fetch dataset.

Diagnostic checklist before opening an issue

  1. Open one of the channel's videos in a browser and check the transcript panel (⋯ → Show transcript). If YouTube shows nothing there, that video has no captions and no scraper can produce them.
  2. Confirm the proxy. The startup log line says proxy=enabled or proxy=disabled. Residential group, paid plan active.
  3. Baseline run: one channel URL, maxVideos: 3, defaults everywhere else, deliveryMode: "none".
  4. Read the Transcript Health view — language, auto-generated flag and error per video, in one table.
  5. Compare the dataset row count with the Found N video(s) log line.
  6. Try cookies from a throwaway logged-in session if the bot check persists.

If the issue survives all six steps, open an Issues ticket on the Actor page (or email support) with the run ID, the channel 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 and public metadata. 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 a third-party channel it is not an option at all — which is the main reason this Actor exists.

Do I need a paid Apify plan?

For reliable runs, yes: the default residential proxy group requires a paid plan, and YouTube serves datacenter IPs a "Sign in to confirm you're not a bot" wall.

When do I need the cookies field?

Only when a residential proxy alone doesn't clear the bot check. Paste a Netscape cookies.txt export from a logged-in session; it is stored as a secret input. Use a throwaway account rather than your primary one — supplying cookies puts that account in scope.

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-full-channel-transcripts-scraper"

Input & scope

What channel URL formats are accepted?

@handle, /channel/ID, /c/name, /user/name, a tab URL like /videos, or any single video URL from the channel — the channel is resolved from it for you.

Can I scrape several channels in one run?

Yes — channelUrls is an array. Channels are processed one after another; videos within each channel run in parallel up to maxConcurrency.

How do I get every video on a channel?

Set maxVideos: 0, which is uncapped per channel. On a prolific channel that is thousands of transcript fetches, so always pair it with maxTotalChargeUsd.

Can I choose the transcript language?

You can express a preference with transcriptLanguages, in priority order. It is not a filter: if no preferred language exists, the Actor returns any available transcript — including auto-generated — without warning per video. Always read transcriptLanguage on each row.

Can it translate transcripts?

No. It returns what YouTube publishes, untranslated. The single-video Transcript Scraper does auto-translation across 13 languages.

Output & fields

Why is a field missing from my rows?

Because its toggle is off. A toggled-off field is an absent key, not a null — use .get() or optional access rather than indexing.

Which toggles cost extra requests?

Three tiers. channelName, channelId, viewCount and thumbnail are free. likes, comments, keywords, description, dateText and relativeDateText trigger one extra request per video — enabling one costs the same as enabling all six. The six extended channel toggles share one fetch per channel between them.

Why is datePublished null?

It is derived from whatever the channel listing returned, and the listing frequently omits the timestamp. Enabling any per-video toggle (for example includeDateText) triggers the full fetch and fills the date in — at the cost of one extra request per video.

What does transcriptError mean?

That this video's transcript could not be retrieved — the creator disabled captions, or none exist in any language. The row is still saved, with transcript null, so your channel inventory stays complete. Its absence means the transcript succeeded.

How do I know if a transcript is auto-generated?

transcriptIsGenerated: true. Machine transcripts carry recognition errors, unreliable punctuation and mangled proper nouns — filter on the flag before quoting or before treating the text as high quality.

Why are there fewer rows than the log's video count?

A video whose record couldn't be assembled is logged as Failed to build record for <id> and skipped. The run still succeeds; compare the dataset size against the Found N video(s) line and re-run those videos if they matter.

Can I get the comments themselves?

No — only the comment count, and only if you enable includeComments. Comment threads are the personal-data-heavy part of YouTube and are deliberately out of scope. Use the YouTube Scraper if you need them.

Can it download the video or audio files?

No. Transcripts and metadata only. For a channel's Shorts as MP4 or audio, use the YouTube Shorts Scraper.

Delivery

What is the MCP connector for?

It pushes each video's transcript straight into a tool you have already authorized on your Apify account — Notion, Slack, Linear, Jira, GitHub, 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?

chunked for transcripts, because a long video's text will not fit in one page or message. summary for short videos, perSegment only when you genuinely want a record per line, none for dataset-only runs. Remember delivery fires per video.

What happens if I pick perSegment without segments?

It does not fail and does not go silent: the Actor logs a warning and sends one summary call for that video instead. Enable includeTranscriptSegments to get real per-segment delivery.

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 is saved as normal.

Limits & pricing

What does it cost?

Usage-based: you pay for the platform usage a run consumes, not per row. The drivers are maxVideos, the number of channels, and whether any per-video metadata toggle is on. Current rates are on the Actor's Apify Store page, and the Console shows a live total while a run is in progress.

How do I stop a run from overspending?

Pass maxTotalChargeUsd on the run endpoint — it is the only hard ceiling — and never run maxVideos: 0 without it. Cache by videoId so scheduled re-runs don't re-fetch what you already have.


🔍 Companion machine-readable files

FileWhat it defines
.actor/input_schema.jsonEvery input and toggle, with types, defaults and bounds
.actor/dataset_schema.jsonAll 25 possible output fields, which toggle each needs, and the four Console views
.actor/output_schema.jsonWhere the run's output is exposed
.actor/actor.jsonActor identity and storage wiring
my_actor/main.pyChannel loop, concurrency, toggle resolution and record assembly
my_actor/connector.pyMCP connector session handling, transcript packing and {placeholder} rendering

If this page and the schema files disagree, the schema files win. They are what the platform validates against at run time; this page is documentation and can lag a release.


Other YouTube Actors

This Actor is the channel-scale transcript specialist: one channel in, every video's words out. Use these siblings when the job is different.

ActorBest forWhy pick it over this one
YouTube Transcript ScraperOne video's timestamped transcript, in 13 languages with auto-translationYou have a single URL, or you need the transcript translated — this Actor returns captions untranslated.
YouTube Scraper: Videos, Channels & CommentsVideo, channel and comment metadata from search queries, channel URLs, video URLs or hashtagsYou need views, likes, comment threads, or discovery by search and hashtag — none of which this Actor's transcripts give you.
YouTube Shorts ScraperA channel's Shorts with engagement metrics and optional MP4/audio downloadYou're working through short-form output, or you need the media files themselves.

Pick by intent: a channel's words → this Actor · one video's words → Transcript Scraper · numbers, comments and discovery → YouTube Scraper · Shorts and their files → Shorts Scraper.

Enrichment & downstream pipeline

ActorUse it for
Advanced Website Crawling ActorCrawl the creator's site, blog or show notes for clean HTML/Markdown/text in the same corpus
Pinterest ScraperPins from searches, boards, profiles and pin URLs
All Jobs ScraperJob listings aggregated across many boards

Suggested pipeline patterns

🔎 Video knowledge base This Actor with maxVideos: 0 for the backfill → the single-video Transcript Scraper for each new upload → store by videoId → index the transcript text for semantic search across everything the channel has 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.

✍️ Content repurposing at scale This Actor → transcript text into your LLM of choice → blog drafts, threads, newsletters → publish through a Notion or Slack connector.

🌍 Multi-channel topic mapping Several channelUrls in one run → cluster transcript text per channel → compare what each creator actually covers rather than what their titles claim.

🤖 Agent retrieval tool Register the Actor as an MCP tool so an agent can pull a channel's corpus on demand and answer questions with links and timestamps.

Browse all Actors by Techforce Global at scraper.techforce.global.


🔐 Compliance & Data Privacy

Trademark & affiliation. 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.

  • Public content only. Everything returned is visible to any signed-out visitor. No private or members-only videos, and no bypassing of authentication.

  • No comment text in the output. Transcripts are the video's spoken content; metadata is content and channel statistics. Comment threads — the part of YouTube that is personal data — are not collected by this Actor. That makes it materially lower-risk than its comment-scraping sibling.

  • But a transcript is speech, and speakers are people. A transcript of an interview or a vlog contains an identifiable person's words, and can contain third parties' names, health details or opinions spoken aloud. Under GDPR / UK GDPR and CCPA/CPRA that content can be personal data about the speaker and about anyone discussed. Treat a transcript corpus as you would any document set containing personal information: a retention policy, access control, and no re-publication of individuals' statements out of context.

  • Special-category content cannot be filtered in advance. Health, politics, religion and sexuality come up in spoken content, and you cannot know which transcripts contain it until after retrieval. Keep retention short and access controlled.

  • Transcripts are copyrighted material. The spoken words of a video are the creator's expression, and YouTube's auto-generated captions are derived from it. Internal research, search and analysis sit on far safer ground than republishing transcripts as your own content or presenting them as an alternative to watching the video.

  • Using transcripts to train a model is a distinct act with distinct risk. Scraping for analysis and ingesting into a training corpus are not the same thing legally, and the licensing position for the latter is contested. If that's your plan, get advice rather than relying on "it was public".

  • Auto-generated transcripts contain errors — don't attribute them as verbatim quotes. transcriptIsGenerated: true means a machine wrote it. Mis-transcribed names and negations can invert meaning. Quoting a machine transcript as something a person said is a misattribution risk, and potentially a defamation one. Check the flag before quoting.

  • YouTube's Terms of Service prohibit automated access, including circumventing access restrictions. This Actor does not remove that risk — it is a risk you accept by running it. Supplying cookies from your own logged-in session also puts your account in scope; use a throwaway account rather than your primary one if you go that route.

  • Attribution over mirroring. videoUrl is on every row. Link back rather than presenting a transcript archive as a substitute for the source, and credit the channel.


🆘 Support & Custom Pipeline Engineering

Need automated multi-city scheduled feeds, webhook enrichment, or enterprise data warehouse syncs?



🏷️ Structured data for search & AI discovery

Two blocks: SoftwareApplication describing the Actor, and FAQPage wrapping the FAQ above so those answers are eligible for rich results. The FAQPage entries are generated from the visible FAQ and match it question-for-question.

{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "YouTube Full Channel Transcripts Scraper",
"alternateName": "YouTube Channel Transcript Scraper",
"applicationCategory": "DeveloperApplication",
"applicationSubCategory": "Web Scraping / Video Transcripts & RAG Ingestion",
"operatingSystem": "Cloud (Apify platform)",
"description": "Scrapes the transcript of every video on one or more YouTube channels — as a single plain-text string, as timestamped {text, start, duration} segments, or both — alongside 19 individually toggleable video and channel metadata fields, without a Google API key, OAuth, or video ownership. Resolves a channel from an @handle, /channel/ID, /c/, /user/ path or any video URL. Reports the language actually retrieved, whether the transcript was auto-generated, and a per-video error when none was available, so gaps are recorded rather than silently dropped. Public captions only, with GDPR/CCPA and speaker-identifiability guidance included. Residential proxy by default with optional cookie support, and optional delivery into Notion, Slack, Linear, Airtable or any MCP connector with chunking for long transcripts.",
"url": "https://apify.com/techforce.global/youtube-full-channel-transcripts-scraper",
"author": {
"@type": "Organization",
"name": "Techforce Global",
"url": "https://www.techforceglobal.com"
},
"provider": {
"@type": "Organization",
"name": "Apify",
"url": "https://apify.com"
},
"offers": {
"@type": "Offer",
"priceCurrency": "USD",
"category": "Pay per platform usage",
"description": "Usage-based: billed for the compute time and resources a run consumes, not per row. Current rates are shown on the Actor's Apify Store page.",
"url": "https://apify.com/techforce.global/youtube-full-channel-transcripts-scraper"
},
"featureList": [
"Transcript for every video on a channel, or the newest N",
"Several channels in a single run",
"Plain-text transcript for embedding and search",
"Timestamped segments for deep-linking to a moment",
"Reports the language actually retrieved, not just the one requested",
"Flags auto-generated transcripts so quality can be assessed",
"Per-video error field so gaps are recorded rather than silently dropped",
"19 individually toggleable metadata fields across three cost tiers",
"Channel resolved from a handle, ID, legacy path or any video URL",
"Residential proxy by default, rotated per video, plus optional secret cookie input",
"Configurable parallelism from 1 to 50 videos at once",
"Rows saved as they are scraped, so aborted runs keep their partial data",
"Optional MCP delivery with chunking for long transcripts",
"Four Console dataset views including a transcript-health view"
],
"isAccessibleForFree": false,
"softwareRequirements": "Apify account and API token; a paid plan for residential proxies",
"keywords": "YouTube channel transcript scraper, bulk YouTube transcripts, video transcripts, RAG ingestion, subtitle extraction, timestamped segments, content analysis, video search index, media research, MCP connector"
}
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Do I need a YouTube or Google account, API key, or OAuth app?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. The Actor reads publicly available caption tracks and public metadata. You need an Apify account and API token; you need no Google credentials whatsoever."
}
},
{
"@type": "Question",
"name": "Is this the official YouTube API?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. This is an independent Actor and is not affiliated with, endorsed by, or sponsored by YouTube or Google."
}
},
{
"@type": "Question",
"name": "Why can't I just use the official YouTube Data API?",
"acceptedAnswer": {
"@type": "Answer",
"text": "captions.download only works for videos you own, via OAuth. For a third-party channel it is not an option at all — which is the main reason this Actor exists."
}
},
{
"@type": "Question",
"name": "Do I need a paid Apify plan?",
"acceptedAnswer": {
"@type": "Answer",
"text": "For reliable runs, yes: the default residential proxy group requires a paid plan, and YouTube serves datacenter IPs a \"Sign in to confirm you're not a bot\" wall."
}
},
{
"@type": "Question",
"name": "When do I need the cookies field?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Only when a residential proxy alone doesn't clear the bot check. Paste a Netscape cookies.txt export from a logged-in session; it is stored as a secret input. Use a throwaway account rather than your primary one — supplying cookies puts that account in scope."
}
},
{
"@type": "Question",
"name": "Can I plug it into Claude, Cursor, or a LangChain agent?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes — it is a native MCP tool: claude mcp add --transport http apify \"https://mcp.apify.com?tools=techforce.global/youtube-full-channel-transcripts-scraper\""
}
},
{
"@type": "Question",
"name": "What channel URL formats are accepted?",
"acceptedAnswer": {
"@type": "Answer",
"text": "@handle, /channel/ID, /c/name, /user/name, a tab URL like /videos, or any single video URL from the channel — the channel is resolved from it for you."
}
},
{
"@type": "Question",
"name": "Can I scrape several channels in one run?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Yes — channelUrls is an array. Channels are processed one after another; videos within each channel run in parallel up to maxConcurrency."
}
},
{
"@type": "Question",
"name": "How do I get every video on a channel?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Set maxVideos: 0, which is uncapped per channel. On a prolific channel that is thousands of transcript fetches, so always pair it with maxTotalChargeUsd."
}
},
{
"@type": "Question",
"name": "Can I choose the transcript language?",
"acceptedAnswer": {
"@type": "Answer",
"text": "You can express a preference with transcriptLanguages, in priority order. It is not a filter: if no preferred language exists, the Actor returns any available transcript — including auto-generated — without warning per video. Always read transcriptLanguage on each row."
}
},
{
"@type": "Question",
"name": "Can it translate transcripts?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. It returns what YouTube publishes, untranslated. The single-video YouTube Transcript Scraper does auto-translation across 13 languages."
}
},
{
"@type": "Question",
"name": "Why is a field missing from my rows?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Because its toggle is off. A toggled-off field is an absent key, not a null — use .get() or optional access rather than indexing."
}
},
{
"@type": "Question",
"name": "Which toggles cost extra requests?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Three tiers. channelName, channelId, viewCount and thumbnail are free. likes, comments, keywords, description, dateText and relativeDateText trigger one extra request per video — enabling one costs the same as enabling all six. The six extended channel toggles share one fetch per channel between them."
}
},
{
"@type": "Question",
"name": "Why is datePublished null?",
"acceptedAnswer": {
"@type": "Answer",
"text": "It is derived from whatever the channel listing returned, and the listing frequently omits the timestamp. Enabling any per-video toggle (for example includeDateText) triggers the full fetch and fills the date in — at the cost of one extra request per video."
}
},
{
"@type": "Question",
"name": "What does transcriptError mean?",
"acceptedAnswer": {
"@type": "Answer",
"text": "That this video's transcript could not be retrieved — the creator disabled captions, or none exist in any language. The row is still saved, with transcript null, so your channel inventory stays complete. Its absence means the transcript succeeded."
}
},
{
"@type": "Question",
"name": "How do I know if a transcript is auto-generated?",
"acceptedAnswer": {
"@type": "Answer",
"text": "transcriptIsGenerated: true. Machine transcripts carry recognition errors, unreliable punctuation and mangled proper nouns — filter on the flag before quoting or before treating the text as high quality."
}
},
{
"@type": "Question",
"name": "Why are there fewer rows than the log's video count?",
"acceptedAnswer": {
"@type": "Answer",
"text": "A video whose record couldn't be assembled is logged as Failed to build record for <id> and skipped. The run still succeeds; compare the dataset size against the Found N video(s) line and re-run those videos if they matter."
}
},
{
"@type": "Question",
"name": "Can I get the comments themselves?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No — only the comment count, and only if you enable includeComments. Comment threads are the personal-data-heavy part of YouTube and are deliberately out of scope. Use the YouTube Scraper if you need them."
}
},
{
"@type": "Question",
"name": "Can it download the video or audio files?",
"acceptedAnswer": {
"@type": "Answer",
"text": "No. Transcripts and metadata only. For a channel's Shorts as MP4 or audio, use the YouTube Shorts Scraper."
}
},
{
"@type": "Question",
"name": "What is the MCP connector for?",
"acceptedAnswer": {
"@type": "Answer",
"text": "It pushes each video's transcript straight into a tool you have already authorized on your Apify account — Notion, Slack, Linear, Jira, GitHub, 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."
}
},
{
"@type": "Question",
"name": "Which delivery mode should I use?",
"acceptedAnswer": {
"@type": "Answer",
"text": "chunked for transcripts, because a long video's text will not fit in one page or message. summary for short videos, perSegment only when you genuinely want a record per line, none for dataset-only runs. Remember delivery fires per video."
}
},
{
"@type": "Question",
"name": "What happens if I pick perSegment without segments?",
"acceptedAnswer": {
"@type": "Answer",
"text": "It does not fail and does not go silent: the Actor logs a warning and sends one summary call for that video instead. Enable includeTranscriptSegments to get real per-segment delivery."
}
},
{
"@type": "Question",
"name": "Does delivery work when running locally?",
"acceptedAnswer": {
"@type": "Answer",
"text": "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 is saved as normal."
}
},
{
"@type": "Question",
"name": "What does it cost?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Usage-based: you pay for the platform usage a run consumes, not per row. The drivers are maxVideos, the number of channels, and whether any per-video metadata toggle is on. Current rates are on the Actor's Apify Store page, and the Console shows a live total while a run is in progress."
}
},
{
"@type": "Question",
"name": "How do I stop a run from overspending?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Pass maxTotalChargeUsd on the run endpoint — it is the only hard ceiling — and never run maxVideos: 0 without it. Cache by videoId so scheduled re-runs don't re-fetch what you already have."
}
}
]
}