YouTube Channel Scraper — Latest Videos via RSS (No API Key)
Pricing
from $0.70 / 1,000 result items
YouTube Channel Scraper — Latest Videos via RSS (No API Key)
Latest videos of any YouTube channel or playlist without API key or quota: official RSS (15 latest, exact dates/views) or the public Videos/Shorts tab (~30/48 latest). Keyword, date and view filters, channel stats (subscribers, total views), per-video details (duration, likes, category).
Pricing
from $0.70 / 1,000 result items
Rating
0.0
(0)
Developer
Samat Makatov
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
5 days ago
Last modified
Categories
Share
Monitor any YouTube channel or playlist without the Data API, quota, browser or proxy. Reads the official RSS feed (15 latest videos with exact timestamps, view counts and descriptions) or the public Videos / Shorts tab (~30 / ~48 latest), optionally enriched with channel stats (subscribers, total views, country, links) and per-video details (duration, likes, category, keywords — paused, see Limits). Give a @handle, any channel URL, a UC… id or a PL… playlist id.
Use cases
- Competitor / creator monitoring — daily run with
maxAgeDays: 1over 50 channels; alert on new uploads that matchincludeKeywords. - Channel benchmarking —
includeChannelStats: trueto compare subscribers, total views and video counts of the channels you follow. - Content research —
source: "videos",sort: "mostViewed"to see which recent topics perform for each channel. - Shorts trend tracking —
source: "shorts"for the latest 48 Shorts with view counts. - Sponsorship due diligence —
includeVideoDetailsfor exact duration, likes and category of the last N videos (paused since late 09/2026: YouTube shows its anti-bot check on video pages — see Limits). - Playlist sync — feed a course or podcast playlist (
PL…) into your CMS / vector DB whenever a new episode appears.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
channels | string[] | — | @handle, youtube.com/@x, /channel/UC…, /c/Name, /user/Name, UC… id, PL…/UU… playlist id or playlist URL. Links work with or without https://; a video link (watch?v=…, youtu.be/…, /shorts/…) is read as "the channel of that video". |
source | select | rss | rss (15 latest, exact data), videos (~30 latest uploads, approx. dates & rounded views, durations), shorts (~48 latest Shorts). Playlists always use RSS. |
limitPerChannel | int | 15 | Max videos kept per entry (1–100; the source caps apply). |
includeKeywords | string[] | — | Keep videos whose title/description contains any (case-insensitive). |
excludeKeywords | string[] | — | Drop videos containing any. |
sinceDate | date | — | Keep videos published on/after this date. |
maxAgeDays | int | — | Keep videos newer than N days (good for scheduled runs). |
minViews | int | — | Drop videos below this view count. |
sort | select | newest | newest, mostViewed, feed. Applied before limitPerChannel. |
includeChannelStats | bool | false | Fetch the About page: subscribers, video count, total views, country, joined, description, links, avatar. Emits one type: "channel" row per channel + channel* columns on videos. |
includeVideoDetails | bool | false | Paused (see Limits). Fetch each video page: durationSec, likeCount, category, keywords, exact views, isLive. A page YouTube does not serve leaves detailsFetched: false and the reason in detailsError. |
maxDetailsPerChannel | int | 5 | Budget for includeVideoDetails (0–50). |
descriptionLength | int | 1000 | Truncate RSS descriptions (0 = drop). |
maxItems | int | 1000 | Hard cap on dataset rows across all channels (channel-stats rows count too). |
dedupe | bool | true | Skip a videoId already emitted by an earlier entry. An entry listed twice is read once. |
fields | string[] | — (all) | Keep only these columns, in this order. type, channelId and videoId are always kept and come first unless you place them. Case and spaces do not matter (channel title = channelTitle); an unknown name is skipped and named in the status. A row that would keep none of your columns (e.g. a channel row when you list only video columns) is not written. |
Reference
What each source gives you
| Field | rss | videos tab | shorts tab | + includeVideoDetails (paused) |
|---|---|---|---|---|
| items | ≤ 15 | ≈ 30 | ≈ 48 | — |
publishedAt (exact ISO) | yes | no (publishedAtApprox from "3 days ago" / "3d ago") | no | yes (publishDate) |
views | exact | rounded ("572K") | rounded | exact |
description | yes (truncated) | no | no | no |
durationSec | no | yes | no | yes |
rating / ratingCount | yes | no | no | likeCount |
category, keywords, isLive | no | no | no | yes |
Accepted channel references
| Input | Example |
|---|---|
| Handle | @Fireship, Fireship |
| Channel URL | https://www.youtube.com/@Fireship/videos, youtube.com/@Fireship (no scheme), m.youtube.com/@Fireship, /channel/UCsBjURrPoezykLs9EqgamOA, /c/Fireship, /user/GoogleDevelopers |
| Channel id | UCsBjURrPoezykLs9EqgamOA |
| Playlist | PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf, https://www.youtube.com/playlist?list=PL…, uploads playlist UU… |
| Video link | https://www.youtube.com/watch?v=…, youtu.be/…, /shorts/…, /live/… → the channel that published the video (the run log and SUMMARY.notes say which one). |
Examples
Daily "what's new" across a watchlist
{ "channels": ["@Fireship", "@aiDotEngineer", "@lexfridman"], "maxAgeDays": 1 }
Channel stats next to the latest uploads
{ "channels": ["@Fireship", "@ThePrimeagen", "@t3dotgg"], "includeChannelStats": true, "limitPerChannel": 3 }
Only the columns you need
{ "channels": ["@Fireship"], "fields": ["title", "views", "publishedAt", "url"] }
Top-performing recent videos per channel
{ "channels": ["@Fireship"], "source": "videos", "sort": "mostViewed", "limitPerChannel": 10 }
Keyword watch: reviews mentioning a product
{ "channels": ["@mkbhd", "@UnboxTherapy"], "includeKeywords": ["iPhone", "Pixel"], "excludeKeywords": ["#shorts"], "maxAgeDays": 30 }
Latest Shorts
{ "channels": ["@Fireship"], "source": "shorts", "limitPerChannel": 20 }
Output
Video row (RSS + details, when YouTube serves the video page):
{"type": "video","input": "https://www.youtube.com/@Fireship","kind": "channel","source": "rss","playlistId": null,"channelId": "UCsBjURrPoezykLs9EqgamOA","channelTitle": "Fireship","channelUrl": "https://www.youtube.com/channel/UCsBjURrPoezykLs9EqgamOA","channelHandle": "@Fireship","channelSubscribers": 4270000,"channelVideoCount": 841,"channelTotalViews": 744056340,"channelCountry": null,"videoId": "FluKUJyeYD8","title": "Did OpenAI actually build AGI? GPT-6 Astra first look","url": "https://www.youtube.com/watch?v=FluKUJyeYD8","publishedAt": "2026-09-04T20:14:12.000Z","publishedAtApprox": null,"publishedText": null,"updatedAt": "2026-09-11T22:17:40.000Z","description": "CodeRabbit Security protects your code…","thumbnail": "https://i3.ytimg.com/vi/FluKUJyeYD8/hqdefault.jpg","views": 3999521,"viewsText": null,"rating": 5,"ratingCount": 45194,"likeCount": 45194,"durationSec": 446,"durationText": null,"isShort": false,"isLive": false,"category": "Science & Technology","keywords": ["webdev", "app development"],"detailsFetched": true,"detailsError": null,"fetchedAt": "2026-09-12T23:41:12.086Z"}
| Field | Description |
|---|---|
type | video or channel (stats row, only with includeChannelStats). |
input, kind, source | What you passed, channel/playlist, and which source produced the row. |
channelId, channelTitle, channelUrl, channelHandle | Resolved channel identity. |
channelSubscribers, channelVideoCount, channelTotalViews, channelCountry | From About page (includeChannelStats), else null. channelCountry is null when the channel does not publish a country (common). |
videoId, title, url, thumbnail | Video identity. |
publishedAt / publishedAtApprox / publishedText | Exact UTC ISO-8601 …Z (RSS/details) or approximate from relative text (tabs). updatedAt (RSS) is UTC too. |
views, viewsText, rating, ratingCount, likeCount | Engagement. |
durationSec, durationText, isShort, isLive, category, keywords | From tab / details. |
description | RSS description, truncated to descriptionLength. |
detailsFetched, detailsError | true when the watch page was read (includeVideoDetails). false with a reason when YouTube did not serve the video's data (age restriction, members-only, its anti-bot check) or the run skipped it (after an anti-bot check, near the timeout); false with null beyond maxDetailsPerChannel or without includeVideoDetails. |
Every video row has all these columns (null where the source has no value).
Channel row (type: "channel") adds channelDescription, channelJoined, channelAvatar, channelKeywords, channelLinks[], channelIsFamilySafe and the raw subscribersText / videoCountText / totalViewsText. Key-value record SUMMARY: { rows, videos, channelRows, channels, entriesRead, entriesNotRead, source, details, statsErrors[], blockedBy, requests, notes[], errors[], delivered, stoppedBy, status } — rows = videos + channel rows (what is billed), details = { requested, fetched, failed, skipped, errors[] }, notes records inputs we interpreted (a video link resolved to its channel, a corrected fields name, a repeated entry).
Use it from code / agents
curl -X POST "https://api.apify.com/v2/acts/yadroo~youtube-channel-feed/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' -d '{"channels":["@Fireship"],"maxAgeDays":7}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('yadroo/youtube-channel-feed').call({ channels: ['@aiDotEngineer'], includeChannelStats: true });const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("yadroo/youtube-channel-feed").call(run_input={"channels": ["@Fireship"], "source": "videos", "sort": "mostViewed"})items = client.dataset(run["defaultDatasetId"]).list_items().items
MCP: connect https://mcp.apify.com and call the yadroo/youtube-channel-feed tool with the same JSON.
Pricing
Pay per event: $0.001 per run start + $0.001 per row (a video or a channel-stats row). Bronze −10 %, Silver −20 %, Gold and above −30 % on the row price; the start event is the same on every plan; platform usage is included. Typical: 10 channels × 15 videos = 150 rows ≈ $0.15; a daily maxAgeDays: 1 watchlist usually yields a handful of rows, under $0.01.
Your maximum cost per run is respected: the run stops at the last row it pays for, ends with "Stopped at your spending limit: N rows delivered", and fetches no video details for rows it cannot deliver.
Limits & FAQ
- Only 15 videos? That is YouTube's RSS cap. Use
source: "videos"(~30) or"shorts"(~48); for full back-catalogues use a full YouTube scraper. - Approximate dates and rounded views on tabs. The Videos/Shorts tabs only show relative dates ("3 days ago", in YouTube's compact layout "3d ago") and rounded counts ("572K", "2.5M");
publishedAtApproxandviewsare computed from those and both tab layouts are read.source: "rss"gives exact dates and view counts for the 15 latest videos;includeVideoDetailswould give them per video but is paused (below). - Per-video details are paused. Since at least 27.09.2026 YouTube answers video pages requested from Apify's cloud with its "Sign in to confirm you're not a bot" check (every test run of 02.10.2026). The actor does not try to get around it: after the first check it requests no more video pages, the rows still come from RSS / the tabs with
detailsFetched: falseand the reason indetailsError, and the status says so. Feeds, tabs and channel About pages are not affected. - How much fits in one run. One request at a time, every request at least 0.6 s after the previous one — the channel-page lookup, the About page and the feed of one entry included: up to 4 s per
@handlechannel from RSS (less forUC…ids, which need no page lookup), up to 6 s withincludeChannelStats(About page), plus about 2 s per video page when YouTube serves them. The default run timeout (900 s) fits roughly 190 RSS channels or 120 channels with stats (measured 07.10.2026: 50 channels, 144 rows, under 4 minutes). Near the timeout the run stops starting new channels, saves what it has read and ends with "Stopped before the run timeout: N rows saved" — raise the timeout or split the channel list. - Rate limits / blocks. Up to 5 polite retries on 429/5xx, waiting as long as YouTube's
Retry-Afterasks and otherwise 5 s, 10 s, 20 s, 40 s — a short burst of "too many requests" from Apify's shared cloud IPs is waited out instead of ending the run. If YouTube still keeps answering 429, refuses with 403, redirects to its "unusual traffic" page, or shows its "confirm you're not a bot" check, the run does not try to get around it (no proxies, no other clients): it stops sending that kind of request, keeps the rows it has, and says what it met plus "start the run again in 15–30 minutes, or with fewer channels per run" in the status (SUMMARY.blockedBy). A check on video pages only stops the details (rows getdetailsError); on feeds, channel pages or About pages the run stops reading channels. - Private / deleted / renamed. 404 → clear error for that entry in
SUMMARY.errors; the run continues with the others and fails only if every entry it read failed. A feed or About page that answers with something else than the expected data is an error too (never an empty or null-filled success); a failed About page is listed inSUMMARY.statsErrorsand gives no channel row. - Anything that is not a YouTube address (another site, a typo'd handle) is reported per entry with what to pass instead — it never falls back to a different channel.
- Members-only / age-restricted videos get
detailsFetched: falsewith YouTube's reason indetailsError. - Roadmap. Comments count, transcript availability flag, uploads-playlist paging for older videos.
Made by Yadroo · Sibling actors: google-news-search · rss-to-json · hackernews-search · crypto-news