YouTube Channel Videos Scraper — Metadata & Metrics
Pricing
from $5.00 / 1,000 video scrapeds
YouTube Channel Videos Scraper — Metadata & Metrics
Scrape public YouTube channel videos and Shorts with titles, descriptions, dates, views, likes, comments, duration, thumbnails, and channel metadata. No cookies required.
Pricing
from $5.00 / 1,000 video scrapeds
Rating
0.0
(0)
Developer
Khadin Akbar
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
YouTube Channel Videos Scraper
Turn known YouTube channels into a clean, analysis-ready inventory of public videos and Shorts. Give the Actor channel URLs, @handles, or channel IDs; it returns one validated dataset row per video with its URL, title, description, publish time, duration, thumbnail, public engagement metrics, channel identity, and collection provenance.
This YouTube channel video scraper is for a precise job: you already know which channels matter and need their recent or popular public content as structured data. It does not require your YouTube cookies, Google login, browser session, or personal YouTube API key.
Use the prefilled Actor input page when you want to verify one channel with a bounded 10-video run.
Decide in 30 seconds
| Your job | Use this Actor? | Recommended route |
|---|---|---|
| Export videos or Shorts from known channels | Yes | Add channel URLs or handles to channelUrls. |
| Monitor new uploads from a fixed creator or competitor list | Yes | Use sortBy: "latest" and a bounded date window. |
| Compare public views, likes, comments, duration, and posting patterns | Yes | Keep maxTotalVideos small first, then export the dataset. |
| Discover channels from a topic or keyword | Not first | Start with YouTube Search Scraper, then pass its channelUrl or channelId values here. |
| Collect comments after selecting videos | Not directly | Send this Actor's videoUrl or videoId values to YouTube Comments Scraper. |
| Download media, audio, captions, or transcripts | No | Use a purpose-built downloader or transcript Actor. |
| Access private, deleted, age-gated, or login-only content | No | Those surfaces are outside this Actor's public-data scope. |
A real workflow: from channel list to editorial decision
Imagine a content strategist starts Monday with 12 competitor channels and one question: “What did they publish in the last 30 days, and which formats earned visible engagement?” Search results are the wrong source because ranking changes by query, location, and personalization. The strategist already has the channel list.
They run this Actor with contentType: "all", a start date, maxVideosPerChannel: 25, and a whole-run cap. The dataset becomes the evidence table: titles show recurring themes, durationSeconds separates short and long formats, publishedAt reveals cadence, and the public metric fields support a current-snapshot comparison. When a high-interest video needs audience analysis, its videoUrl flows directly into the comments Actor. The decision is no longer based on opening 12 channel tabs by hand.
That workflow is intentionally bounded. It does not pretend a public metric snapshot is historical performance data, and it does not interpret a missing like count as zero.
What one dataset row contains
Each row represents one public long-form video or YouTube Short. The flat record works in CSV, JSON, spreadsheets, BI tools, databases, Make, n8n, and AI-agent pipelines.
| Field group | Fields | What it answers |
|---|---|---|
| Video identity | videoId, videoUrl, title, description | What is the item and where is its public page? |
| Channel identity | channelId, channelHandle, channelName, channelUrl, channelSubscriberCount | Which channel published it? |
| Time and format | publishedAt, durationSeconds, durationText, contentType, isShort, isLive, isUpcoming | When and in what format was it published? |
| Public metrics | viewCount, likeCount, commentCount, engagementRate | What visible engagement snapshot did the provider return? |
| Media and labels | thumbnailUrl, badges, genre | What display and classification metadata is available? |
| Provenance | provider, input, sortBy, resultPosition, page, scrapedAt | How, where, and when was the row collected? |
engagementRate is calculated as (likeCount + commentCount) / viewCount only when all three usable public counts exist and views are greater than zero. If YouTube or the provider omits a count, the Actor omits the rate instead of understating it.
Optional fields vary by video, channel, region, and provider response. Missing data stays missing; the Actor does not invent placeholder values or write error rows into the dataset.
Quick start recipes
Recipe 1: ten recent long-form videos
Use this first to verify the channel and inspect the output shape at a bounded cost.
{"channelUrls": ["https://www.youtube.com/@MrBeast"],"contentType": "videos","maxVideosPerChannel": 10,"maxPagesPerContentType": 1,"maxTotalVideos": 10,"sortBy": "latest"}
Recipe 2: recent uploads across a reporting window
publishedAfter is inclusive; publishedBefore is exclusive. Both accept real UTC calendar dates in YYYY-MM-DD form.
{"channelUrls": ["https://www.youtube.com/@TED","https://www.youtube.com/@NASA"],"contentType": "all","maxVideosPerChannel": 25,"maxPagesPerContentType": 2,"maxTotalVideos": 50,"sortBy": "latest","publishedAfter": "2026-06-01","publishedBefore": "2026-07-01"}
When contentType is all, the long-form feed is processed before the Shorts feed and both share the per-channel cap. Raise maxVideosPerChannel if you need room for both formats.
Recipe 3: popular Shorts from a channel ID
{"channelUrls": ["UCX6OQ3DkcsbYNE6H8uQQuVA"],"contentType": "shorts","maxVideosPerChannel": 20,"maxPagesPerContentType": 2,"maxTotalVideos": 20,"sortBy": "popular"}
Provider rankings can differ slightly. Treat popular as the selected provider's current feed order, not as an immutable YouTube-wide ranking.
Input reference and cost controls
| Input | Type and default | Use it for | Important boundary |
|---|---|---|---|
channelUrls | array, required | Channel URLs, @handles, or IDs beginning UC | 1–100 entries; video and playlist URLs are rejected. |
contentType | videos | videos, shorts, or all | all shares one per-channel result cap. |
maxVideosPerChannel | integer, 50 | Cap saved rows for each channel | 1–500. |
maxPagesPerContentType | integer, 10 | Bound provider pagination per selected feed | 1–50; this is not a row count. |
maxTotalVideos | integer, 500 | Cap all saved and billable rows in the run | 1–5,000; strongest whole-run event-cost control. |
sortBy | latest | Request recent-first or popularity-oriented ordering | latest or popular. |
publishedAfter | omitted | Keep records on or after a UTC date | Real YYYY-MM-DD date; rows without a machine-readable date are excluded. |
publishedBefore | omitted | Keep records before a UTC date | Exclusive upper bound; must be later than publishedAfter. |
providerOrder | scrapecreators-first | Select fallback order or isolate a provider for diagnosis | Single-provider modes remove fallback resilience. |
includeRawData | false | Diagnose provider field drift | Adds a capped raw object and makes rows less convenient for agents and sheets. |
API inputs are validated without coercion. For example, "10" is not accepted where the schema declares the integer 10, "true" is not accepted as a boolean, and a rollover date such as 2025-02-30 is rejected. This keeps UI, API, and agent behavior consistent.
Output example
{"recordType": "video","contentType": "videos","provider": "scrapecreators","input": "https://www.youtube.com/@MrBeast","channelId": "UCX6OQ3DkcsbYNE6H8uQQuVA","channelHandle": "MrBeast","channelName": "MrBeast","channelUrl": "https://www.youtube.com/@MrBeast","videoId": "xvFZjo5PgG0","videoUrl": "https://www.youtube.com/watch?v=xvFZjo5PgG0","title": "A public video title","description": "A public video description returned by the provider.","publishedAt": "2026-07-01T00:00:00.000Z","durationSeconds": 823,"durationText": "13:43","thumbnailUrl": "https://i.ytimg.com/vi/xvFZjo5PgG0/maxresdefault.jpg","viewCount": 23456789,"likeCount": 1200000,"commentCount": 18342,"engagementRate": 0.0519,"isShort": false,"sortBy": "latest","resultPosition": 1,"page": 1,"scrapedAt": "2026-07-18T12:00:00.000Z"}
The default key-value store also contains:
OUTPUT: compact terminal outcome, row and charge counts, cost figures, memory allocation, and warnings.RUN_SUMMARY: detailed input, providers, attempts, status codes, pagination, filters, validation, billing, and stop reason.
Use the dataset for records and OUTPUT for orchestration. Do not infer success from an HTTP or Actor run status alone.
Run outcomes for automations and AI agents
| Outcome | Transport state | Meaning | Recommended agent action |
|---|---|---|---|
COMPLETE | succeeded | Requested bounded work completed without recorded data-quality warnings | Consume rows. |
PARTIAL | succeeded | Usable rows exist, but a route, validation, write, or event-cap warning occurred | Consume with warnings; decide whether to retry the missing scope. |
VALID_EMPTY | succeeded | The request was valid but no matching public rows were available, or the event cap prevented provider work | Check dates, channel availability, and stopReason; do not invent rows. |
INVALID_INPUT | succeeded | Input type, value, date, or channel reference was invalid | Correct the named field; do not retry unchanged. |
CONFIG_ERROR | failed | Owner-managed provider credentials or internal configuration prevented work | Escalate; changing channel input will not fix it. |
UPSTREAM_FAILED | failed | Every configured provider route failed before a usable row was saved | Retry with backoff or use a diagnostic provider mode. |
Continuation tokens are provider-specific and remain internal. There is no public resume-token input. To bound or deepen a run, change maxPagesPerContentType, maxVideosPerChannel, and maxTotalVideos; never copy a continuation token between providers.
Pricing with worked examples
This Actor uses Pay per event + Apify platform usage.
| Event | Price | When it is charged |
|---|---|---|
apify-actor-start | $0.00005 | One event per allocated GB or part thereof, with a one-event minimum. |
video-scraped | $0.005 | Once for each validated video or Short successfully persisted to the dataset. |
At the default 512 MB allocation, the start event count is one:
A bounded run of 10 records costs $0.05005 in named event charges at that memory allocation.
- 1 saved video:
1 × $0.00005 + 1 × $0.005 = $0.00505 - 10 saved records:
1 × $0.00005 + 10 × $0.005 = $0.05005 - 50 saved videos:
1 × $0.00005 + 50 × $0.005 = $0.25005
At 4 GB, 10 saved videos cost 4 × $0.00005 + 10 × $0.005 = $0.05020 in event charges. Apify compute, storage, network, and any proxy usage are additional. The Actor reports both the maximum bounded event estimate before provider work and actual named-event counts afterward.
Set maxTotalVideos before increasing page depth. A date filter can reduce saved rows and event charges, but provider pages still use compute and provider capacity while the Actor looks for matching dates.
Use through the API
cURL
Keep the token in an environment variable and send it in the authorization header, not in a URL.
curl -X POST \'https://api.apify.com/v2/acts/khadinakbar~youtube-channel-videos-scraper/runs?waitForFinish=60' \-H "Authorization: Bearer $APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"channelUrls": ["https://www.youtube.com/@TED"],"contentType": "videos","maxVideosPerChannel": 10,"maxPagesPerContentType": 1,"maxTotalVideos": 10,"sortBy": "latest"}'
Read data.defaultDatasetId for rows and data.defaultKeyValueStoreId for OUTPUT and RUN_SUMMARY. If the run is still active after the wait window, poll the run endpoint before reading evidence.
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('khadinakbar/youtube-channel-videos-scraper').call({channelUrls: ['https://www.youtube.com/@TED'],contentType: 'all',maxVideosPerChannel: 20,maxPagesPerContentType: 2,maxTotalVideos: 20,sortBy: 'latest'});const [{ items }, output] = await Promise.all([client.dataset(run.defaultDatasetId).listItems(),client.keyValueStore(run.defaultKeyValueStoreId).getRecord('OUTPUT')]);console.log(output?.value?.outcome, items.length);
Python
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("khadinakbar/youtube-channel-videos-scraper").call(run_input={"channelUrls": ["https://www.youtube.com/@TED"],"contentType": "videos","maxVideosPerChannel": 10,"maxPagesPerContentType": 1,"maxTotalVideos": 10,"sortBy": "latest",})rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())output = client.key_value_store(run["defaultKeyValueStoreId"]).get_record("OUTPUT")print(output["value"]["outcome"], len(rows))
Agent and MCP prompt card
When this Actor is exposed through Apify's Actors MCP server, route a request here only if the user provides known channels or channel identifiers.
Agent prompt: Collect 10 recent videos from the supplied channel, inspect
OUTPUT, return warnings forPARTIAL, and reportVALID_EMPTYwithout inventing data.
Use khadinakbar--youtube-channel-videos-scraper to collect up to 10 recentlong-form videos from https://www.youtube.com/@TED. Set one provider page anda whole-run cap of 10. Return videoId, videoUrl, title, publishedAt,durationSeconds, viewCount, likeCount, and commentCount. Then inspect OUTPUT.If outcome is PARTIAL, explain the warnings. If VALID_EMPTY, say that no matchingpublic rows were returned. Never substitute made-up metrics or retry invalid input.
Agent routing contract:
- Required entity: at least one known public channel URL,
@handle, or channel ID. - Output entity: one public video or Short per dataset row.
- Freshness:
scrapedAtis collection time; public metrics are a snapshot, not a time series. - Side effects: starts a paid Actor run and may persist billable dataset rows.
- Cost controls: set row and page caps explicitly.
- Failure inspection: read
OUTPUT, thenRUN_SUMMARYwhen the outcome is notCOMPLETE. - Pagination: controlled by bounded inputs; no cross-provider continuation token is exposed.
Limits, recovery, and honest expectations
| Symptom | Likely reason | Recovery |
|---|---|---|
| Fewer rows than expected | Date filter, duplicate IDs, missing dates, public availability, or result caps | Inspect RUN_SUMMARY, then widen one boundary deliberately. |
No rows with VALID_EMPTY | Valid channel but no matching public items, or event cap blocked work | Check stopReason, dates, content type, and charge cap. |
PARTIAL with data | A provider route failed or a row could not be validated/persisted | Keep usable rows, inspect warnings, and retry only the missing scope. |
| Provider-specific failure | Credential rejection, throttling, timeout, or upstream shape change | Restore default fallback order; use an *-only mode only for diagnosis. |
| Different order between runs | Public feeds and provider ordering changed | Treat resultPosition as run-scoped, not permanent rank. |
| Missing public counts | YouTube/provider did not expose them for that item | Preserve nullability; do not convert missing values to zero. |
The Actor retries transient request failures and can fall back between two owner-managed public-data providers. Provider continuation tokens are opaque and are never forwarded across providers. It deduplicates video IDs across inputs and selected feed types, validates a complete record before persistence, and couples each successful dataset write to the video-scraped event.
No scraper can guarantee an exhaustive historical archive of YouTube. Deleted, private, restricted, unavailable, or provider-omitted videos may not appear. Public counts can change immediately after collection.
Verification snapshot
On 2026-07-18, the Actor was fresh-pulled from live build 1.3.1 and rebuilt through v1.4. Local validation finished with 32 passing tests, 95.65% helper-module line coverage, 85.15% branch coverage, valid Apify schemas, clean syntax checks, and an npm audit with zero known vulnerabilities. The review caught and fixed cross-provider continuation-token reuse, permissive API coercion, invalid calendar-date rollover, memory-insensitive start estimates, incomplete engagement-rate semantics, ambiguous bare video IDs, an SDK charge-limit state that could disagree with the persisted dataset, and a 4 GB MCP run whose platform-expanded start count was larger than the SDK's explicit-call count.
Build 1.4.3 completed a reviewed 26/26 REST acceptance matrix with zero unexpected failures at 512 MB. A separate real Actors MCP call against build 1.4.4 at 4 GB then found a semantic reporting defect that the REST matrix could not expose: Apify correctly expanded one explicit apify-actor-start call to four billable start events, while the old OUTPUT reported one. Build 1.4.5 is the corrected release target and must independently pass the full 26-case REST matrix, a real 4 GB MCP call, the live-release verifier, and a fresh source readback before handoff. The pinned run IDs live in the release evidence rather than being hidden behind an aggregate success claim.
This is engineering evidence, not a claim that YouTube or either upstream provider will always return every field. Final cloud acceptance evidence is tied to the deployed build and its pinned run IDs rather than inferred from a SUCCEEDED transport status.
Responsible use
Use this Actor for public YouTube metadata you are permitted to process. You are responsible for applicable law, YouTube terms, privacy obligations, contractual restrictions, and content rights. Do not use it to access private data, evade controls, identify sensitive individuals, or redistribute copyrighted media without permission. Apply appropriate retention, access, and deletion controls to exported datasets.
Frequently asked questions
Does it download YouTube videos or audio?
No. It returns structured public metadata and metric snapshots, not media files, audio, captions, or transcripts.
Does it need my YouTube API key or cookies?
No. Provider credentials are managed by the Actor owner. Users provide channel references and limits, not personal YouTube credentials.
Can it find channels for a topic?
This Actor expects known channels. Use youtube-search-scraper for keyword discovery, then map its channelUrl or channelId output into channelUrls here.
How do I collect comments from the returned videos?
Pass each videoUrl to startUrls, or each videoId to videoIds, in youtube-comments-scraper. This is a schema-confirmed downstream handoff, not a generic cross-link.
Why can engagement rate be absent?
The rate requires views, likes, and comments. If any public count is unavailable, omitting the derived rate is more accurate than treating the missing count as zero.