YouTube Channel Scraper – Videos, Views & Likes
Pricing
from $0.50 / 1,000 videos
YouTube Channel Scraper – Videos, Views & Likes
Scrape the latest videos from any public YouTube channel — title, link, exact view count, likes, publish date, duration, description and thumbnail — one row per video. No login, no cookies, no API key and no browser: a channel listing costs one request. Unofficial.
Pricing
from $0.50 / 1,000 videos
Rating
0.0
(0)
Developer
Simple Actors
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Scrape the latest videos from any public YouTube channel — title, link, exact view count, likes, publish date, duration, description, category and thumbnail — one row per video. Built for channel monitoring, competitor and content research, influencer vetting and video dataset building.
No login, no cookies, no API key and no browser. Everything on a channel listing is in a JSON object inside the page YouTube serves to a logged-out reader, so a whole channel costs one request.
Unofficial. Not affiliated with, endorsed by, or sponsored by YouTube or Google.
Features
- Latest videos per channel — up to 30, newest first, read from the page YouTube serves a logged-out reader.
- Exact view counts and publish instants — not YouTube's rounded "53K views" and "3 days ago", but 53,674 and the real timestamp.
- Like counts, descriptions and categories — which appear nowhere on the channel listing.
- Every address form works —
@handle,/channel/UC…, and the legacy/c/and/user/forms, so a list saved a decade ago still resolves. - Bare handles and channel IDs accepted — paste a spreadsheet column straight in.
- Channel context on every row — name, id, handle, subscriber count and the channel's total video count, so you can tell 30-of-30 from 30-of-6,100.
- Rounded figures are always labelled —
viewCountIsApproximateandpublishedAtIsApproximatemean you are never silently misled. - A cheap freshness mode — turn details off and a whole channel is one request.
- Incremental polling —
onlyVideosNewerThantakes7 days,3 monthsor an ISO date, and refuses rather than returning a misleading short list. - No browser, 256 MB — fast and light.
- Runs stay green. A nonexistent channel or a pasted video URL is a row.
Input
{ "handles": ["NASA"], "maxVideos": 30 }
All four of YouTube's address forms work, so a list saved at any point in the last decade still resolves:
{"startUrls": [{ "url": "https://www.youtube.com/@NASA" },{ "url": "https://www.youtube.com/channel/UCLA_DiR1FfKNvjuUpBHmylQ" },{ "url": "https://www.youtube.com/user/NASAtelevision" }]}
| Field | Type | Default | What it does |
|---|---|---|---|
startUrls / handles | array | — | The channels. handles also takes bare handles (NASA) and channel IDs (UCLA_…). |
maxVideos | integer | 30 | Newest first. 30 is the ceiling — see What it cannot do. |
includeVideoDetails | boolean | true | Exact views, likes, description and publish date. One request per video, and what the price turns on — see What it costs. |
onlyVideosNewerThan | string | — | 7 days, 3 months, or an ISO date. |
proxy | object | Apify datacenter | What it is built and measured on. Residential is available but rarely worth it — see below. |
Output
{"type": "video","videoId": "FkgVB19I6xw","url": "https://www.youtube.com/watch?v=FkgVB19I6xw","title": "NASA's Roman Space Telescope: A New Perspective on the Cosmos","viewCount": 53674,"viewCountIsApproximate": false,"likeCount": 1839,"publishedAt": "2026-08-24T21:00:22.000Z","publishedText": "3 days ago","publishedAtIsApproximate": false,"durationSeconds": 46,"category": "Science & Technology","thumbnailUrl": "https://i.ytimg.com/vi/FkgVB19I6xw/hq720.jpg","channelName": "NASA","channelId": "UCLA_DiR1FfKNvjuUpBHmylQ","channelHandle": "@NASA","subscriberCount": 15100000,"channelVideoCount": 6100,"scrapedAt": "2026-08-28T15:40:29.000Z"}
Store channelId, not the handle. A channel's owner can change its handle;
the UC… id never changes.
Exact figures, and when you get them
YouTube rounds everything it displays. A channel listing says "53K views" and
"3 days ago" — 53,674 and 53,001 both print as 53K. The exact numbers live only
on each video's own page, which is what includeVideoDetails fetches, along
with the like count and description that exist nowhere else.
About 92% of those reads land. YouTube refuses some from datacenter addresses; the Actor retries each up to six times on fresh ones, which took the rate from 60% to 92% measured across 100 videos on ten channels. Residential lifts the last 8% at roughly ten times the cost per video, which is rarely worth it.
You are never misled. Every row says which figures it got:
viewCountIsApproximate | likeCount | |
|---|---|---|
| exact figures read | false | a number |
| listing figures only | true | null |
A video with no public view count at all — a members-only upload, say —
comes back with viewCount: null and viewCountIsApproximate: null. A null
flag means there is no figure to describe, not a rounded one waiting to be
improved.
How to use
From Apify Console
- Open the Actor and click Try for free / Start.
- Paste channel addresses into Channels, or a column of bare handles and channel IDs into Channels (plain list) — both are read together. Give a channel, not a video.
- Leave Exact views, likes and dates on for real figures, likes, descriptions and categories. Turn it off for a cheap freshness sweep across many channels — a channel then costs one request.
- To poll for what is new, set Only videos newer than to a window shorter than the gap between your runs.
- Click Start, then open the Dataset tab and export as JSON, CSV or Excel.
Store channelId, not the handle — the handle can change, the UC… id
cannot.
From the API
curl -s "https://api.apify.com/v2/acts/simple.actors~youtube-channel-videos/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"handles": ["NASA"], "maxVideos": 30}'
A cheap daily freshness check across many channels, with the JavaScript client:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('simple.actors/youtube-channel-videos').call({handles: ['NASA', 'veritasium', 'UCLA_DiR1FfKNvjuUpBHmylQ'],includeVideoDetails: false, // one request per channel, rounded figuresonlyVideosNewerThan: '2 days',});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const row of items) {if (row.error) { console.warn(row.error, row.errorDescription); continue; }console.log(row.channelName, row.title, row.publishedText);}
Use cases
- Monitor channels for new uploads — poll a list on a schedule with
onlyVideosNewerThanandincludeVideoDetails: falsefor a cheap check, then read the details of anything new. - Competitor and content research — titles, durations, categories, descriptions and exact view counts across rival channels.
- Influencer vetting — subscriber count, total video count and real engagement on recent uploads, rather than YouTube's rounded display figures.
- Video performance benchmarking — exact views and likes per video, loaded straight into a spreadsheet or warehouse.
- Building a video dataset — metadata for a channel's latest 30 uploads with
stable
videoIdandchannelIdkeys. - Media and brand monitoring — watch newsroom, agency and brand channels for what they published today.
Usage notes
What it costs
| each video returned | $0.0005 |
| each video read for exact figures | $0.0010 on top |
So $1.50 per 1,000 videos with exact views, likes, descriptions and publish dates, and $0.50 per 1,000 for titles, links, durations, thumbnails and rounded figures.
That split is the real cost, passed on: a channel listing is one request for up
to thirty videos, while the exact figures are a request each. If you are
watching a lot of channels to see what is new, turn includeVideoDetails off
and a channel costs one request.
Nothing else is charged. A channel that could not be read, a video with no detail page available, a run whose every input was unusable — none of them bill.
What it cannot do
Thirty videos per channel. That is what a channel page renders to a
logged-out reader; going further needs YouTube's internal browse API with a
signed continuation token, which is a far more fragile surface than reading a
page. Every row carries channelVideoCount, so you can always tell whether you
are seeing all of a channel's videos or the latest thirty of many.
If you ask for a window reaching further back than those thirty
(onlyVideosNewerThan: "10 years"), the channel comes back as an error row
(window_too_wide) rather than a short list that would look like a complete
answer for that window.
Failures
The run always succeeds. A channel that does not exist, a string that could never be a handle, a video URL pasted where a channel belongs — each is a row, and the run's status message counts them. Only a bug in this Actor fails a run.
Act on the presence of an
errorfield, never on the run status. A channel read fine that has posted nothing produces no rows; a channel that could not be read produces exactly one row, carryingerrorand novideoId.
error | what happened |
|---|---|
not_found | no such channel |
bad_input | the text given could never be a channel, or is a video/playlist URL |
window_too_wide | the window reaches further back than one page of videos shows |
read_failed | YouTube could not be reached, or served a page in a language this Actor could not read |
FAQ
Is scraping YouTube legal? This Actor reads only the data YouTube already serves to a logged-out visitor in the page itself — it does not log in, use cookies, or reach private or members-only content. YouTube's Terms of Service restrict automated collection, so check the platform's ToS and your own obligations before using it.
Do I need a YouTube Data API key or a Google Cloud project? No. There is no key, no OAuth and no quota of your own to manage.
Can I get more than 30 videos per channel?
No. Thirty is what a channel page renders to a logged-out reader; going further
needs YouTube's internal browse API with a signed continuation token, which is a
far more fragile surface than reading a page. Every row carries
channelVideoCount, so you can always tell whether you are seeing all of a
channel's videos or the latest thirty of many.
Does it support pagination?
Not beyond that first page, for the reason above. To follow a channel over time,
run it on a schedule with onlyVideosNewerThan.
Why is viewCount rounded on some rows?
Because the exact figure lives only on each video's own page, and YouTube
refuses some of those reads from datacenter addresses — about 92% land after up
to six retries. Those rows keep the listing's rounded figures and say so via
viewCountIsApproximate: true, with likeCount: null. You are never silently
given a wrong number.
What does viewCountIsApproximate: null mean?
That there is no figure to describe at all — a members-only upload, for example,
publishes no view count. A null flag is not a rounded number waiting to be
improved.
Should I turn on residential proxy? Rarely. It lifts that last 8% of detail reads at roughly ten times the cost per video, and every row already tells you which figures it carries.
Should I store the handle or the channel ID?
The channelId. A channel's owner can change its handle at any time; the UC…
id never changes.
Why did my run succeed when a channel was not read?
By design. A channel that does not exist, a string that could never be a handle,
or a video URL pasted where a channel belongs are each answers about that input,
not faults — so each is a row and the run stays green. Act on the presence of an
error field, never on the run status.