YouTube Video Downloader & Scraper - YouTube All-in-One
Pricing
from $135.00 / 1,000 video downloads
YouTube Video Downloader & Scraper - YouTube All-in-One
Download YouTube videos, Shorts, playlists, and channels as MP4. Up to 10 concurrent downloads with no browser needed. Extract comments, captions, and rich metadata. Metadata-only mode for fast, cheap research. Quality selection with automatic fallback. $0.15/video download, $0.005 metadata-only.
Pricing
from $135.00 / 1,000 video downloads
Rating
0.0
(0)
Developer
jy-labs
Maintained by CommunityActor stats
0
Bookmarked
141
Total users
23
Monthly active users
6 days ago
Last modified
Categories
Share
YouTube All-in-One Downloader & Scraper
Turn YouTube URLs, playlists, channels or search queries into structured JSON: title, channel, views, likes, duration, upload date, tags, chapters, category, captions, comments with replies, channel details and related videos. Choose between an LLM-ready transcript row for AI pipelines, metadata-only rows for research, or MP4/M4A file downloads saved to your run's key-value store. The Actor talks to YouTube's InnerTube API through youtubei.js, so no browser is started and no YouTube Data API key is needed. Up to 10 videos are processed in parallel, and you pay per delivered video.
Independent tool. Not affiliated with, endorsed by, or sponsored by YouTube or Google. YouTube is a trademark of Google LLC.
What you get
- Transcripts for AI pipelines. Set
outputFormat: "llm_ready"and each video becomes one flat row with a plain-texttranscript, awordCount, the transcript language, and the core metadata. No file is downloaded. - Rich metadata.
videoId,title,description,channelName,channelUrl,viewCount,likeCount,duration,durationSeconds,uploadDate,thumbnailUrl,tags,category,chapters,isLiveandisShort, plusplaylistIndexandplaylistTitlewhen the video came from a playlist. - Captions and subtitle files. You can get the caption text in the row, an SRT or VTT file in the key-value store, or both. You can prefer a language and optionally have YouTube translate the track.
- Comments with replies. Top comments with author, text, likes, published time and reply count. You can add the reply threads and keep up to 500 comments per video.
- Channel details and related videos. Subscriber count, channel description, banner, video count and join date, plus up to 20 related videos.
- File downloads. Choose
1080p(the default),highest,720p,480p,360poraudio_only. If the resolution you ask for isn't offered, the Actor falls back to the nearest lower one. If its file would be overmaxFileSizeMb, the Actor downloads the highest lower resolution that fits and notes it inqualityFallback. The row'squalityis the delivered format's label, such as720p60, or534pfor a widescreen film. Files are stored in the run's key-value store, and each row links to its file with a signeddownloadUrl. See Limits & notes for what a video file contains. - Batch and incremental runs. You can mix videos, Shorts, playlists, channels and search queries in one run. Duplicates are removed. Monitor mode skips videos that an earlier run already processed.
- Honest billing. You're charged the video download price only when a file is actually delivered. If the metadata arrives but the file doesn't, the row is billed at the metadata price. Failed videos cost nothing.
Quick start
- Click Try for free and paste one or more YouTube URLs into YouTube URLs.
- Pick what you need: a transcript, metadata, or a file download.
- Click Start. Each video becomes one dataset row, and downloaded files go to the run's key-value store.
This is the listing's example input. It returns one transcript row and no file:
{"startUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],"downloadVideo": false,"extractMetadata": true,"outputFormat": "llm_ready","extractCaptions": true,"downloadCaptions": false,"captionLanguage": "en","maxVideos": 1,"proxyConfiguration": { "useApifyProxy": true }}
To download a file, leave downloadVideo on (the default) and choose a quality:
{"startUrls": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"],"quality": "360p","maxVideos": 1}
Before you download. Keep the
RESIDENTIALproxy group (the default). YouTube's bot check blocks most datacenter IPs, so downloads without it mostly fail (details). The defaultquality: "1080p"takes the highest resolution at or below 1080p, in H.264 when YouTube offers it.quality: "highest"can pick an AV1 1440p or 4K stream: a ~120 MB file costs about $1 of residential transfer, and it can exceed the default 200 MBmaxFileSizeMbon longer videos. The Actor then downloads the highest lower resolution that fits, such as 1080p, and the row'squalityFallbacksays so. You get asize_limit_exceededmetadata row only when no lower resolution has a size YouTube reports within the cap (one with no reported size isn't picked in advance), or when the download still overflows mid-way after two step-downs. To keep 4K on long videos, setquality: "highest"and raisemaxFileSizeMb(highestis capped at 500 MB).
Input
At least one of startUrls or searchQueries is required. Everything else is optional.
Key fields
| Field | Default | What it does |
|---|---|---|
startUrls | none | Video, Shorts, playlist or channel URLs, mixed freely |
searchQueries | none | YouTube searches; the videos found are processed too |
outputFormat | default | llm_ready returns a flat transcript row and no file |
downloadVideo | true | false returns metadata-only rows at the metadata price |
quality | 1080p | highest, 1080p, 720p, 480p, 360p, audio_only |
maxVideos | 100 | 1–1000 videos per run, across all URLs and searches |
maxFileSizeMb | 200 | 1–2000. Over it, a lower resolution with a reported size that fits is delivered (qualityFallback); otherwise skipped. Your cap on transfer cost (details) |
extractMetadata | true | false returns only sourceUrl, downloadUrl, videoId, quality, fileSize |
extractCaptions | false | Caption text in captions |
extractComments | false | Top comments in comments |
maxConcurrency | 4 | Videos processed in parallel (1–10) |
proxyConfiguration | Apify, RESIDENTIAL | Groups downloads run on, from the first attempt. Keep RESIDENTIAL (details) |
extractMetadata switches on automatically when you set downloadVideo: false or turn on captions, comments, channel info, related videos, caption files or thumbnails. outputFormat: "llm_ready" also forces extractCaptions: true and downloadVideo: false, and turns off channel info, related videos, thumbnails, comments and caption files, because the transcript row has no field for them.
Captions
captionLanguage(defaulten) is the preferred language code, such asen,ko,jaorpt-BR. In that language, manual captions win over auto-generated ones. If the language isn't available, caption text uses the first manual track (or the first track), and the caption file uses the first track.autoTranslateLanguageasks YouTube to translate the chosen track. If the translated caption text can't be fetched, the original is returned.downloadCaptionsalso saves a caption file and returnscaptionFileUrlandcaptionFileLanguage.captionFormatissrt(default) orvtt.
Comments, channel and related videos
maxComments(default 100, max 500) sets how many top-level comments to take, in YouTube's "Top" order.extractRepliesadds arepliesarray to comments that have replies.extractChannelInfoadds achannelInfoobject. Each channel is looked up only once per run.extractRelatedVideosadds up to 20relatedVideos.downloadThumbnailsaves the thumbnail and returnsthumbnailDownloadUrl.
File names
filenameTemplate (default {videoId}_{type}) accepts {videoId}, {title}, {quality}, {channelName}, {date} (the run date) and {type}. Invalid characters are removed and names are cut to 200 characters. Videos get .mp4 and audio gets .m4a. Caption files are always named {videoId}_captions_{language}.{srt|vtt}.
Monitoring and webhook
- With
monitorModeand astateStoreName, the processed video IDs are kept in that named key-value store, and later runs skip them. Use one store name per job. A video whose file you asked for but didn't get (adownload_failedrow) isn't recorded at first, so the next run tries it again and emits and bills its row again. After its thirddownload_failedrow across runs, the video is recorded and later runs skip it. Asize_limit_exceededrow is recorded, because the size cap is your own setting: later runs skip that video, so to get its file, raisemaxFileSizeMbor lowerqualityand run it without monitor mode or with a newstateStoreName. In monitor mode a spending limit too low for the next download doesn't fall back to metadata rows: the run stops starting videos, charges nothing for them, and the next run tries them again. webhookUrlreceives aPOSTwhen the run finishes, including runs with nothing to process, such as a monitor run that found no new videos. The body containsactorId,runId,processed,downloaded,downloadFailed,sizeLimitExceeded,downloadSkippedByChargeLimit,failed,stoppedByChargeLimit,total,successRate,totalTimeSeconds,avgTimePerVideoSeconds,noNewVideosandcompletedAt.noNewVideosistrueonly when monitor mode skipped every video as already processed. A run that found no valid video, for example because the URLs were invalid, reportstotal: 0withnoNewVideos: false.
Reliability and proxy
maxRequestRetries(default 3, max 10) sets retries per video, with exponential backoff.includeFailedVideosadds rows for videos that delivered nothing.- Downloads start on the groups in
proxyConfiguration(RESIDENTIALby default) from the first attempt. YouTube's bot check blocks about 4 in 5 datacenter exits, and a datacenter try could waste up to about 2.5 minutes per video. With Apify Proxy on and at least one retry allowed, metadata-only andllm_readyruns (and videos a download run delivers asinsufficient_budgetmetadata rows) make the first attempt for each video through Apify's datacenter proxy, which is cheaper and works for metadata, and retry on your groups if it fails. Your proxy country carries over. Custom proxy URLs are used for every attempt. - A download counts as failed when the metadata arrives and the download was tried, but no file arrives. A failed download gets one more attempt at the download, and then the metadata row is returned. A dead proxy exit is different: when every client on that exit gets no response at all and no file bytes have arrived, the Actor moves to a new exit right away, with no backoff. It does this up to 3 times per video, and these attempts don't use up the failed download's one more attempt. After 3 dead exits, the next one counts as a failed download. If an exit dies after file bytes have arrived, it counts as a failed download too.
- Retries follow the reason YouTube gives. Private, deleted, removed, unavailable and members-only videos are never retried. Age-restricted and geo-blocked videos stop after two attempts on your proxy group. YouTube's "Sign in to confirm you're not a bot" check is about the exit IP, not the video, so it is retried on a new exit, up to three attempts on your proxy group. Rate limits and bot checks on your proxy group get longer backoff. An attempt the bot check stops before any download is tried counts toward these three bot-check attempts, not toward a failed download's one more attempt, so a failed download followed by a bot check still gets a new exit. A video never gets more than
maxRequestRetries+ 1 attempts. - Downloads need the
RESIDENTIALproxy group. YouTube answers most datacenter IPs with "Sign in to confirm you're not a bot", for every client and with or without a token, and usually returns no metadata at all. In our test on September 30, 2026, about 4 in 5 Apify datacenter exits got that answer. When an attempt hits the check, the Actor doesn't try the other clients on that exit. On a metadata-only run, a datacenter attempt that hits it moves to your proxy group right away, with no backoff. If your proxy groups are datacenter only (for example{ "useApifyProxy": true }with no group selected), the run log warns at the start, most downloads fail, and each failed row'serrorsays the bot check blocked it and that downloads needRESIDENTIAL. - How a file is fetched. YouTube now stops a normal video stream at about 60 seconds of media unless the request carries a proof-of-origin (PO) token. The Actor starts one BotGuard session per run, through the proxy of the first download that needs it, and mints a token from each video's ID. It then downloads the video and audio tracks over YouTube's SABR streaming protocol, the way the web player does, through the same proxy exit as the rest of that attempt. If this fails, the Actor falls back to the mobile web client with the token (only when YouTube still gives it direct file URLs), then to the iOS client, which mostly helps with Shorts. Starting BotGuard and minting a token each get 30 seconds. If either fails or takes longer, that download goes on without a token. After a failed BotGuard start, the Actor waits 5 minutes before trying again, and it stops trying after 3 failed starts in a run. Metadata-only and
llm_readyruns never mint a token.
Supported URLs
watch?v=ID, youtu.be/ID, /shorts/ID, /embed/ID, /playlist?list=ID, /@handle and /channel/ID. A URL with both v= and list= is treated as that single video.
Output
Each processed video becomes one row in the default dataset. Rows are written as each video finishes, so their order may differ from the order of your input. The dataset has these views: Overview, Full Details, Captions, Comments, Chapters, Related Videos, LLM Ready and Errors.
Default row
This row is from a real quality: "360p" run, shortened. The video's best format was 240p, so the Actor fell back to it:
{"sourceUrl": "https://www.youtube.com/watch?v=jNQXAC9IVRw","downloadUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/jNQXAC9IVRw_video.mp4?signature=…","videoId": "jNQXAC9IVRw","title": "Me at the zoo","description": "…","channelName": "jawed","channelUrl": "http://www.youtube.com/@jawed","viewCount": 438024470,"likeCount": 19954003,"duration": "0:19","durationSeconds": 19,"uploadDate": "Apr 24, 2005","thumbnailUrl": "https://i.ytimg.com/vi/jNQXAC9IVRw/hqdefault.jpg?…","quality": "240p","fileSize": "218.53 KB","captions": [],"comments": [],"tags": ["me at the zoo", "jawed karim", "first youtube video"],"isLive": false,"isShort": false,"chapters": [{ "title": "Intro", "startTime": "0:00", "startTimeSeconds": 0 },{ "title": "End", "startTime": "0:17", "startTimeSeconds": 17 }],"category": "Film & Animation","relatedVideos": []}
quality shows what was actually delivered. It is a height such as 720p for a specific request, best for highest or audio_only, and none when no file was saved. isShort is true only when the input URL used the /shorts/ form. Chapters come from YouTube's chapter markers, or from timestamps in the description if there are none.
Optional fields
These fields are filled when the matching input is on. The values below are illustrative:
{"captions": [{ "language": "English", "languageCode": "en", "text": "We're no strangers to love…" }],"captionFileUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/dQw4w9WgXcQ_captions_en.srt?signature=…","captionFileLanguage": "en","comments": [{"author": "@someone","authorChannelUrl": "https://www.youtube.com/@someone","text": "Still a classic.","likes": 1200,"publishedTime": "2 years ago","replyCount": 14,"replies": [{"author": "@another","authorChannelUrl": "https://www.youtube.com/@another","text": "Agreed.","likes": 30,"publishedTime": "1 year ago"}]}],"channelInfo": {"channelId": "@RickAstleyYT","subscriberCount": "4.5M subscribers","description": "…","bannerUrl": "https://yt3.googleusercontent.com/…","videoCount": "400 videos","joinedDate": "Joined Feb 2, 2015"},"relatedVideos": [{ "videoId": "VIDEO_ID", "title": "…", "channelName": "…", "viewCount": "1.2M views", "duration": "3:24" }],"thumbnailDownloadUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/dQw4w9WgXcQ_thumbnail?signature=…","playlistIndex": 1,"playlistTitle": "My playlist"}
captions holds at most one track: your preferred language, or the fallback described in Captions. If a video has no captions, captions is [] and the rest of the row is still delivered. Counts inside channelInfo and relatedVideos are the text YouTube displays, not numbers.
Metadata-only row (downloadVideo: false)
This is the same shape as the default row, with downloadUrl: null, quality: "none" and fileSize: "". It has no downloadSkippedReason.
LLM-ready row (outputFormat: "llm_ready")
{"videoId": "dQw4w9WgXcQ","title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)","channelName": "Rick Astley","channelUrl": "http://www.youtube.com/@RickAstleyYT","transcript": "We're no strangers to love You know the rules and so do I…","wordCount": 427,"language": "English","languageCode": "en","sourceUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ","duration": "3:33","durationSeconds": 213,"viewCount": 1820844904,"uploadDate": "Oct 25, 2009","category": "Music","tags": ["rick astley", "Never Gonna Give You Up", "nggyu"],"description": "The official video for “Never Gonna Give You Up” by Rick Astley…"}
transcript is the caption text as one plain string. wordCount is the number of words separated by whitespace. language is YouTube's track name. When auto-translate is used, it reads like English → ko and languageCode holds the target language. If a video has no captions, you still get the row, with transcript: "" and wordCount: 0.
Download requested but not delivered
Sometimes the metadata can be read but the file can't be delivered. The usual reasons are that YouTube's bot check blocked the download on every exit tried (see Reliability and proxy), that every streaming client was refused (age restriction, DRM, region lock), or that the file is larger than the size cap and no lower resolution could be delivered within it (see Limits & notes). A refused download first gets one more attempt, as described in Reliability and proxy. A file over the size cap is not retried, because another exit would fetch the same file. If no attempt delivers the file and extractMetadata is on (the default), you still get a full metadata row, billed at the metadata price (shortened here):
{"sourceUrl": "https://www.youtube.com/watch?v=9bZkp7q19f0","downloadUrl": null,"videoId": "9bZkp7q19f0","title": "PSY - GANGNAM STYLE(강남스타일) M/V","channelName": "officialpsy","viewCount": 6076408859,"duration": "4:12","quality": "none","fileSize": "","downloadSkippedReason": "download_failed","category": "Music"}
downloadSkippedReason is download_failed, size_limit_exceeded, or insufficient_budget (your spending limit no longer covered a video-download, so the download was not started; see Spending limit). It appears only on these rows, so you can filter on it. With extractMetadata: false, failed and oversized downloads count as failed instead, and a run whose limit no longer covers a download stops starting videos.
Lightweight row (extractMetadata: false)
{"sourceUrl": "https://www.youtube.com/watch?v=jNQXAC9IVRw","downloadUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/jNQXAC9IVRw_video.mp4?signature=…","videoId": "jNQXAC9IVRw","quality": "240p","fileSize": "218.53 KB"}
Failed row (includeFailedVideos: true)
A failed row means nothing was delivered: no metadata and no file. These rows are never billed.
{"sourceUrl": "https://www.youtube.com/watch?v=VIDEO_ID","downloadUrl": null,"error": "…","status": "failed"}
Pricing
This Actor uses pay-per-event pricing, with no monthly rental. You pay the event prices below, and you also pay the Apify platform usage of your runs: compute, storage and proxy data transfer. These prices are current as of September 2026.
Event prices
| Event | Charged when | Free | Bronze | Silver / Gold / Platinum / Diamond |
|---|---|---|---|---|
video-download | A video or audio file was delivered | $0.15 | $0.1425 | $0.135 |
metadata-extraction | A row was delivered without a file | $0.005 | $0.00475 | $0.0045 |
apify-actor-start | Once per run, per GB of run memory (minimum one) | $0.00005 | $0.00005 | $0.00005 |
Your price tier follows your Apify subscription plan.
Which event a row triggers
video-download: a file was delivered (downloadUrlis set).metadata-extraction: a row without a file. That coversllm_readyrows (even with an empty transcript),downloadVideo: false, and rows withdownloadSkippedReason.- Nothing: failed rows, and videos skipped by monitor mode.
Spending limit. If you set a maximum cost per run, the Actor never delivers a row it can't charge for. It starts a new video only while your limit still covers one more row (a video-download on download runs), counting the videos already in progress. When what is left of your limit is less than one video-download but still covers a metadata-extraction, extractMetadata is on (the default), and monitor mode with a stateStoreName is not on, the Actor stops downloading: each further video is delivered as its metadata row without the file, marked downloadSkippedReason: "insufficient_budget" and billed as metadata-extraction. Like a metadata-only run, these videos make their first attempt through Apify's datacenter proxy (with Apify Proxy on and at least one retry allowed) and move to your groups only if it fails, so they add little residential transfer. The run's status message says how many downloads were skipped this way (downloadSkippedByChargeLimit in the webhook body). To get the files, raise the limit above your tier's video-download price. When the limit can't cover even a metadata row (or, with monitor mode and a stateStoreName, can't cover the next download), the Actor starts no more videos and ends the run with a status message saying how many videos the spending limit stopped (stoppedByChargeLimit in the webhook body). Rows already delivered stay.
Platform usage
Platform usage depends on run memory, run time, and how much data goes through the proxy. For downloads, proxy transfer is by far the largest part.
- Downloads run on the residential proxy. Download runs start on your
RESIDENTIALgroup, because YouTube's bot check blocked about 4 in 5 datacenter exits in our September 30, 2026 test. The PO token a download needs is minted through that same exit, which adds the youtube.com page and the BotGuard script to the residential transfer, usually once per run. On a download run, expanding playlists, channels, and search queries into videos also goes throughRESIDENTIAL, but those are small pages. - Residential transfer costs about $8/GB in our runs (your plan's rate applies), and you pay it as platform usage on top of the event price. A 100 MB file costs about $0.80 of usage on top of the $0.15
video-downloadevent. A 4-minute video at720pwas 27 MB in our test, or about $0.22 of transfer. - To control cost, keep the default
1080por pick720prather thanhighest, which can choose a large AV1 1440p or 4K stream (about $1 of transfer for a ~120 MB file). SetmaxFileSizeMb(1–2000) to the biggest file you're willing to pay transfer for. A video over it comes at the highest lower resolution that fits; a video with no such resolution is skipped and billed as a metadata row.
Metadata-only runs move little data. One metadata-only video took 9 s and under $0.001 of platform usage at 1 GB run memory. Compute scales with memory, so at the default 2 GB expect up to about twice that, under $0.002. These figures are for metadata only, not for downloads. If you only extract metadata or use llm_ready, you can lower memory to 512–1024 MB in the run options to save compute.
Worked examples (Free tier prices)
| Job | Event charges |
|---|---|
| 1,000 transcripts or metadata rows | 1,000 × $0.005 = $5.00 ($4.50 on Silver+) |
| 100 video downloads, all delivered | 100 × $0.15 = $15.00 ($13.50 on Silver+) |
50 downloads: 45 files, 3 download_failed, 2 private | 45 × $0.15 + 3 × $0.005 = $6.765 (private: $0) |
| One run at the default 2 GB memory | apify-actor-start 2 × $0.00005 = $0.0001 |
Platform usage is added on top of every example.
Use cases
- RAG and embeddings. Pull transcripts from a playlist or channel with
llm_ready, split them into chunks, and embed them. Chapters in default mode give natural chunk boundaries. - Training and evaluation datasets. Use
searchQueriesplusllm_readyto collect topic-specific transcripts with title, channel and tags. Export the dataset as JSONL. - Channel and competitor monitoring. Schedule a run on a channel with
monitorModeanddownloadVideo: false. Each run then processes only videos it hasn't seen, and the webhook tells your system when it finishes. - Comment and sentiment analysis. Set
downloadVideo: false,extractComments: trueandextractReplies: true, and feed the threads to your NLP pipeline. - Subtitle files. Set
downloadCaptions: truewithcaptionFormat: "srt"or"vtt". AddautoTranslateLanguagefor a translated track. - Archiving your own content. Download files you own or have permission to store, together with their metadata.
Use via API
The Actor ID is jy-labs/youtube-all-in-one-downloader-scraper. In URLs, use jy-labs~youtube-all-in-one-downloader-scraper. Get your API token from Apify Console → Settings → API & Integrations.
cURL: run and get items in one call
curl -X POST \"https://api.apify.com/v2/acts/jy-labs~youtube-all-in-one-downloader-scraper/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \-H "Content-Type: application/json" \-d '{"startUrls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],"outputFormat": "llm_ready","captionLanguage": "en"}'
The response is the dataset rows as a JSON array. Synchronous runs have a time limit on Apify's side (currently 300 seconds), so for large batches, start the run asynchronously with POST /v2/acts/jy-labs~youtube-all-in-one-downloader-scraper/runs and read the dataset when the run finishes.
JavaScript (apify-client)
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('jy-labs/youtube-all-in-one-downloader-scraper').call({startUrls: ['https://www.youtube.com/playlist?list=PLAYLIST_ID'],outputFormat: 'llm_ready',maxVideos: 50,});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const item of items) {console.log(item.title, item.wordCount);}
Python (apify-client)
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("jy-labs/youtube-all-in-one-downloader-scraper").call(run_input={"startUrls": ["https://www.youtube.com/watch?v=jNQXAC9IVRw"],"quality": "720p","maxFileSizeMb": 100,})for item in client.dataset(run["defaultDatasetId"]).list_items().items:print(item.get("title"), item.get("downloadUrl"), item.get("downloadSkippedReason"))
The same input works from Apify integrations, schedules and webhooks.
Limits & notes
- Every video file has audio. YouTube often serves video and audio as separate streams. When it does, the Actor downloads both and merges them into one
.mp4without re-encoding. The video is MP4: H.264 when YouTube offers it at the chosen resolution, otherwise AV1 (usually above 1080p, sohighestoften gives AV1). The audio is AAC. The size caps below apply to the merged file. A silent file is never saved or billed: if no attempt can get an audio stream, the row getsdownloadSkippedReason: "download_failed"and is billed asmetadata-extraction, notvideo-download. - Size caps. A file may not be larger than
maxFileSizeMb(default 200 MB, at most 2000) or the fixed cap for your quality setting, whichever is smaller. The fixed caps are:360p100 MB,480p150 MB,720p250 MB,1080p400 MB,highest500 MB,audio_only50 MB. With the default settings,720pand above are limited to 200 MB, and ahighestdownload that picks AV1 4K can exceed that on longer videos. When the resolution you asked for is over the cap, explicit ones like1080pincluded, the Actor picks the highest lower resolution whose size YouTube reports within the cap, before downloading anything. The row then carriesqualityFallback: { "requested": "2160p", "delivered": "1080p", "reason": "size_limit" }, itsqualityis the delivered one, and it is billed as a normalvideo-download. A lower resolution with no reported size isn't picked this way. If a stream turns out larger than reported and crosses the cap mid-way, the Actor stops it and tries the next lower resolution, at most twice per video. The video is skipped (size_limit_exceeded) only when no lower resolution has a size YouTube reports within the cap (one with no reported size isn't picked in advance), or when the download still overflows mid-way after two step-downs.audio_onlyhas no lower step: an audio track over the cap is skipped. - Time per attempt. The SABR download gets 60 seconds plus 1 second per MB of the expected file, up to 10 minutes, for the video and audio tracks together. A stalled small file therefore fails in about a minute. The merge then gets 60 seconds. Each fallback client gets 60 seconds for the video stream, another 60 seconds for the separate audio stream, and 60 seconds for the merge. Large files on slow routes can time out. A mid-stream step-down runs the download again within the same attempt with a fresh time budget, so with its two step-downs one attempt can transfer up to three times the size cap and take about three times as long. The fallback clients and one more attempt on your proxy group are tried first, and if they fail the row ends up as
download_failed. - Memory and disk. Every download streams its tracks to temporary files, merges them on disk and uploads the result from the file, so memory use doesn't grow with file size. Each download in progress needs free disk for about twice its file size while its tracks are merged.
- Videos with no file. Private, deleted and unavailable videos give no metadata and become failed rows. Age-restricted, DRM-protected or region-locked videos may still return metadata. In that case they become
download_failedrows after one more attempt on your proxy group. - Playlists and channels. The Actor reads only the first page of results that YouTube returns for a playlist or a channel's Videos tab. Long playlists and big channels can therefore give fewer videos than
maxVideos. Supported channel URLs are@handleand/channel/ID. - Search. Queries run in order, before the URLs, and share the
maxVideosbudget. This means the first query can use up the whole budget. - Shorts found by expanding a playlist, channel or search get
isShort: false, because only/shorts/input URLs are flagged. - Storage. Files are saved in the run's default key-value store and kept for your plan's data-retention period. Copy anything you want to keep. The
downloadUrllinks are signed, so they open without your API token. - Proxy. Turning the proxy off takes downloads off the residential proxy they run on, and YouTube may then block requests. Downloads through datacenter exits alone mostly fail at YouTube's bot check (see Reliability and proxy).
Responsible use and copyright
Download only content you own or have the rights or permission to use. Respect YouTube's Terms of Service, copyright law, and the privacy of commenters. Comments and channel data can include personal data, so handle them according to the laws that apply to you, such as GDPR. You are responsible for how you use the data and files this Actor returns.
FAQ
How do I get only transcripts, as cheaply as possible?
Set outputFormat: "llm_ready". No file is downloaded, and each video is billed as metadata-extraction ($0.005 on the Free tier).
What if a video has no captions?
In llm_ready mode you get the row with an empty transcript and wordCount: 0, billed as metadata. In default mode, captions is [].
Can I get transcripts in another language?
Yes. Set captionLanguage. If that language isn't available, the Actor uses a different track, so check languageCode on the row. To get a translation instead, set autoTranslateLanguage.
What happens when my quality isn't available?
The Actor takes the highest resolution at or below your request. If every format is above your request, it takes the lowest one available. If the file at that resolution is over maxFileSizeMb, it goes down to the highest resolution that fits and sets qualityFallback. The quality field shows what you actually got.
Am I charged for failed videos?
No. Rows with status: "failed" and videos skipped by monitor mode aren't charged. You still pay the platform usage of the run.
Can I get only the new videos from a channel every day?
Yes. Turn on monitorMode, set a stateStoreName, and schedule the Actor. Because channels are read from their first page of videos, schedule often enough that new uploads are still on that page.
Do I need a YouTube API key? No. The Actor doesn't use the YouTube Data API.
Support
Found a bug or need a feature? Open an issue on the Actor's Issues tab and include the run ID. Rows with includeFailedVideos: true and the run log make problems much faster to fix.