Request a tool
All toolsGuidesMCP serverRequest a toolPlatformsCategories
YouTube Shorts Scraper icon

YouTube Shorts Scraper

Extract YouTube Shorts by channel or keyword: titles, video ids, URLs, exact views and likes, publish dates, durations, thumbnails and channel details.

74 runs on Apify
Run this in the cloudRun on Apify →

Social Media Scrapers

How it works

  1. 1
    Open it on Apify

    Hit Run on Apify — it opens the tool in the cloud, no install.

  2. 2
    Set the inputs

    Adjust channelUrls, searchQueries, maxItems (sensible defaults are pre-filled).

  3. 3
    Click Run

    The tool runs on Apify’s cloud and collects the data for you.

  4. 4
    Export the results

    Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.

Inputs

FieldWhat it doesType
channelUrlsYouTube channels to pull Shorts from, newest first. Any format works: https://www.youtube.com/@MrBeast, @mkbhd, https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA, youtube.com/c/mkbhd, youtube.com/user/PewDiePie, or a bare UC... id. Up to 20 targets per run in total, counting keywords.array
searchQueriesSearch YouTube Shorts for these words or phrases. One row per matching Short. You can mix keywords and channels in the same run.array
maxItemsTotal number of Shorts to return across all channels and keywords. The budget is split evenly between the targets, so four targets and 60 rows gives you fifteen of each. Keep it low while you are testing - you pay per row.integer
maxItemsPerTargetHard cap on how many Shorts to take from each channel or keyword. Leave it empty and the maximum-rows budget is simply split evenly between your targets.integer
includeStatsOn by default. Adds one small request per Short to turn the rounded "27M views" the feed shows into the exact 27,549,434, and to add the exact like count, the publish date and the duration in seconds. Turn it off for a faster run that returns only what the feed itself carries. The price per row is the same either way.boolean
sortBy"Newest first" orders the Shorts this run collected by their real publish date. "Feed order" keeps the order YouTube served them in.string
proxyUrlsLeave this empty. By default the run rotates a large pool of addresses that cost you nothing per gigabyte. Fill it in only if you specifically want the traffic to leave through proxy servers you already pay for, in the form http://user:pass@host:port.array

What you get

A structured dataset — each result includes fields like:

videoIdtitleurlviewCountlikeCountpublishedAtpublishedTimeTextdurationSecondsthumbnailchannelNamechannelIdchannelUrlviewCountTextposition

Export every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.

Related tools in Social Media Scrapers

Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.

TikTok Scraper - Profiles, Videos, Hashtags & Search iconSocial Media Scrapers

TikTok Scraper - Profiles, Videos, Hashtags & Search

Keyless TikTok scraper for profiles, videos, hashtags & search. Get views, likes, comments & video URLs as JSON/CSV. Cheaper, no API key, failed runs free.

5 use cases

Instagram Scraper - Profiles, Posts & Reels (No Login) iconSocial Media Scrapers

Instagram Scraper - Profiles, Posts & Reels (No Login)

Keyless Instagram scraper: profiles, posts and reels in one run. Likes, comments, views, media, hashtags. No login or API key. From $0.45/1k results.

5 use cases

Tweet Scraper - X / Twitter, No Login, Cheapest iconSocial Media Scrapers

Tweet Scraper - X / Twitter, No Login, Cheapest

No-login X/Twitter scraper: tweets, profiles, search, likes, retweets, views and media to JSON/CSV. No minimums, no caps, failed runs free. ~$0.14/1k.

5 use cases

Twitter (X) User Scraper - Profiles & Followers, No Login iconSocial Media Scrapers

Twitter (X) User Scraper - Profiles & Followers, No Login

Keyless X (Twitter) profile scraper: followers, bio, verified status & more by username. No login or API key, pay per profile, failed lookups free.

5 use cases

TikTok User Scraper - Profiles, Followers & Stats (No Login) iconSocial Media Scrapers

TikTok User Scraper - Profiles, Followers & Stats (No Login)

Scrape TikTok profiles without login or API key. Get followers, likes, bio, verified status & stats. Export CSV/JSON. Only $0.35 per 1,000 profiles.

5 use cases

Reddit Scraper iconSocial Media Scrapers

Reddit Scraper

Scrape Reddit posts and comments from any subreddit or user profile. Sort by top/hot/new, filter by score, get clean text. No key or login needed.

20 use cases

See all Social Media Scrapers →

YouTube Shorts Scraper

Give it YouTube channel URLs or handles and get that channel's Shorts feed back, newest first — or give it a keyword and get the Shorts that match it. Every row carries the title, the video id, the Short URL, the exact view count, the exact like count, the publish date, the duration in seconds, the thumbnail and the channel name and id. No account, no cookies, no API key, no browser.

  • Shorts specifically — read from the channel's own Shorts tab, not filtered out of the uploads feed by guessing at duration.
  • Exact numbers, not the rounded ones the page shows: 27,549,434 views and 1,023,955 likes, not "27M" and "1M".
  • Channels and keywords in the same run, up to 20 targets, with the row budget shared evenly between them.
  • @handles, /channel/UC…, /c/… , /user/… and legacy vanity URLs all resolve, including the old redirect-style ones.
  • Newest first by real publish date, not by whatever order the feed happened to serve.
  • Runs with empty input return a labelled sample row, free, so you can see the shape before spending anything.

Price

$0.40 per 1,000 Shorts, plus a $0.0005 start fee per run (billed per gigabyte of run memory, so exactly that on the default 1 GB).

This is the cheapest YouTube Shorts scraper on the market, and it is the same rate on every plan, free or paid. There are no volume tiers, no minimum spend, no subscription and no add-on fees. What you read here is what you pay on day one and on day four hundred.

ShortsTotal cost
100$0.0405
1,000$0.4005
10,000$4.0005
100,000$40.0005

What is actually charged

  • One short-scraped event per Short row written to the dataset. Nothing else is metered per row.
  • Free: the sample row an empty run returns, and every diagnostic row — a blocked target, a dead URL, a search that matched nothing. Those rows all carry "charged": false.
  • Shorts already returned earlier in the same run are dropped before they are charged, so overlapping keywords never bill twice.
  • A channel that has never posted a Short costs you nothing beyond the start fee — you get one free diagnostic row saying so.
  • Ordinary long-form videos that YouTube mixes into a filtered search are discarded, not billed as Shorts.
  • A run that finds nothing costs the start fee and nothing more.
  • Rows never leave the dataset without a charge, and are never charged without a row. The billed event is a named one, so there is no price quietly attached to apify-default-dataset-item — the trick that makes some scrapers bill you for their own error messages.

Input

{
  "channelUrls": [
    "https://www.youtube.com/@MrBeast",
    "@mkbhd"
  ],
  "searchQueries": [
    "cooking hacks"
  ],
  "maxItems": 60,
  "sortBy": "newest"
}
FieldWhat it does
channelUrlsChannel URLs or handles. https://www.youtube.com/@MrBeast, @mkbhd, https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA, youtube.com/c/mkbhd, youtube.com/user/PewDiePie and a bare UC… id all work. Up to 20 targets per run when combined with searchQueries.
searchQueriesKeywords to search YouTube Shorts for. One row per matching Short. Combine with channelUrls in the same run if you like.
maxItemsTotal rows across all targets. The budget is split evenly, so four targets and 60 rows gives you fifteen each. Default 20, hard ceiling 5,000. Keep it low while testing — you pay per row.
maxItemsPerTargetOptional hard cap per channel or keyword. Leave it empty to let maxItems split evenly.
includeStatsOn by default. Fetches each Short's exact view count, like count, publish date and duration. Turn it off for a faster run that returns only what the feed itself shows: title, id, URL, thumbnail and a rounded view count.
sortBynewest (default) orders the rows this run collected by their real publish date. feed keeps YouTube's own order instead.
proxyUrlsLeave empty. Fill it in only if you want the traffic to leave through proxy servers you already pay for, as http://user:pass@host:port.

Run it with empty input and you get one clearly labelled sample row, free, so you can see the output shape before you spend anything.

Output

One row per Short. A real row from a real run:

{
  "ok": true,
  "charged": true,
  "recordType": "short",
  "input": "https://www.youtube.com/@MrBeast",
  "searchQuery": null,
  "videoId": "LiH-P4rSkLI",
  "title": "Can You Pass This Classroom Quiz?",
  "url": "https://www.youtube.com/shorts/LiH-P4rSkLI",
  "viewCount": 27549434,
  "viewCountText": "27M views",
  "viewCountIsApproximate": false,
  "likeCount": 1023955,
  "publishedAt": "2026-08-11T16:00:06.000Z",
  "publishedTimeText": null,
  "durationSeconds": 74,
  "thumbnail": "https://i.ytimg.com/vi/LiH-P4rSkLI/sardefault.jpg",
  "channelName": "MrBeast",
  "channelId": "UCX6OQ3DkcsbYNE6H8uQQuVA",
  "channelUrl": "https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA",
  "position": 1,
  "statsError": null,
  "scrapedAt": "2026-08-15T21:52:26.584Z"
}

Field notes

  • videoId — the 11-character YouTube id. Stable, and safe to use as a primary key across re-runs.
  • url — always the /shorts/<id> form. The same video also plays at /watch?v=<id> if you prefer that.
  • viewCount — the exact integer when includeStats is on. With stats off it falls back to the rounded figure the feed prints.
  • viewCountIsApproximate — true when the count is the rounded feed figure rather than the exact one. Check this before doing arithmetic on views.
  • viewCountText — the view count exactly as the feed shows it, e.g. "27M views". Kept so you can reconcile a row against what you see on screen.
  • likeCount — the exact like count. Null when the creator has hidden likes on that Short — around 2 in 100 in testing.
  • publishedAt — publish time as ISO 8601 in UTC.
  • publishedTimeText — the relative date a search result carries, e.g. "13 days ago". Usually null on channel rows, where publishedAt is exact.
  • durationSeconds — length in whole seconds. Shorts run up to about three minutes, so this is not always under 60.
  • thumbnail — the largest still the feed offered. It is a vertical 9:16 frame, not the 16:9 thumbnail a normal video has.
  • channelId — the UC… id, which never changes even when the handle does. channelUrl is built from it.
  • position — the row's place in the delivered order for its target, starting at 1.
  • statsError — set only when the per-Short metadata call could not complete for that one video; the row is still delivered with everything the feed gave.

Every real row carries "charged": true. Sample rows carry "_sample": true and diagnostic rows carry "_diagnostic": true with an errorCode you can filter on, and neither is ever billed.

How it works

  • Shorts live behind their own tab on a channel and their own filter in search, so the run reads those surfaces directly rather than pulling the uploads feed and guessing which entries are Shorts by their length. Guessing gets it wrong both ways: it misses Shorts longer than a minute and it picks up ordinary short videos that are not Shorts at all.
  • Everything is plain JSON, requested and parsed. No page rendering, no headless browser, no login, no cookies and no API key — which is why a run costs what it does.
  • A second small request per Short is what turns "27M views" into 27,549,434, and adds the exact like count, the publish date and the duration. It is the smallest response that carries all four; the obvious Shorts-specific alternative returns ninety times more data for less information.
  • Requests leave through a large pool of rotating datacenter addresses, so a per-address rate limit is answered by moving rather than by waiting.
  • Channel handles are resolved in cost order: an id already in the URL costs nothing, a handle costs one small lookup, and the old redirect-style vanity URLs cost one more. Only if all of that fails does the run fall back to reading the channel page itself.

What people use it for

  • Tracking a creator's Shorts output over time — schedule the same channels daily and diff on videoId to see only what is new, with view and like counts attached.
  • Competitive research on a niche: run five channels in one go and sort the rows by viewCount to see which Shorts actually landed.
  • Finding hooks that work — pull a keyword's Shorts, sort by views per day since publishedAt, and read the top twenty titles before writing your own.
  • Building a Shorts dataset for analysis: the rows are flat and typed, so they load straight into a spreadsheet or a database with no cleaning.
  • Influencer vetting — a channel's recent Shorts with real like-to-view ratios tell you more about engagement than a subscriber count does.
  • Feeding a dashboard or a newsletter with a clean table instead of scraping a rendered page.

Reading the output

Every run writes three kinds of row, and they are easy to tell apart:

  • Real rows carry "charged": true and "recordType": "short". These are the rows you paid for, one billed event each.
  • The sample row carries "_sample": true and "charged": false. There is exactly one, it only appears when the input had no channels and no keywords, and it exists so you can look at the output shape before you spend anything.
  • Diagnostic rows carry "_diagnostic": true, "charged": false and an errorCode you can switch on: NO_RESULTS when a channel has no Shorts or a keyword matched none, NOT_FOUND when a handle does not exist, RATE_LIMITED when YouTube throttled the run, SERVER_ERROR when YouTube itself faltered, NETWORK when it could not be reached, and TIME_BUDGET when the run ran out of time before reaching a target. Each carries a plain-English error and the input it belongs to.

If you only want the data, filter on charged == true. The count of those rows always equals the number of events you were billed for, so the dataset is its own invoice.

Channels versus keywords

The two modes behave differently, and it is worth knowing which you want.

A channel returns that channel's Shorts tab, which is already in newest-first order, and pages through it until your row budget runs out. Ask for 500 and you get the 500 most recent Shorts that channel posted.

A keyword returns the Shorts YouTube considers the best matches for that phrase. YouTube will not sort a Shorts-filtered search by date — asking it to do so quietly turns the Shorts filter off and hands back ordinary long videos instead — so sortBy: "newest" orders the Shorts this run actually collected by their real publish date. That is "the newest of the matches found", not "the newest Shorts on YouTube matching this phrase". If you want the latter, run a channel instead: a creator's tab really is chronological.

Limitations

  • A channel that has never posted a Short has no Shorts tab at all. You get one free diagnostic row saying so, and no charged rows. Around one channel in twelve in our test set was like this.
  • likeCount is null when the creator has hidden likes on a Short. That is roughly 2 rows in 100 and there is no way to recover the number.
  • Keyword search returns what YouTube ranks as the best matches, not an exhaustive index. Two runs of the same keyword minutes apart can return a slightly different set, and the row budget decides how deep it goes.
  • Keyword results cannot be sorted newest-first by YouTube itself, so sortBy: "newest" sorts the Shorts the run collected. Channel mode has no such caveat.
  • View and like counts are a snapshot at read time. A Short that is currently trending will read differently ten minutes later.
  • Comment counts, descriptions, hashtags, the audio track and the transcript are not returned. This Actor is the Shorts feed with its headline metrics, nothing more.
  • Age-restricted and members-only Shorts may return without a like count or a publish date; the row still arrives with everything the feed showed, and statsError says why.
  • Private, deleted and region-blocked Shorts never appear in the feed in the first place, so they cannot be returned.
  • Ordering is by publish date, not by views. Sort the dataset yourself if you want the biggest rather than the newest.
  • The hard ceilings are 5,000 rows and 20 targets per run. Split larger jobs across runs.
  • Everything is read logged out, so anything YouTube only shows to a signed-in viewer is out of scope by design.

Questions

How is this different from scraping a channel's videos and keeping the short ones?

Shorts are a separate surface on YouTube, not a length category. A channel's uploads feed and its Shorts tab are different lists, and a Short can run up to about three minutes while plenty of ordinary videos are under a minute. Filtering by duration therefore misses real Shorts and invents fake ones. This Actor reads the Shorts surfaces themselves.

Why are some like counts empty?

The creator turned like counts off for that video. It is a per-video setting and the number is simply not published anywhere, so no scraper can recover it. You still get the row and everything else about it.

Do I need a proxy, an API key or a YouTube account?

None of the three. The run brings its own egress and its cost is already inside the price you see. The proxyUrls field exists only for callers who specifically want traffic to leave through servers they already own.

Will the run fail if a channel does not exist?

No. You get one uncharged diagnostic row for that target and the run carries on to the others, finishing as succeeded. A failed run would still bill the start fee, which would mean paying to be told about a typo.

Can I run this on a schedule?

Yes. Nothing is held between runs, so the same input is safe to repeat. Use videoId to work out which rows are new since last time.

What does turning includeStats off actually save?

It skips one small request per Short, so the run finishes noticeably faster. You keep the title, id, URL, thumbnail, channel and a rounded view count, and you lose the exact view count, the like count, the publish date and the duration. The price per row is the same either way.

How do I get exactly the rows I paid for?

Filter the dataset on "charged": true. Sample and diagnostic rows are always false, and the number of charged rows always equals the number of billed events.