Most people building a youtube shorts api pipeline start with the search endpoint and get nothing. This repo starts by proving why, then gives the route that works: the Shorts tab for discovery at 1 credit, and the metadata endpoint for the numbers.
Built on ScrapingBee's web scraping API and its dedicated YouTube endpoints. Verified live on 2026-09-15.
This is worth settling before you write any code. Three content queries, 20 results each, every duration recorded:
| Query | Results | Shortest video |
|---|---|---|
satisfying asmr |
20 | 4:38 |
kitchen hack |
20 | 5:34 |
gym fail |
20 | 5:10 |
Sixty videos, and not one under four and a half minutes. The full duration list for satisfying asmr runs 8:02, 20:01, 2:23:20, 3:07:51, 1:00:03 ... 24:00:00, including two twenty four hour livestreams.
Searching for the word "shorts" is no better. It returns long compilations about the format:
13:03 2,789,749 views World's FUNNIEST YouTube Shorts!
46:43 2,882,326 views I Tested Clickbait Shorts
1:04:53 687,709 views 1 HOUR of Genius Secrets I Learned on Yo
And in that entire 459,893 character response: zero /shorts/ URLs, zero reelWatchEndpoint, zero reelItemRenderer.
The reason is structural. YouTube puts Shorts in a separate shelf on the results page, and the endpoint returns the videoRenderer items only, so the Shorts shelf never reaches you. No parameter changes this. Filtering search output by duration returns an empty list, which is exactly what you would expect once you know the shelf is missing.
A channel's Shorts tab, through the standard HTML API. 1 credit.
curl -G "https://app.scrapingbee.com/api/v1/" \
-H "Authorization: Bearer $SCRAPINGBEE_API_KEY" \
--data-urlencode "url=https://www.youtube.com/@MrBeast/shorts" \
-d mode=autoThat returned 1,179,717 bytes containing 48 unique Shorts video IDs, every one of them a genuine Short because the tab only lists Shorts. Pull them with one regex:
ids = sorted(set(re.findall(r"/shorts/([A-Za-z0-9_-]{11})", html)))
len(ids) # 48This is the counterintuitive part. Five runs against the same URL:
| Configuration | Credits | Bytes | Shorts IDs found |
|---|---|---|---|
mode=auto |
1 | 1,177,147 | 48 |
mode=auto |
1 | 1,178,599 | 48 |
mode=auto |
1 | 1,186,131 | 48 |
render_js=true |
5 | 585,819 | 0 |
render_js plus premium_proxy |
25 | 1,670,707 | 48 |
The 5 credit rendered fetch returns roughly half the bytes and not a single Short. Paying more for a browser actively breaks this page. The delivered HTML already carries everything, so mode=auto at 1 credit is both the cheapest and the most reliable option, and it was consistent across three consecutive runs.
Guard against the occasional empty response anyway. If the ID list comes back empty, retry rather than concluding the channel has no Shorts.
Two markers in that page worth knowing. shortsLockupViewModel appears 49 times and /shorts/ 48 times. reelItemRenderer, which most older scraping guides tell you to look for, appears zero times. YouTube renamed that renderer, so a parser written against the old name silently finds nothing on a page that is full of Shorts.
Authentication on the HTML API is the same header: Authorization: Bearer YOUR_API_KEY.
GET https://app.scrapingbee.com/api/v1/youtube/metadata?video_id=<id>
5 credits. The parameter is video_id. It is not search, and sending the wrong one produces a precise error at 0 credits:
{"errors": {"query": {"search": ["Unknown field."], "video_id": ["Missing data for required field."]}}}Unlike search, metadata returns a clean flat object with 19 keys and no wrappers:
video_id title description duration view_count like_count comment_count
channel_id channel_url uploader uploader_id uploader_url upload_date
categories tags thumbnails formats is_live age_limit
duration is an integer in seconds, which is the definitive Shorts test. Live results from three IDs pulled off the tab above:
| video_id | duration | views | likes | title |
|---|---|---|---|---|
5mU6SRS2Bxo |
36 | 12,840,911 | 280,412 | World's Largest Tennis Match |
6W_841xoprg |
30 | 121,014,585 | 2,224,624 | Can a Window Stop a Wrecking Ball? |
897gvApD6V4 |
8 | 800,626,321 | 3,822,847 | Will a Zebra Subscribe to me? |
like_count and comment_count exist nowhere else. Search gives you a view count string and nothing on engagement, so the metadata call is what makes performance analysis possible at all.
One of the four IDs tested returned this instead of a video:
{"error": "Something went wrong, please try again later or contact support."}The same ID retried immediately returned duration: 36 and a full record. So treat a response whose only key is error as transient rather than as a dead video, and retry once before you write the ID off. The call is still billed, so a naive retry loop costs real credits.
Discovery is nearly free and confirmation is where the money goes:
1 channel Shorts tab = 1 credit -> 48 video IDs
48 metadata calls = 240 credits -> durations, views, likes, comments
-----------
241 credits for one channel's Shorts catalogue
At the entry paid tier of 250,000 credits that is roughly 1,000 channel sweeps a month, or far more if you only pull metadata for the IDs you have not seen before. Cache the IDs. A channel's back catalogue does not change, only the tail does.
If all you need is the ID list and posting cadence, stop after the 1 credit call.
def engagement(meta):
views = meta["view_count"]
return (meta["like_count"] + meta["comment_count"]) / views if views else NoneOn the wrecking ball Short: 2,224,624 likes over 121,014,585 views is 1.84 percent. On the zebra Short: 3,822,847 over 800,626,321 is 0.48 percent. Same channel, same format, nearly four times the rate on the lower view count, which is the kind of comparison the raw view number hides.
GET /api/v1/youtube/subtitles takes video_id on the same convention and returns the caption track, which is how you classify what a Short is about without watching it. Also 5 credits. The YouTube captions API and YouTube transcript scraper API pages cover that surface.
Measured from spb-cost response headers:
| Call | Credits |
|---|---|
Channel Shorts tab via the HTML API, mode=auto |
1 |
/youtube/metadata |
5 |
/youtube/subtitles |
5 |
/youtube/search, which will not help you here |
5 |
| Rejected request (wrong parameter name) | 0 |
The YouTube endpoints are flat 5 with no light request discount and no proxy tier to pick, so budgeting is 5 * calls. The discovery step is on the HTML API instead, which is why it lands at 1.
Failed requests are retried inside the API for up to 30 seconds, so keep client timeouts above that. Plan tiers are on the pricing page.
Public channel Shorts tabs and public video metadata. Private and unlisted videos, members only content, YouTube Studio analytics and anything requiring a signed in session are out of reach, and scraping under login credentials is prohibited by ScrapingBee's terms of service.
Channel names, handles and uploader IDs belong to real people, so treat them as personal data where that applies. YouTube's Terms of Service govern use of the data, and Google publishes an official YouTube Data API which is the right tool when its quota and scope fit your case.
Adjacent endpoints: YouTube video scraper API, YouTube comment scraper API, YouTube playlist results API, YouTube music API, YouTube title scraper API, YouTube metatags, YouTube movie results API.
Why does my Shorts search return no Shorts? Because the search endpoint returns only the long form video shelf. Measured across 60 results from three queries, the shortest was 4:38. Use a channel Shorts tab for discovery instead.
How do I tell a Short from a normal video?
duration <= 180 from the metadata endpoint. It is an integer in seconds, so it is one comparison and no string parsing.
What replaced reelItemRenderer?
shortsLockupViewModel. Parsers written against the old renderer name find nothing on a current Shorts tab.
Can I get Shorts by hashtag or topic? Not from these endpoints. Discovery is channel scoped. Build a channel list first, then sweep.
Why did one metadata call return an error object?
Transient. Retry once. A response whose only key is error is not the same as a removed video.
MIT. See LICENSE.