YouTube Scraper — Shorts, Videos & Search avatar

YouTube Scraper — Shorts, Videos & Search

Pricing

Pay per event

Go to Apify Store
YouTube Scraper — Shorts, Videos & Search

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

Leo Nguyen

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 hours ago

Last modified

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 forInput
Shorts from a channelchannels: ["@MrBeast"] (default)
Regular videos from a channelchannels: ["@MrBeast"], channelTabs: ["videos"]
Both tabschannelTabs: ["shorts", "videos"]
Search resultssearchQueries: ["ai tools 2026"]

What you get

One row per video (or one row per listing, your choice):

FieldExample
videoIdegvLKQe6I4I
urlhttps://www.youtube.com/shorts/egvLKQe6I4I
titleDon't Pop the Balloon
viewCount102000000 — parsed to a number
viewCountText102M views — YouTube's own wording
thumbnailhighest-resolution source YouTube offers
publishedText11 days ago — videos and search rows only
durationText12:56 — search rows only
channelNameon search rows, the channel that posted the video
channel, channelUrl, listingrepeated on every row, so no join is needed
fromCachewhether 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 ytInitialData48 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 as videoRenderer, Shorts as shortsLockupViewModel — 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 ytInitialData is 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.
  • viewCount is null, never 0, 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), so viewCount is precise to about 1%, not exact. viewCountText is preserved so you can see what was actually said.
  • Shorts only. The /videos and /streams tabs 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.txt
mkdir -p storage/key_value_stores/default
echo '{"channels":["@MrBeast"],"useApifyProxy":false}' > storage/key_value_stores/default/INPUT.json
python -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)"