YouTube Scraper — Shorts, Videos & Search
Pricing
Pay per event
YouTube Scraper — Shorts, Videos & Search
Shorts, channel videos and search results from YouTube — videoId, title, view count, publish date, duration, thumbnail — paginated through InnerTube, cached and paced.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Leo Nguyen
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 hours ago
Last modified
Categories
Share
YouTube Scraper — Shorts, videos & search (cached)
Three listings from YouTube, one Actor: a channel's Shorts tab, a channel's videos tab, and search results. videoId, title, view count, publish date, duration, thumbnail. No API key, no browser, no quota.
| Ask for | Input |
|---|---|
| Shorts from a channel | channels: ["@MrBeast"] (default) |
| Regular videos from a channel | channels: ["@MrBeast"], channelTabs: ["videos"] |
| Both tabs | channelTabs: ["shorts", "videos"] |
| Search results | searchQueries: ["ai tools 2026"] |
What you get
One row per video (or one row per listing, your choice):
| Field | Example |
|---|---|
videoId | egvLKQe6I4I |
url | https://www.youtube.com/shorts/egvLKQe6I4I |
title | Don't Pop the Balloon |
viewCount | 102000000 — parsed to a number |
viewCountText | 102M views — YouTube's own wording |
thumbnail | highest-resolution source YouTube offers |
publishedText | 11 days ago — videos and search rows only |
durationText | 12:56 — search rows only |
channelName | on search rows, the channel that posted the video |
channel, channelUrl, listing | repeated on every row, so no join is needed |
fromCache | whether this came from cache or a live fetch |
On a search job, channel holds the query you asked for and listing is search.
How it behaves
Measured against live pages on 2026-08-06 from a plain datacenter IP:
- Every listing ships its data inline as
ytInitialData— 48 rows per request for Shorts, ~30 for a channel's videos, ~20 for search — with nothing to render. That is why this Actor needs no browser and stays cheap. - Pagination goes through YouTube's own InnerTube API. One test run pulled 174 Shorts across 2 channels in 5 requests. Verified per type on 2026-08-06: Shorts 48+48, videos 30+30, search 20+16, with zero overlap between page 1 and page 2 in all three.
- Pagination stops when the listing runs out, not when a page counter says so. Asking for 96 from a channel with 78 returns 78 and spends nothing extra.
- The three types genuinely differ under the hood and are handled separately rather than assumed
identical: channel videos arrive as
lockupViewModel, search asvideoRenderer, Shorts asshortsLockupViewModel— and a search continuation must be POSTed to/youtubei/v1/search, not/browse, which answers a bare HTTP 400 that looks like an expired token.
Deliberate choices you should know about:
- A channel that fails does not fail the run. It comes back as a row with
error, so a 20-channel job returns the other 19. Verified: a nonexistent handle produced one error row and the run still exited clean. - YouTube does not answer overload with a clean error. It serves a consent or challenge page
that is still HTTP 200. So a missing
ytInitialDatais treated as "we were blocked" — never as "this channel has no Shorts". Those two are very different answers and conflating them is how scrapers quietly return empty results. - Requests are paced under ~1/s and results are cached. A channel's Shorts list changes a few times a week, so a cached answer from an hour ago is the same answer — and it costs YouTube nothing, which is what keeps this Actor off the throttle.
viewCountisnull, never0, when YouTube's text cannot be parsed. A zero is a lie you could aggregate without noticing.
Limits — read before buying
- View counts are rounded by YouTube itself (
102M views), soviewCountis precise to about 1%, not exact.viewCountTextis preserved so you can see what was actually said. - Shorts only. The
/videosand/streamstabs use different structures and are out of scope. - No like counts, comments or publish dates on the channel listing — YouTube does not put them there. Getting those means one request per video, which is a different (and far more expensive) Actor.
- YouTube's Terms of Service restrict automated access. You are responsible for how you use the output. Only public channel listing data is collected.
Input
{"channels": ["@MrBeast", "UCHnyfMqiRRG1u-2MsSQLbXA", "https://www.youtube.com/@veritasium"],"maxShortsPerChannel": 96,"cacheMaxAgeMinutes": 180}
Handles, bare names, UC… ids and full URLs all work — with or without a /shorts or /videos
suffix already on the end.
Development
pip install -r requirements.txtmkdir -p storage/key_value_stores/defaultecho '{"channels":["@MrBeast"],"useApifyProxy":false}' > storage/key_value_stores/default/INPUT.jsonpython -m src
src/shorts.py is plain standard library and runs without the Apify SDK — useful for checking
whether YouTube renamed something:
$python -c "from src.shorts import ShortsClient; c=ShortsClient(); s,t,i=c.first_page('@MrBeast'); print(len(s), i)"