YouTube Channel Scraper - Videos, Shorts, Live · Apify
YouTube Channel Scraper (videos, shorts, live) avatar

YouTube Channel Scraper (videos, shorts, live)

Pricing

from $0.30 / 1,000 videos

Go to Apify Store
YouTube Channel Scraper (videos, shorts, live)

YouTube Channel Scraper (videos, shorts, live)

Export a public YouTube channel's videos, Shorts or livestreams: titles, views, duration, publish time and thumbnails. Use handles, channel IDs or URLs; limit results for a small first run, then schedule repeat exports. No YouTube Data API key required.

Pricing

from $0.30 / 1,000 videos

Rating

0.0

(0)

Developer

Murat Uzun

Murat Uzun

Maintained by Community

Actor stats

0

Bookmarked

13

Total users

3

Monthly active users

a day ago

Last modified

Features

Limited permissions

Share

What is YouTube Channel Scraper?

YouTube Channel Scraper reads a public YouTube channel's Videos, Shorts or Live tab and returns one row per video with title, view count, publish time, duration and thumbnail. You do not need your own YouTube Data API key or a browser. Give it a channel ID, an @handle, or a channel URL; export the results or use Apify's schedules, webhooks and API to repeat the workflow. YouTube can still block requests or change its page data, and Apify usage limits apply.

Pricing: YouTube Channel Scraper (videos, shorts, live) costs $0.50 per 1,000 results (pay per result, no subscription; Apify's free plan credit covers small runs).

The Free-plan rate was checked against this Actor's live pricing on October 28, 2026. Other Apify plans have lower per-row rates; see Pricing below and the live pricing tab before running.

Result quality and billing

Only videos with a valid video ID, matching YouTube URL and non-empty title enter the default dataset. Duplicate video IDs are removed within a process attempt. Errors and empty/missing-tab notices are saved as unique DIAGNOSTIC-* records in the default key-value store; OUTPUT summarizes confirmed results, partial failures and diagnostics. They do not generate the default-dataset result event. The Actor start fee and applicable platform usage may still apply; check the live Pricing tab for your plan.

If all attempted channels fail to produce usable data, the run fails. A genuine empty/missing tab can complete with zero results. Interrupted pagination keeps valid videos and a separate diagnostic. An explicitly empty channel list never starts a demo. Result budget is reserved before channel work and writes are serialized. Counters and deduplication apply to one process attempt; migration/restart totals are not inferred.

Try one channel with a small result limit

Paste this into the JSON input, set Maximum cost per run, and run it once:

{
"channels": ["@apify"],
"tab": "videos",
"sortBy": "newest",
"maxVideosPerChannel": 5,
"maxConcurrency": 1
}

Check that at least one row has a videoId, a video url, a title, and no error. A channel may have fewer than five available videos. Export the checked result before increasing the limit.

Use the channel-inventory starter for a downloadable input. For repeat use, the upload-monitor workflow explains scheduling and deduplicating by videoId. In the default mode, scheduled runs can return the same videos again, so deduplicate downstream; the Actor does not promise only unseen uploads. To get only new uploads, turn on the optional upload monitor below.

Videos, Shorts and Live in one run, and only recent uploads

Set Tabs (tabs) to scrape several tabs of every channel in one run, for example ["videos", "shorts", "streams"]. Each tab gets its own limit: maxVideosPerChannel for videos, maxShortsPerChannel for Shorts and maxStreamsPerChannel for the Live tab (both default to the videos limit). A handle is resolved once per channel and shared by all its tabs. Every row's type (video, short, stream) says which tab it came from, and OUTPUT.tabs and OUTPUT.attemptedTabs summarise the run.

Set Only uploads newer than (oldestPostDate) to a date (2026-03-01) or an age (7 days, 2 weeks, 3 months, 1 year) to keep only newer videos and live streams. In the default newest-first order the Actor stops paging at the first older upload, so a weekly run reads only the first page or two. With Sort by: popular it filters instead. The channel grid shows only relative times ("3 weeks ago"), so the cut-off uses publishedAtApprox with YouTube's granularity. Shorts cards carry no upload time and are not filtered. If no upload falls inside the window, the run still succeeds, with zeroResultReason: "NO_VIDEOS_IN_DATE_RANGE" in OUTPUT, and nothing is charged.

{
"channels": ["@mkbhd", "@veritasium"],
"tabs": ["videos", "shorts"],
"maxVideosPerChannel": 20,
"maxShortsPerChannel": 10,
"oldestPostDate": "30 days"
}

Upload monitor: only new uploads (optional)

Off by default. Set onlyNew to true and the Actor keeps a small state record per channel and tab in a named key-value store (stateStoreName, default youtube-channel-scraper-state). The record holds the last 500 video IDs it saw, newest first. On each run the tab is read newest first and that channel stops at the first video ID it already knows, without requesting more pages. Only the new videos are written to the dataset and charged; an unchanged channel returns zero rows and the run still succeeds.

  • First run without state: with baselineOnly: false (default) the channel is scraped normally up to maxVideosPerChannel and the written videos become the state. With baselineOnly: true the current videos are recorded as seen without writing or charging any rows, so the next run returns only uploads published after the baseline.
  • State is saved only after a confirmed dataset write. If the write fails, the state stays as it was; if the state cannot be saved, the run fails so you know the next run may repeat those videos.
  • onlyNew needs newest-first order. sortBy: "popular" together with onlyNew is rejected as an input error before any channel request, and no result is charged.
  • At most maxVideosPerChannel new videos are returned per channel and run. If more were uploaded since the last run, or pagination fails before reaching a known video, the older uploads in that gap are skipped (pagination failures leave a DIAGNOSTIC-* record). Use one stateStoreName per separate monitor; pricing and result events are unchanged.

Example scheduled input, e.g. an Apify schedule with cron 0 */6 * * * (every 6 hours):

{
"channels": ["@apify", "UCX6OQ3DkcsbYNE6H8uQQuVA"],
"tab": "videos",
"sortBy": "newest",
"maxVideosPerChannel": 30,
"onlyNew": true,
"baselineOnly": true,
"stateStoreName": "my-upload-monitor"
}

What data does YouTube Channel Scraper extract?

YouTube Channel Scraper extracts 20 fields per video:

FieldTypeDescription
channelId, channelName, channelUrlstringThe channel that owns the video
subscriberCountText, subscriberCountstring, numberSubscriber count as shown ("517M subscribers") and parsed
videoId, url, title, typestringVideo ID, watch/shorts URL, title, and video/short/stream
viewCountText, viewCountstring, numberView count as shown ("85M views") and parsed
publishedTimeText, publishedAtApproxstringRelative publish time ("7 days ago") and an approximate ISO 8601 date
durationText, durationSecondsstring, numberDuration badge ("23:28") and parsed seconds
thumbnailUrlstringLargest available thumbnail image
descriptionSnippetstringShort description preview, when the tab includes one
isLivebooleanWhether the video/stream is broadcasting live right now
query, error, scrapedAtstringInput value, null error on accepted video rows, scrape timestamp

How to use YouTube Channel Scraper

  1. Paste channels into Channels: an @handle, a channel ID (UCX6OQ3DkcsbYNE6H8uQQuVA), or a full URL all work.
  2. Pick a Tab — Videos, Shorts, or Live (past and current livestreams).
  3. Optionally set Sort by to popular to get the channel's highest-viewed videos first.
  4. Set Max videos per channel and click Start, then export as JSON, CSV, Excel or HTML.

Example input

{
"channels": ["@MrBeast", "@mkbhd"],
"tab": "videos",
"sortBy": "newest",
"maxVideosPerChannel": 100,
"maxConcurrency": 3
}

Example output

{
"channelId": "UCX6OQ3DkcsbYNE6H8uQQuVA",
"channelName": "MrBeast",
"channelUrl": "https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA",
"subscriberCountText": "517M subscribers",
"subscriberCount": 517000000,
"videoId": "gTKS8SAwUzE",
"url": "https://www.youtube.com/watch?v=gTKS8SAwUzE",
"title": "I Survived The Most Extreme Places On Earth",
"type": "video",
"viewCountText": "85M views",
"viewCount": 85000000,
"publishedTimeText": "7 days ago",
"publishedAtApprox": "2026-09-06T00:00:00.000Z",
"durationText": "23:28",
"durationSeconds": 1408,
"thumbnailUrl": "https://i.ytimg.com/vi/gTKS8SAwUzE/hq720_custom_2.jpg",
"isLive": false,
"query": "@MrBeast",
"error": null,
"scrapedAt": "2026-09-13T01:00:00.000Z"
}

Input parameters

ParameterTypeDefaultDescription
channelsarray["@apify"]Channel IDs, handles or URLs, one video per row per channel
proxyModestring"auto"auto, always or never, see Proxy requirement below
proxyConfigurationobjectResidential proxyWhich proxy group to use when proxyMode needs one
tabstring"videos"videos, shorts or streams (the channel's Live tab)
tabsarray—Several tabs in one run, e.g. ["videos","shorts","streams"]; overrides tab
oldestPostDatestring—Only uploads on or after a date (2026-03-01) or within an age (7 days); videos and streams
sortBystring"newest"newest or popular (best-effort; falls back to newest)
maxVideosPerChannelinteger100Cap per channel (1-5000)
maxShortsPerChannelinteger= max videosShorts limit per channel when shorts is scraped
maxStreamsPerChannelinteger= max videosLive-tab limit per channel when streams is scraped
maxConcurrencyinteger3Channels scraped in parallel (1-10)
onlyNewbooleanfalseUpload monitor: write and charge only videos not seen before, see Upload monitor
stateStoreNamestring"youtube-channel-scraper-state"Named key-value store for upload-monitor state
baselineOnlybooleanfalseWith onlyNew, record a first-run baseline without writing or charging rows

Proxy requirement

Passing a channel ID (UC...) needs no extra request at all. Passing a handle (@apify) or a legacy /c///user/ URL costs one extra request to read that channel's page and pull its UC... ID out of the HTML — and that specific request can get YouTube's "Sign in to confirm you're not a bot" page (or Google's "unusual traffic" captcha wall) when it comes from an Apify platform (datacenter) IP. The Proxy mode input controls the response: Auto (default) tries that request directly first — $0 proxy cost — and only switches to Apify Proxy (see Proxy configuration) for the rest of the run if it gets blocked; Always skips straight to the proxy; Never always stays direct. The channel's /browse data itself is never proxied (no report of it being blocked).

Pricing

YouTube Channel Scraper uses pay-per-event pricing: $0.0005 per video row on the Free plan, or $0.50 per 1,000 video rows. Paid Apify plans get lower per-row rates; see the live Pricing tab for the current rate on your plan. There is also an actor-start event priced at $0.00005 per event; Apify applies one event per GB of Actor memory, with a minimum of one. These rates were checked on October 28, 2026; the live pricing tab is authoritative. Set Maximum cost per run before starting.

Handle resolution can use Apify Proxy when direct requests are blocked (see Proxy requirement above). Check the live pricing tab for what platform usage is included. Post-run dataset access and storage can incur standard Apify charges; see Apify's pricing-model explanation. Proxy use does not guarantee that YouTube will accept every request.

YouTube Channel Scraper vs. the YouTube Data API

The official YouTube Data API is a good alternative if you can maintain an API integration. You can get a channel's uploads playlist and page through it with playlistItems.list, which costs one quota unit per call and returns up to 50 items. You do not need a search request for every upload. Choose this Actor when you want the public Videos, Shorts or Live-tab workflow, normalized output and Apify scheduling/export without maintaining that integration. It is not a guarantee against YouTube blocking or future changes.

Using YouTube Channel Scraper with AI agents and MCP

YouTube Channel Scraper is pay-per-event with limited permissions — the two requirements for an Actor to be callable through the Apify MCP server at mcp.apify.com. An agent passes channels and tab and gets back one structured row per video, ready for a content-monitoring or competitor-research step. The same run works from n8n, Make, Zapier and LangChain through Apify's integrations.

Need bulk volume or a custom scraper?

Need a fixed monthly price, a large recurring run, extra output fields, or a scraper for a site this Actor does not cover? Open an issue on this Actor's Issues tab and include: the target site or URL pattern, the expected volume per run and how often you run it, and the output fields you need. We reply there.

Run it from code

JavaScript (npm install apify-client):

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('webdatatools/youtube-channel-scraper').call({
channels: ['@apify'],
tabs: ['videos', 'shorts'],
maxVideosPerChannel: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const v of items) console.log(v.type, v.publishedTimeText, v.title);

Python (pip install apify-client):

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('webdatatools/youtube-channel-scraper').call(
run_input={'channels': ['@apify'], 'maxVideosPerChannel': 20, 'oldestPostDate': '30 days'},
)
for item in client.dataset(run['defaultDatasetId']).iterate_items():
print(item['title'], item['viewCount'], item['url'])

CLI (npm install -g apify-cli, then apify login):

$echo '{"channels":["@apify"],"maxVideosPerChannel":10}' | apify call webdatatools/youtube-channel-scraper --output-dataset

MCP (Claude Desktop, Cursor, VS Code): add https://mcp.apify.com/?tools=webdatatools/youtube-channel-scraper as an MCP server with your Apify token as a Bearer header, then ask for example "List the last 30 days of uploads from @veritasium, Shorts included."

Diagnostic codes and run outcomes

Rows that are not usable videos are never written or charged. Each one is saved as a DIAGNOSTIC-* record in the default key-value store with errorCode and a plain-English error:

errorCodeMeaning
INVALID_CHANNEL_INPUT / CHANNEL_RESOLUTION_FAILEDThe channel input could not be turned into a channel ID
BROWSE_REQUEST_FAILEDYouTube did not answer the channel page request
NO_MATCHING_TAB / EMPTY_TABThe channel has no such tab, or it is empty (not a failure)
NO_VIDEOS_IN_DATE_RANGENo upload inside oldestPostDate (not a failure)
CONTINUATION_FAILED / UNRECOGNISED_CONTINUATION / UNRECOGNISED_LAYOUTPaging or layout problem; earlier videos are kept
STOPPED_FOR_TIMEThe run time limit stopped paging; earlier videos are kept
STATE_WRITE_FAILED / DATASET_DELIVERY_UNCONFIRMEDStorage problem; the run fails so you notice

OUTPUT counts results, diagnostics, attempted channels and tabs, and the run-time-limit source (ACTOR_TIMEOUT_AT, or the run's own timeout option when that variable is missing). A run with saved videos succeeds. A run with no videos succeeds when the reason is benign, and states it as zeroResultReason: NO_NEW_UPLOADS, BASELINE_SAVED, NO_VIDEOS_IN_DATE_RANGE, EMPTY_TAB, CHARGE_LIMIT or RUN_TIME_LIMIT. It fails when every channel failed, the input is invalid, or storage could not be confirmed.

FAQ

How much does a typical run cost? You pay per saved video row: $0.0005 on the Free plan ($0.50 per 1,000), less on paid plans, plus a start fee of a fraction of a cent. 10 channels x 30 videos = 300 rows = about $0.15. Diagnostics, empty tabs, filtered-out older uploads and, in upload-monitor mode, already-seen videos are never charged. Set Maximum cost per run: the Actor reserves the budget before each channel tab, so parallel work never overspends.

Why is descriptionSnippet always null? YouTube's current channel-grid response (the "lockup" card format) does not send a description preview for grid items, unlike the older per-video card. It is kept as a field for forward compatibility if YouTube adds it back.

How is publishedAtApprox calculated? YouTube only ever sends a relative label ("7 days ago"), never an absolute date, on this page. The Actor subtracts that duration from the scrape time — treat it as approximate, not exact.

What happens if a channel has no Shorts or Live tab? That channel returns a single row with error explaining the tab was not found, instead of failing the whole run.

Is this legal to run? Yes. The Actor reads the same public channel pages a logged-out visitor's browser loads, and does not require or bypass any login.

Can I export to CSV or Excel? Yes, from the Output tab or the API, with a ready-made Overview view.

Part of the webdatatools web-intelligence suite — every Actor is pay-per-event, reads public data without a login, and returns one clean row per entity:

Browse the whole suite at webdatatools, or call ten of these Actors straight from Claude, Cursor or Cline with the webdatatools MCP server.

Website & domain intelligence

Content for AI, LLMs and RAG

Search, video and social

Leads, jobs and company data

Developer, app and research data

Support and feedback

Found a channel layout this Actor doesn't handle, or a parsing bug? Open an issue on the Issues tab.

If this Actor is useful to you, you can leave a review on its Apify Store page. Nothing is offered in return.