YouTube Channel & Video Scraper
Eimantas V · @amethyst
Scrape YouTube channels and videos without a browser: subscriber counts, full video lists, exact view counts, durations, publish dates, keywords, and optional likes and comment counts.
About
YouTube Channel & Video Scraper
Channel stats and full video lists with exact view counts — no browser, no API key, no quota.
@mkbhd Marques Brownlee 21.1M subscribers · 1.8K videos
6 recent uploads · median 3,642,713 views · uploading every 7 days
Google Pixel 11/Pro/Fold Impressions 1,562,071 views 11:14 14 hours ago
Galaxy Z Fold 8 Review: Honeymoon's Over 4,097,984 views 11:35 12 days ago
Framework 13 Pro: The Modular Laptop 3,187,441 views 12:48 2 weeks ago
One channel with 6 videos: 8 requests, 0.4 MB, 0.8 seconds.
Why it is fast and cheap
Most YouTube scrapers load the page in a headless browser. This one calls the same internal API youtube.com calls from your browser, and the difference is not small: a watch page is 1.25 MB of HTML wrapped around 16 KB of data. Reading the data directly makes runs roughly eighty times lighter, which is why the price below is what it is.
What you get
Per channel — channelId, handle, title, description, keywords, subscriberCount, videoCount, avatarUrl, rssUrl, plus rollups over the videos returned: medianViewsScraped and uploadIntervalDays, the mean gap between uploads.
Per video
| Group | Fields |
|---|---|
| Reach | viewCount, viewCountIsExact, viewsPerDay, viewCountText |
| Engagement | likeCount (exact), commentCount, likesPerThousandViews — opt-in |
| Timing | publishedAt, publishedText, daysSincePublished |
| Content | title, descriptionSnippet, keywords, category, durationSeconds |
| Format | isShort, isLive, thumbnailUrl |
viewsPerDay is the one that matters for comparison. A three-year-old video with 4M views and a three-week-old video with 4M views are not the same result, and raw view counts cannot tell you which is winning.
Who this is for
- Influencer marketing — vet creators before you pay them. Subscriber count is vanity;
medianViewsScrapedagainstsubscriberCountshows how many people actually watch, anduploadIntervalDaysshows whether the channel is still active. - Content strategy — pull a competitor's last 200 uploads, sort by
viewsPerDay, and read what worked. - Trend research —
keywordsandcategoryacross a set of channels, refreshed daily. - Media monitoring — watch specific channels for new uploads with
publishedWithinDays: 1.
Pairs with the TikTok Creator Scraper: same buyer, the other half of the picture.
Input
{
"channels": ["@mkbhd", "@MrBeast"],
"maxVideosPerChannel": 100,
"publishedWithinDays": 90
}
Accepts handles, channel URLs, UC… ids, legacy /c/ and /user/ paths, and — for videos — watch, youtu.be, /shorts/ and /live/ links.
| Option | Default | Notes |
|---|---|---|
maxVideosPerChannel | 50 | Your main billing guard. 0 = channel stats only |
includeShorts | false | Separate tab. Shorts carry no duration or date of their own — those need exactVideoStats |
publishedWithinDays | — | Applied after fetching; YouTube's tab has no date filter |
exactVideoStats | true | Exact views and timestamps; one small request per video |
includeEngagement | false | Likes and comments — ~25× the data |
includeDescription | false | Off keeps the dataset far smaller |
language / country | en / US | Affects display text and region-restricted videos |
Four things worth knowing
Each was measured against live channels.
Subscriber counts are rounded, and that is YouTube's doing. The site itself publishes "21.1M subscribers" — the exact number has not been public since 2019. subscriberCount is that text parsed to 21100000, and subscriberCountText keeps the original so you can see it is rounded. Any tool quoting an exact subscriber figure is inventing precision.
View counts are exact, but only if you ask — and only if YouTube agrees. A channel listing gives "1.5M views"; resolving the video gives 1584034. exactVideoStats is on by default and costs one 16 KB request per video.
YouTube sometimes answers that request without describing the video, which datacenter addresses see routinely. When it does the Actor tries a second client, and if that is also refused it keeps the rounded listing figure rather than inventing one.
Two fields tell you exactly what you got, and they are deliberately separate:
viewCountIsExact— whetherviewCountis the real number. It can be true even when the video lookup failed, because turning on engagement recovers the exact count from that payload.publishedText— when it is set,publishedAtwas estimated from wording like "2 weeks ago". Videos the lookup did describe have an exact timestamp and nopublishedText.
keywords and category come only from the video lookup, so they are empty when it is refused. The run log reports both gaps separately.
Likes cost 25× more than everything else. The like total is not in the cheap endpoint — fetching it means a second request that is roughly 400 KB against 16 KB. That is why includeEngagement is off by default. Comment counts are rounded by YouTube itself: "2.4M" is as precise as the site is.
Publish dates are exact where possible, approximate otherwise. With exactVideoStats you get a real timestamp. Without it, "2 weeks ago" is anchored to the coarsest unit YouTube gave, and publishedText always carries the original wording so you can tell which you are looking at.
Output
{
"recordType": "video",
"videoId": "Z6z_feacXW8",
"channelTitle": "Marques Brownlee",
"title": "Galaxy Z Fold 8 Review: Honeymoon's Over",
"viewCount": 4097984, "viewCountText": "4M views",
"durationSeconds": 695, "durationText": "11:35",
"publishedAt": "2026-08-01T…", "publishedText": "12 days ago",
"daysSincePublished": 12, "viewsPerDay": 341499,
"category": "Science & Technology", "isShort": false
}
Three ready-made views: Videos, Channels and Engagement. Set flattenOutput: true for CSV.
Honest limits
- No transcripts. YouTube stopped serving caption tracks to anonymous clients; the endpoint returns zero bytes. Anything offering bulk transcripts is running a browser fleet or an authenticated session.
- No comment text. Only the count, and only when engagement is enabled.
- Subscriber counts are rounded. See above.
- Region-restricted videos will not resolve outside their country. Set
countryto reach them. videosScrapeddescribes this run, not the channel. A cap of 10 gives cadence and median over the last 10 uploads, not the channel's lifetime.- A private, deleted or age-restricted video returns
VIDEO_NOT_FOUNDand is not charged. Failed rows carry no figures at all — a row that says it could not read the video will never also report a like count. viewCountIsExact: falsemeansviewCountcame from YouTube's rounded display text. See above.- Empty
keywordsand a nullcategorymean the per-video lookup was refused for that row;publishedAtis estimated in that case too.
Pricing
| Event | Price | When |
|---|---|---|
| Actor start | $0.005 | Once per run |
| Channel scraped | $0.004 | Per channel profiled |
| Video scraped | $0.0003 | Per video returned, after filters |
$0.30 per 1,000 videos. Tracking 50 creators with their 20 most recent uploads costs about $0.51. Channels and videos that cannot be resolved are never charged.
Tips
- Rank by
viewsPerDay, notviewCount. It is the only fair comparison across videos of different ages. medianViewsScraped ÷ subscriberCountis the number influencer marketers actually want: what share of an audience shows up.uploadIntervalDaysclimbing run over run means a channel is slowing down — usually before its view counts show it. It is null whenever some returned video has no date, because a gap measured across undated uploads reads far slower than the channel really is.- Scraping a Shorts-heavy channel without a proxy? A Shorts thumbnail carries no date, and
/playeris what supplies one. If the log says videos could not be resolved individually, turn on the proxy — orincludeEngagement, which reads the date off the watch page instead. publishedWithinDays: 1with a daily schedule is a cheap new-upload feed across a whole competitive set.- Leave
includeEngagementoff unless you specifically need likes. It is the single biggest cost lever in this Actor.
FAQ
- Why do some videos have rounded view counts?
- YouTube does not give exact view counts or full video details to the default Bytewells network. Those rows come with viewCountIsExact: false and a count read from text like "1.5M views", and have no keywords or category. For exact counts, keywords and categories, set Proxy configuration to Residential in the input. The proxy traffic is billed to your Bytewells credits, about 1 cent per 100 videos.
Input
Preview of the input form. Rent the Actor to fill it in and start runs from the console.
channelsHandles, URLs or channel ids, one per line: '@mkbhd', 'https://www.youtube.com/@mkbhd', 'UCBJycsmduvYEL83R_U4JriQ'. Old /c/ and /user/ URLs work too.
videosVideo URLs or 11-character ids. Accepts watch, youtu.be, /shorts/ and /live/ links. Use this when you want specific videos rather than a whole channel.
startUrlsAlternative to Channels and Videos, for feeding output from another Actor straight into this one.
sourceDatasetIdRead channel or video identifiers from an existing dataset instead of typing them.
sourceDatasetFieldWhich field on the source dataset holds the identifier.
maxVideosPerChannelHow many recent uploads to return per channel. YouTube serves 30 per page, so this is your main billing guard. Set 0 to fetch channel statistics only and no videos at all.
includeShortsAlso read the channel's Shorts tab, which YouTube keeps separate from regular uploads. Each returned Short carries isShort: true. A Shorts thumbnail shows no duration and no date, so those come only from "Exact view counts and dates"; without it a Short's durationSeconds and publishedAt are null.
publishedWithinDaysKeep only recent uploads. Applied after fetching, because YouTube's channel tab has no date filter. 0 keeps everything.
exactVideoStatsResolve every video individually to get its exact view count and an exact publish timestamp. Without this you get YouTube's rounded display text — '1.5M views', '2 weeks ago' — which is cheaper but imprecise. Adds one small request per video.
includeEngagementFetch each video's like total and comment count. This needs a second, much larger request per video — roughly 25 times the data — so it makes runs slower and more expensive. Comment counts are rounded by YouTube itself.
includeDescriptionStore each video's full description. Off by default because descriptions dominate dataset size; a 300-character snippet is always included.
languageTwo-letter code used for YouTube's display text, e.g. 'en', 'de', 'es'. Affects the wording of relative dates and view counts, not the numbers.
countryTwo-letter code for the storefront YouTube serves, e.g. 'US', 'GB'. Some videos are region-restricted and will not resolve outside their country.
maxConcurrencyChannels processed in parallel. Responses are small, so this can be raised comfortably.
requestTimeoutSecsPer-request timeout.
maxRetriesRetries for connection resets and 5xx responses.
flattenOutputEmit flat dot-notation columns with arrays joined by ' | '. Use for spreadsheets; leave off for warehouses.
proxyConfigurationOptional. YouTube's own endpoints serve this data to anonymous clients, so a proxy is only worth enabling for very large runs or to read a specific country's catalogue.
API
Bytewells speaks the Apify API. Existing integrations keep working: point apify-client at https://bytewells.com/api and use your Bytewells API token (Console → Settings → API access). The Actor ID is amethyst/youtube-channel-scraper (or amethyst~youtube-channel-scraper in URLs).
JavaScript · apify-client
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({
token: process.env.BYTEWELLS_TOKEN,
baseUrl: 'https://bytewells.com/api',
});
const input = {
"channels": [
"@mkbhd",
"@MrBeast"
],
"sourceDatasetField": "channelUrl",
"maxVideosPerChannel": 50,
"includeShorts": false,
"publishedWithinDays": 0,
"exactVideoStats": true,
"includeEngagement": false,
"includeDescription": false,
"language": "en",
"country": "US",
"maxConcurrency": 8,
"requestTimeoutSecs": 45,
"maxRetries": 2,
"flattenOutput": false,
"proxyConfiguration": {
"useApifyProxy": false
}
};
const run = await client.actor('amethyst/youtube-channel-scraper').call(input);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);Python · apify-client
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["BYTEWELLS_TOKEN"], api_url="https://bytewells.com/api")
run_input = {
"channels": [
"@mkbhd",
"@MrBeast"
],
"sourceDatasetField": "channelUrl",
"maxVideosPerChannel": 50,
"includeShorts": False,
"publishedWithinDays": 0,
"exactVideoStats": True,
"includeEngagement": False,
"includeDescription": False,
"language": "en",
"country": "US",
"maxConcurrency": 8,
"requestTimeoutSecs": 45,
"maxRetries": 2,
"flattenOutput": False,
"proxyConfiguration": {
"useApifyProxy": False
}
}
run = client.actor("amethyst/youtube-channel-scraper").call(run_input=run_input)
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)HTTP · curl
curl -X POST "https://bytewells.com/api/v2/acts/amethyst~youtube-channel-scraper/runs" \
-H "Authorization: Bearer $BYTEWELLS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"channels":["@mkbhd","@MrBeast"],"sourceDatasetField":"channelUrl","maxVideosPerChannel":50,"includeShorts":false,"publishedWithinDays":0,"exactVideoStats":true,"includeEngagement":false,"includeDescription":false,"language":"en","country":"US","maxConcurrency":8,"requestTimeoutSecs":45,"maxRetries":2,"flattenOutput":false,"proxyConfiguration":{"useApifyProxy":false}}'Runs are billed as compute from your credit balance. Paid Actors need an active rental or trial; otherwise the API answers 402 rental-required.
Related
More Actors from the same publisher.

Facebook Ads Library Scraper - Meta Ads, All Countries
Eimantas V · @amethyst
Scrape the Facebook Ads Library by keyword, Page or Ad Library link, in any country: ad copy, images and videos, landing pages, CTAs, run dates, platforms and the advertiser Page with its likes. Political ad spend included. No login, no token.
MarketingSocial mediaBusiness$29/mo7-day free trial
Instagram Profile Scraper - Followers, Posts & Emails
Eimantas V · @amethyst
Scrape Instagram profiles by username, URL or ID: exact followers, following and post counts, bio, links, emails and phones from the bio, category, verified and business flags, engagement rate, 12 latest posts and related profiles. No login. From $1.60 / 1,000.
Social mediaLead generationMarketing$19/mo7-day free trial
Google Search Results Scraper - SERP API
Eimantas V · @amethyst
Scrape Google search results by keyword or URL: organic results with real URLs and ranks, places, top stories, knowledge panel, related searches, News and Videos tabs. Optional AI Overview, People also ask and ads. Any country, language or city. From $0.40 per 1,000 pages.
SEO toolsMarketingLead generation$19/mo7-day free trial
Twitter / X Scraper - Tweets, Profiles & Engagement
Eimantas V · @amethyst
Scrape tweets from any public Twitter / X account by handle or URL. Full text, likes, retweets, replies, quotes, bookmarks and view counts, plus hashtags, mentions, expanded links, images and playable video URLs. Retweets carry the original post's engagement. No API key, no browser.
Social mediaLead generationAutomation$19/mo7-day free trial