YouTube Search Scraper — Videos by Keyword, Exact Stats
Pricing
from $0.80 / 1,000 video with exact figures
YouTube Search Scraper — Videos by Keyword, Exact Stats
YouTube search results for any keyword, in ranked order: videos and Shorts with unrounded views, likes, publish date and the channel's subscribers — plus chapters and YouTube's AI summary where a result has them. YouTube's own filters, deep paging, only-new mode. No login, no API key.
Pricing
from $0.80 / 1,000 video with exact figures
Rating
0.0
(0)
Developer
Berkan Kaplan
Maintained by CommunityActor stats
0
Bookmarked
7
Total users
4
Monthly active users
17 days ago
Last modified
Categories
Share
foXLabs YouTube series: Channel Email Scraper · Channel Finder · Channel Videos Scraper · Comments Scraper
🔎 Get what YouTube's search returns for your keywords — videos and Shorts, in ranked order — with what the search page does not show: the publish date, the like count, and the size of the channel behind each result. A search is followed to its end, and again — up to four more times — while that still brings enough new videos. Built for content research, finding breakout videos, brand and product monitoring, and video datasets for analysis and AI. No YouTube API key, no login, no cookies.
🔍 What is YouTube Search Scraper — and when should you use it?
Give this Actor keywords — one search per line, as you would type it into YouTube — and it returns one row per video or Short in the order YouTube ranks them, read live from YouTube's own search, with YouTube's own filters (upload date, duration, features, the Popularity order). You choose how much is read for each result: its exact figures (the default), its whole page, or nothing beyond the search result.
Use it when you need: what ranks for a keyword and how those videos did; the videos that out-grew their channel (viewsPerSubscriber); new videos about your products every day, each once; a topic's video set with titles, snippets, chapters and exact figures.
Use something else when: you need a channel's own videos rather than a keyword's (YouTube Channel Videos Scraper), the comments under the results (YouTube Comments Scraper), channels rather than videos (YouTube Channel Finder); or transcripts, tags and categories — this Actor does not read them.
🤖 Use with AI agents
Already on the Apify MCP server? Ask for this Actor by name: foxlabs/youtube-search-scraper. Checked on 2026-10-08: the server lists it as the tool foxlabs--youtube-search-scraper.
Your agent can pay for its own runs. The Actor is pay-per-event only, runs with limited permissions and does not use Standby — Apify's conditions for agentic payments — and Apify Store lists it as eligible for them (read from the Store on 2026-10-08). For an agent with a wallet and no human to sign in, Apify sells a prepaid, spend-capped API token over x402 at agi.apify.com; the terms of that path are Apify's own (see apify.com/agents.md). Billing is the same either way: per delivered video row; status rows are free.
Otherwise paste this into Claude, ChatGPT, Cursor or any MCP-enabled assistant:
I want YouTube search results from the Apify Actor `foxlabs/youtube-search-scraper`.Input: `searchKeywords` is a list of searches. `resultTypes` is ["videos"], ["shorts"] or both. `maxVideosPerKeyword` caps the results per keyword and kind, `maxVideos` the rows in total. `sort` is "relevance" or "popularity"; `uploadedWithin` is "today", "week", "month" or "year"; `duration` is "short", "medium" or "long". `details` is "figures" (publish date and like count — the default), "full" (plus comment count, description, chapters) or "list" (the search result only). `minViewsPerSubscriber` keeps the videos that out-grew their channel.Start with: {"searchKeywords":["drone review"],"maxVideosPerKeyword":50}Ask me what to search for, run the Actor, then show the results as a table with rank, title, channel, views, likes and publish date.
The machine-readable API, MCP config and OpenAPI definition live at apify.com/foxlabs/youtube-search-scraper.md.
📋 Overview
Everything you need to turn YouTube searches into structured rows — in one Actor, with no login, cookies or API key.
Why pick this Actor:
- 🔎 Ranked and deep — every result with its rank: its place in YouTube's first answer, or a number after those for what the search brings when it is followed again. A search is followed to its end, and again while that brings enough new videos: on the platform one keyword gave 515 and 631 different videos in two runs.
- 🔢 Exact figures — unrounded views, likes and the publish date, read from the video itself (where the search page says "7 months ago", the row says 2026-03-04). Where there is nothing to read — a channel that hides its likes, a stream on air, a premiere that has not started — the field is empty, not guessed.
- 📣 The channel behind each result — subscribers, country, lifetime views — and
viewsPerSubscriber: 7 means a video got seven times its channel's subscriber count in views. - 🧩 More from the result itself, at no extra request — chapters (about a third of results over all our runs), YouTube's own AI summary of the video (about one in six), the other channels of a collaboration, the number of tagged products.
- 🎛 YouTube's own filters — upload date, duration, features, the Popularity order — and a switch to search your spelling instead of YouTube's correction of it.
- 🔁 Only what is new — a named list remembers what was delivered; the next run brings only results it has not delivered before.
- 💰 Pay per row, by depth — $0.50 per 1,000 results from the search alone, $0.80 with exact figures, $1.20 with the whole page. Status rows and filtered-out videos are free.
- 🤖 Agent-ready — on the Apify MCP server and open to agentic payments (x402).
✨ Features
- 🎯 Videos and Shorts —
resultTypes: each kind is searched on its own. - 🔬 Three depths —
details:figures(publish date and like count),full(plus comment count, description, hashtags, the page's chapters),list(the search result only — no request per video). - 📊 Channel figures —
channelStats(on by default): one request per channel of the run, however many of its videos the run finds. - 🧹 Filters — YouTube's
uploadedWithin,duration,features,sort; and the Actor'sminViewsandminViewsPerSubscriber. - 🔤 Exact spelling —
exactSpellingsearches the keyword as typed, for brand and product names YouTube would "correct". - 🌍 Country —
countrysets the country the search is made for. - 🔁 Only new —
onlyNewVideoswith alistName: keyword monitoring on a schedule.
🎬 Quick Start
curl -X POST "https://api.apify.com/v2/acts/foxlabs~youtube-search-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"searchKeywords":["drone review"],"maxVideosPerKeyword":50}'
The answer is the dataset itself: the first 50 results with exact figures and channel figures, usually after three to seven seconds of run time.
🚀 Getting Started (3 steps)
- Type your searches — one keyword per line into Search keywords.
- Set the depth, the filters and the limits —
detailsdecides what is read for each result;maxVideosPerKeyword(default 50) andmaxVideos(default 1,000) cap the rows. - Run and export — download the dataset as JSON, CSV, Excel, HTML or XML. To keep watching a keyword, tick Only videos not delivered before, give the list a name and put the run on a schedule.
📥 Input
{"searchKeywords":["drone review"],"maxVideosPerKeyword":50}
| Field | Type | Description |
|---|---|---|
searchKeywords | array | One search per line, as you would type it into YouTube (up to 1,000 lines). |
resultTypes | array | videos, shorts, or both (default ["videos"]). Each kind is searched on its own. |
maxVideosPerKeyword | integer | How many results per keyword and kind (default 50). |
maxVideos | integer | How many rows in total (default 1,000). |
sort | string | relevance (default) or popularity — YouTube's own orders. (For Shorts, Popularity gave next to nothing in our probes: 0 or 1 result in four tries.) |
uploadedWithin | string | any (default), today, week, month or year — YouTube's upload-date filter. |
duration | string | any (default), short (under 3 minutes), medium (3 to 20) or long (over 20). For videos only: a Shorts search is sent without it. |
features | array | Any of live, 4k, hd, subtitles, creative-commons, 360, vr180, 3d, hdr, location. When we picked two (4K with subtitles) YouTube applied both; larger combinations we have not tested. |
exactSpelling | boolean | Search the keyword as typed instead of YouTube's own spelling of it. Default off. |
country | string | Two-letter country code the search is made for (default US). |
details | string | What to read for each video. figures (default): its publish date and like count — one small request. full: its own page — the same, plus the number of comments, the full description, hashtags and the page's chapters; slower, and limited by YouTube (see How it works). list: nothing beyond the search result. |
channelStats | boolean | Add the channel's subscribers, country, lifetime views and number of videos — one request per channel of the run. Default on. |
minViews | integer | Only videos with at least this many views. A stream on air and a premiere that has not started have no view count and do not pass. |
minViewsPerSubscriber | string | Only videos whose views are at least this many times the channel's subscribers (decimals allowed: "0.5"). Needs the subscriber count: leave channelStats on, or use details: "full". |
onlyNewVideos | boolean | Remember delivered videos under listName and skip them in later runs. With this on, maxVideosPerKeyword is how far down the results the Actor looks. Default off. |
listName | string | Name of that memory: letters, digits and hyphens, up to 40 characters (default default). |
proxyConfiguration | object | Nothing to change for normal use: requests go out directly, and a kind of request YouTube refuses is moved to Apify Proxy by the Actor itself. |
More recipes
- The videos that out-grew their channel — at least twice as many views as the channel has subscribers:
{"searchKeywords":["drone review","fpv drone"],"maxVideosPerKeyword":100,"minViewsPerSubscriber":"2"} - This month's videos of 3 to 20 minutes in YouTube's Popularity order (most viewed first, though not strictly sorted):
{"searchKeywords":["skincare routine"],"sort":"popularity","uploadedWithin":"month","duration":"medium","maxVideosPerKeyword":40} - New videos about your products, every day — schedule it daily; a video is delivered once:
{"searchKeywords":["skyrover x1","dji mini 5 pro"],"uploadedWithin":"today","maxVideosPerKeyword":50,"onlyNewVideos":true,"listName":"brand-watch"} - A topic's video set, search results only — the fastest level, no request per video:
{"searchKeywords":["budget mechanical keyboards","mechanical keyboard review","best keyboard switches"],"maxVideosPerKeyword":200,"details":"list","channelStats":false} - Shorts:
{"searchKeywords":["drone review"],"resultTypes":["shorts"],"maxVideosPerKeyword":50}
📤 Output
One row per video (type: "video"). A keyword that brought nothing comes back as a free row with type: "status" and the reason in error (one row per kind of result), and a run whose filters removed every video writes one such row with the run's last word. Two cases write no row, and the status message is where they are told: an "only new" run that finds nothing new (its empty dataset is its answer), and a keyword whose results were all filtered out or all delivered under another keyword of the same run. Every row has the same 51 columns.
| Field | Description |
|---|---|
type | video, or status |
searchKeyword / searchRank / searchPass | The keyword, as you typed it; the result's number among the different results of the search, in the order the Actor met them; and which of YouTube's answers it stood in. With searchPass: 1 the rank is the result's place in YouTube's first answer (1 = first) |
searchEstimatedResults | YouTube's own estimate of how many results the search has — a rough figure that moves from request to request |
videoId / videoUrl / title / videoType | The video (videoId is the stable key) and its kind: video or short |
descriptionSnippet | The lines of the description that YouTube shows under a result; null where the result shows none — among them every Short that came as a shelf card |
aiSummary | YouTube's "AI-generated video summary", where the search result shows one (YouTube adds: "AI can make mistakes"); otherwise null |
channelId / channelUrl / channelHandle / channelTitle / channelIsVerified | The channel the video belongs to, and the verified badge next to its name |
channelSubscribers / channelCountryCode / channelTotalViews / channelVideoCount | channelStats: subscribers as YouTube publishes them (rounded), the country the channel states, its lifetime views and number of videos |
collaborators | The other channels of a collaboration (channelId, channelTitle, channelHandle, rounded subscribers); empty for a video with one channel |
publishedDate / publishedText / daysSincePublished | Publish date from the video itself (figures or full; YouTube shows it in US Pacific time) · what YouTube shows ("Mar 4, 2026" or "7 months ago") · whole days since noon of that day, so a video of the last day can read 0 or 1. A video less than a day old gets the UTC day its hour falls on, and null when that hour holds midnight |
scheduledStartAt | For a premiere or stream that has not started: the moment it is planned for |
durationSeconds | Length of the video; null for streams on air or not started, and for Shorts that YouTube returned as a shelf card |
views / viewsAreExact / viewsText | The view count. Video results carry it unrounded even with details: "list"; viewsAreExact is false only for a Short that came with a rounded count and was not read further |
liveViewers | For a stream that is on air: how many are watching |
likes | Unrounded like count (figures, full). 0 when nobody has liked the video yet; null when the channel hides its like counts (a premiere that has not started can also come without one), and with details: "list" |
commentsCount / commentsCountIsRounded / commentsOff | details: "full" only. Number of comments; YouTube shortens counts of 1,000 and more ("6.1K" → 6100). commentsOff: true when the page shows no comment section |
likeRate / viewsPerDay / viewsPerSubscriber | Likes ÷ views (0.02 = 2%) · views ÷ days since publication · views ÷ the channel's subscribers |
description / hashtags | details: "full" only. The full description, with links that YouTube shows shortened put back as their full addresses; the hashtags YouTube shows above the title |
chapters / chaptersAutoGenerated | title and startSeconds of each chapter. With full: the page's chapters — the creator's own (false) or YouTube's (true). Otherwise: the chapters YouTube shows under the search result, which it does for some videos only, with chaptersAutoGenerated: null |
isLive / wasLive / isUpcoming / isMembersOnly | On air right now · a finished live stream · a premiere or stream that has not started · a video for the channel's paying members (no search result of our runs was one, so this field is untested on real results) |
badges / taggedProducts | The badges YouTube puts on the result ("New", "4K", "CC", "LIVE", "3 products", …) and the number on the products badge |
thumbnailUrl / detailLevel | YouTube's standard thumbnail address · what was read for the row: figures, full or list |
scrapedAt / error | When the row was made · null on video rows, the reason on status rows |
Sample — a row as the Actor returned it on 2026-10-07 with details: "full", every column, nothing shortened:
{"type": "video","searchKeyword": "drone review","searchRank": 2,"searchPass": 1,"searchEstimatedResults": 11070743,"videoId": "rN4hGxTE2hg","videoUrl": "https://www.youtube.com/watch?v=rN4hGxTE2hg","title": "DJI NEO 2 - The Best Beginner Drone EVER!","videoType": "video","descriptionSnippet": "I review the DJI Neo 2 and see if it's the best drone for the beginner. With big upgrades over the original Neo, it's s true follow me ...","aiSummary": null,"channelId": "UCr4-yFNgc44teZJ4DtD5mhg","channelUrl": "https://www.youtube.com/channel/UCr4-yFNgc44teZJ4DtD5mhg","channelHandle": "@MarkMcGeePhotos","channelTitle": "Mark McGee Photos","channelIsVerified": true,"channelSubscribers": 369000,"channelCountryCode": "GB","channelTotalViews": 32804227,"channelVideoCount": 206,"collaborators": [],"publishedDate": "2025-11-14","publishedText": "Nov 14, 2025","daysSincePublished": 327,"scheduledStartAt": null,"durationSeconds": 580,"views": 558794,"viewsAreExact": true,"viewsText": "558,794 views","liveViewers": null,"likes": 6284,"commentsCount": 328,"commentsCountIsRounded": false,"commentsOff": false,"likeRate": 0.0112,"viewsPerDay": 1709,"viewsPerSubscriber": 1.514,"description": "I review the DJI Neo 2 and see if it's the best drone for the beginner. With big upgrades over the original Neo, it's s true follow me flying camera drone. With Active Track improvements, omni directional obstacle avoidance, gesture controls, 4K 60fps and 100fps, Selfie Shot, Dolly zoom and follow modes, the Neo 2 can be flown without and remote control or smart phone. \n\n*Note - to fly Neo 2 with an RC controller, you'll need to purchase the Fly More Combo!\nGet Neo 2 - https://store.dji.com/uk/product/dji-neo-2?vid=204831\n\nMy Headshot Photography Course:\nhttps://bit.ly/My-HS-Course\n\nMy Lightroom Preset Pack:\nhttps://markmcgeephotos.sellfy.store/p/mark-mcgee-preset-pack-vol1/\n\nFollow me:\nhttps://www.instagram.com/markmcgeephotos/?hl=en\n\n00:00 - Intro\n00:50 - 3 Ways to fly Neo 2\n01:46 - Fly with Smart Phone\n03:11 - Dolly Zoom\n04:17 - Fly without Remote or Phone\n04:38 - Selfie Shot\n05:06 - Gesture Controls\n06:35 - 4K 60fps & 100fps\n07:06 - Internal Storage & Quick Transfer\n08:06 - Final Thoughts","hashtags": [],"chapters": [{ "title": "Intro", "startSeconds": 0 }, { "title": "3 Ways to fly Neo 2", "startSeconds": 50 }, { "title": "Fly with Smart Phone", "startSeconds": 106 }, { "title": "Dolly Zoom", "startSeconds": 191 }, { "title": "Fly without Remote or Phone", "startSeconds": 257 }, { "title": "Selfie Shot", "startSeconds": 278 }, { "title": "Gesture Controls", "startSeconds": 306 }, { "title": "4K 60fps & 100fps", "startSeconds": 395 }, { "title": "Internal Storage & Quick Transfer", "startSeconds": 426 }, { "title": "Final Thoughts", "startSeconds": 486 }],"chaptersAutoGenerated": false,"isLive": false,"wasLive": false,"isUpcoming": false,"isMembersOnly": false,"badges": ["4K", "CC"],"taggedProducts": null,"thumbnailUrl": "https://i.ytimg.com/vi/rN4hGxTE2hg/hqdefault.jpg","detailLevel": "full","scrapedAt": "2026-10-07T20:39:48.039Z","error": null}
With the default details: "figures" the same result comes with the same views, likes and date; commentsCount, commentsCountIsRounded, commentsOff and description are null, hashtags is empty, chapters holds what the search result itself showed, and chaptersAutoGenerated is null.
🧠 How it works
For each keyword the Actor asks YouTube's own search, the way its search page does, and builds each row from up to four things — lightest first, a better source replacing what a lighter one said:
- The search result — about 20 a request: title, channel, the unrounded view count, duration, "7 months ago", the description snippet, badges — and, where YouTube shows them, chapters, its AI summary, collaborators and tagged products.
- The video's figures (
details: "figures", the default; one small request per video) — what a video's page keeps refreshing while it is open: the publish date and the like count. - The video's own page (
details: "full", one large request per video) — the same, and the number of comments, the full description, hashtags and the page's chapters. - The channel's panel (
channelStats; one request per channel, however many of its videos the run finds) — subscribers, country, lifetime views.
How deep a search goes. YouTube repeats videos across the pages of a search (11 to 26% of a pass in ten measured passes) and returns a different part of the search every time it is asked. So the Actor follows a search to its end — 220 to 501 different videos in ten measurements — and then again, up to four more times, while a pass still brings enough new ones: at least 10, and at least 5% of what the search had brought before. Four keywords followed this way gave 515 to 664 different videos each in seven measurements; on the platform one keyword gave 515 and 631. (Three of the ten and three of the seven were taken with a probe script through a proxy; the others with this Actor, on the platform or from our own machine through a proxy.) A pass is followed for 60 pages at most (the longest we saw had 32). When a search runs out before maxVideosPerKeyword — its results ended, or following it again no longer brought enough new videos — the status message says so and names up to five such keywords (not in an "only new" run, and not when the run stopped at a limit).
Ranks. searchRank counts the different results in the order the Actor met them. In YouTube's first answer to the search (searchPass: 1) that is the result's place there; what the search brings when it is followed again is numbered after it (searchPass 2 and up) — in one run that followed a keyword to its end, ranks 1 to 314 were the first answer and 315 to 515 came later. Because YouTube's answer changes from request to request, the same search can give a video rank 2 now and rank 5 a minute later. With several keywords in one run a video is delivered once, under the keyword that reached it first, so the other keywords' lists have gaps there (in one of our runs 21 to 27 gaps per 200 rows): for a keyword's full ranking, run it on its own.
Filters. The upload-date, duration and feature filters and the Popularity order are YouTube's own, sent the way its search page sends them. YouTube's answer says which filters it applied; one it did not apply is named in the status message. Two things to know: Popularity brings the most viewed videos first but is not a strict sort by view count (in six samples of 40 results, 4 to 16 of the 39 neighbouring pairs were out of order), and YouTube no longer offers an order by upload date. When YouTube runs out of videos that match an upload-date filter it adds older ones; those are left out, and counted in the status message. That is judged by the age a result shows; a Shorts card shows none, so for Shorts we have one measurement only (25 of 25 within the day).
Features. We sent the ten feature filters with "drone review", 20 results each — eight on their own, 4K and subtitles together: YouTube's answer listed every one as applied. Where a result shows a badge for the feature we counted it: all 20 results of live were on air; all 20 results of vr180 carried the VR180 badge, 18 of the 20 results of 360 the 360° badge and 12 of the 20 of 3d the 3D badge; of the 20 results of 4K with subtitles, 16 carried the 4K badge and 14 the CC badge. YouTube does not put a badge on every result that has a feature, and in these runs showed none for HD, HDR or Creative Commons, so those three could not be checked on the rows. location returned no result for that keyword, and the run said so.
Spelling. YouTube searches for its own spelling of what it takes for a typo — "mechancial keybaord" becomes "mechanical keyboard" — and the status message says when it did. With exactSpelling the keyword is searched as typed: for that example YouTube's estimate fell from millions of results to 304.
Country. For some searches the country changes the results a lot — of the first 20 results for "football highlights", 2 to 4 were shared between the US and the UK, India or Germany — for others hardly at all ("drone review").
Shorts. YouTube answers a Shorts search in three shapes, sometimes in one answer: cards of a Shorts shelf (a title and a rounded view count — no channel, no date, no length), grid items and plain video results. All three are read. For a result that names no channel, figures gets the channel's name and @handle from YouTube's public embed answer, or from the Short's own page when its owner has turned embedding off (one Short in 200 in our measurement). Shorts searches under a filter are erratic on YouTube's side: the same search returned 25 Shorts, then none, then none. An empty answer that comes with an estimate of results is asked for three times before the run says the search is empty. With details: "list" a Short comes as YouTube's answer has it — for a shelf card a title, a rounded view count and the address.
YouTube limits video pages, not the rest. YouTube refuses an address for video pages (HTTP 403) after a number of them, and some addresses from their first pages: 4 of the 11 runs of this Actor with details: "full", and a Shorts run at the default level for the one page it read (a Short whose owner had turned embedding off). The Actor then sends page requests through Apify Proxy, where they are slower (300 pages in 76 seconds in one run and 135 in another, instead of 40 to 45), and keeps everything else direct. If no address is accepted any more, the remaining videos are not left out: they are delivered with their exact figures (detailLevel: "figures", charged as video-exact), and the status message says how many. Searches, figures and channel panels were never refused in the 67 runs whose request log we kept (731, 4,027 and 4,290 requests).
Only new videos. A list name remembers what was delivered. On the next run the Actor looks at the top of each keyword's results — the first maxVideosPerKeyword — and delivers the videos there that it has not delivered before. "New" means new to the list, not newly uploaded: YouTube shows a different part of a search each time, so a later run also brings videos that were online before. In our test — three keywords, uploads of the last week, the first 50 results of each — the first run delivered 149 videos, a second run ten seconds later 23 others, and two more runs two hours later 18 and 19. For newly uploaded videos only, schedule the run daily with uploadedWithin: "today", or filter the rows by publishedDate.
🧪 Data quality — measured
Measured on the Apify platform on 2026-10-07.
figures + channel: one keyword, 300 results | full + channel: one keyword, 300 results | list, no channel figures: one keyword, 300 results | Shorts, figures + channel: one keyword, 50 | |
|---|---|---|---|---|
| Unrounded view count | 300 of 300 | 300 of 300 | 300 of 300 | 50 of 50 |
| Publish date | 300 of 300 | 300 of 300 | 8 of 300 — the videos of the last hours | 50 of 50 |
| Like count | 292 of 300 | 295 of 300 | — | 50 of 50 |
| Duration | 300 of 300 | 300 of 300 | 300 of 300 | 0 of 50 — all came as shelf cards |
| Channel ID and @handle | 300 of 300 | 300 of 300 | 300 of 300 | 50 of 50 |
| Subscribers | 299 of 300 | 298 of 300 | — | 50 of 50 |
| Channel's country | 269 of 300 | 257 of 300 | — | 37 of 50 |
| Chapters | 96 of 300 (as shown in the result) | 216 of 300 (the page's: 59 the creator's, 157 YouTube's) | 102 of 300 | — |
| YouTube's AI summary | 47 of 300 | 56 of 300 | 49 of 300 | — |
| Tagged products | 42 of 300 | 51 of 300 | 50 of 300 | — |
| Number of comments | — | 298 of 300 | — | — |
| Description | — | 298 of 300 | — | — |
| Hashtags | — | 135 of 300 | — | — |
| Unique videos | 300 of 300 | 300 of 300 | 300 of 300 | 50 of 50 |
The four columns are four runs; each run got its own answer from YouTube, so the first three columns are not the same 300 videos.
- Shorts and likes. The last column is one run of 50 Shorts; in three other runs of 200 Shorts each, 188 to 192 came with a like count.
- Where a like count is missing, the channel hides it. The 13 rows without a like count in the first two columns are 8 different videos; we read each of their pages again: each shows a "Like" button without a number. A video nobody has liked yet has
likes: 0— 21 of the 300 in the second column. - Country is filled when the channel states one on its About panel; subscribers are missing where the channel's panel shows no count.
- Comments: the two videos without a count in the second column have no comment section; 23 others say
0, and for all 23 the comment list is headed "0 Comments" (we asked it). - Whose chapters a result shows. 275 videos were read both ways — as a search result and with their page. 91 of the results showed chapters: 56 the creator's, 35 the ones YouTube generates. A result does not say which, so
chaptersAutoGeneratedis filled withdetails: "full"only. - Fresh videos. 100 results of YouTube's "Today" filter (95 of them less than a day old; YouTube also lists "1 day ago" there), with
figures: 94 with a date — 89 of them worked out from "7 hours ago", because YouTube shows no date yet — and 6 without one: each read "22 hours ago" at 22:23 UTC, an hour that holds midnight, so the day would have been a guess between two. All 100 with a view count. - Streams and premieres. In a search for today's uploads that we recorded outside the platform (269 results): 7 on air, 5 not started — each with the moment it is planned for — and 27 finished streams.
- Collaborations. In 15 of 15 collaborations we checked, the first channel YouTube lists is the one the video belongs to; that channel is the row's
channelId, the others are incollaborators.
⏱️ Performance — measured
On the platform with the default 1,024 MB, 2026-10-07.
- 50 results with exact figures and channels (the prefilled input): 3 to 7 seconds of run time in 17 runs.
- 300 results of one keyword with exact figures and channels: 17 to 20 seconds in three runs — about 500 requests. A search is paged one request after the other (0.3 to 0.65 seconds a page). The same 300 as search results only: 15 seconds, 20 requests.
- 1,000 results — five keywords × 200 — with channels,
details: "list": 17 to 20 seconds. 600 results of three keywords without channels: 12 seconds, 42 requests. - One keyword followed to its end: 515 videos as search results only in 44 seconds; 631 with exact figures and channels in 72 seconds.
- 300 results with
details: "full": 40 to 45 seconds from an address YouTube accepted (two runs); 76 to 135 seconds where the pages went through Apify Proxy. - Shorts: 50 with figures and channels in 3 to 4 seconds; 200 of two keywords in 9 to 11 seconds in two runs, and in 34 seconds in a third, in which YouTube refused the one video page the run read and that request took 9.5 seconds through the proxy.
All of this was measured on one evening; YouTube's answer times vary. A run the platform restarts or moves to another server continues from the rows it already delivered: a test run of 600 videos with details: "full" was restarted on purpose when its dataset held 152 rows and ended with 600 different videos.
💼 Use cases
1. Content research — what ranks for a keyword, and why.
Input: your keyword with maxVideosPerKeyword: 100. Output: ranked results with age, length, chapters, views and likes. Use: see what the top results have in common before you make your own video.
2. Finding breakouts — the formats and titles that travel.
Input: topic keywords with minViewsPerSubscriber: "2". Output: only the videos with at least twice as many views as their channel has subscribers. Use: a swipe file of ideas that out-grew their channel.
3. Brand and product monitoring — the new videos YouTube's search lists for your product, each once.
Input: product names with uploadedWithin: "today", onlyNewVideos and a listName, scheduled daily. Output: the day's new videos with channel size and tagged products. Use: alerts for PR, support and affiliate teams.
4. Creator discovery — the channels behind a topic.
Input: topic keywords with channelStats on. Output: every result with its channel's subscribers and country. Use: group by channel to find the creators who rank for your niche.
5. Datasets for analysis and AI agents — a topic's video set.
Input: several related keywords with details: "list". Output: titles, snippets, YouTube's AI summaries, chapters and exact view counts — hundreds of videos in seconds. Use: trend analysis, classification, retrieval.
🔗 Integration
JavaScript / Node.js
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('foxlabs/youtube-search-scraper').call({"searchKeywords":["drone review"],"maxVideosPerKeyword":50});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const row of items.filter((r) => r.type === 'video')) console.log(row.searchRank, row.views, row.viewsPerSubscriber, row.title);
Python
from apify_client import ApifyClientclient = ApifyClient('YOUR_TOKEN')run = client.actor('foxlabs/youtube-search-scraper').call(run_input={"searchKeywords": ["drone review"], "maxVideosPerKeyword": 50})for row in client.dataset(run.default_dataset_id).iterate_items():if row['type'] == 'video':print(row['searchRank'], row['views'], row['viewsPerSubscriber'], row['title'])
Written for apify-client 3 for Python, where call() returns a run object; with version 2 it returns a dict — write run['defaultDatasetId'] there.
Automation (n8n / Zapier / Make): schedule or webhook → run the Actor with your searchKeywords and onlyNewVideos → handle the JSON dataset → push new videos to a sheet, Slack, a CRM or a dashboard.
📊 Pricing
Pay-per-event. Every delivered row carries exactly one of three events, named by its detailLevel:
| Event | When | Price |
|---|---|---|
video | the row was made from the search result alone (details: "list") | $0.0005 a row ($0.50 per 1,000) |
video-exact | the video's exact figures were read (details: "figures", the default) | $0.0008 a row ($0.80 per 1,000) |
video-detailed | the video's own page was read (details: "full") | $0.0012 a row ($1.20 per 1,000) |
Plus Apify's run-start event ($0.00005 for a run with up to 1 GB of memory — the default — also for a run that delivers nothing; Apify counts this event per GB of run memory, so a run you start with more is charged more of them: we measured 256 MB and 1 GB, one event each). Current pricing.
Not charged: status rows, videos that did not pass your filters, and videos that could not be read. A video asked for with full whose page YouTube did not give is delivered with its exact figures and charged as video-exact.
Spending limit. Set a maximum cost per run in the run options. Before every row the Actor checks that it still fits; when the next row would not, it stops delivering, keeps what it has delivered, and says so in its status message.
❓ FAQ
Are the view counts exact? Yes for videos, at every level: YouTube's search results carry the unrounded count. A Short that YouTube returned as a shelf card carries a rounded one ("1.4M views"); figures and full replace it with the exact count, and viewsAreExact tells you which you have.
Why did I get fewer results than maxVideosPerKeyword? Most often the search ran out: YouTube's results ended, or following the search again no longer brought enough new videos — the status message names up to five keywords this happened to. Other causes have their own note there: maxVideos, a filter, a limit that stopped the run; an "only new" run delivers only what is new. A keyword gave 515 to 664 different videos in our measurements (four keywords); narrow keywords and filtered searches give fewer.
Why does a row have no like count? With details: "list" likes are not read. With figures and full, likes is null when the channel hides its like counts; a premiere that has not started can also come without one.
Can I sort by upload date? YouTube no longer offers that order. Use uploadedWithin for recent videos; with figures or full every row then has its publishedDate, except a premiere or stream that has not started and a video less than a day old whose hour holds midnight UTC (6 of 100 in our test of "Today").
Why did a later "only new" run bring videos that are not new uploads? "New" means not delivered to this list before. YouTube shows a different part of a search each time, so a later run can find videos that were online before — in our test every run of the same input brought 18 to 23 videos new to the list, nearly all of them online before. For new uploads only, run daily with uploadedWithin: "today", or filter the rows by publishedDate.
Where is an "only new" list kept? In a key-value store named youtube-search-<listName> in your Apify account; delete it, or use another listName, to start over. It keeps up to 500,000 video IDs and is saved as the run goes. A run that is killed before it could save its last videos — a timeout, for instance — is made up for: the list's next run first reads back what that run delivered.
Does it need a proxy or an API key? No API key, and nothing to set up. Requests go out directly. A kind of request YouTube refuses — in our runs only video pages (read with details: "full", and for a Short whose owner has turned embedding off); never searches, figures or channel panels — is moved to Apify Proxy by the Actor itself. Our tests ran on an account with 30 datacenter proxy addresses (read from the account on 2026-10-08); how the switch behaves on a plan with fewer we have not measured.
Can I export to CSV / Excel / JSON? Yes — directly from the Apify dataset.
🐛 Troubleshooting
- A status row instead of videos — the
errorcolumn says why: "YouTube search returned no videos for …" (nothing matches the keyword and filters), or "… in 3 tries, although it estimates N results" (YouTube answered with an empty page three times: run it again later). - "YouTube's results ended before maxVideosPerKeyword for N keywords" — those searches ran out: YouTube's results ended, or following them again brought too few new videos.
- "YouTube searched for its own spelling of N keywords (…)" — turn on
exactSpellingto search as typed. - "N results older than the upload-date filter were left out" — YouTube ran out of matching videos and added older ones.
- "YouTube did not apply this filter: …" — YouTube's answer did not list the filter as applied; the results may be unfiltered in that respect.
- "… videos did not pass your filters (…)" — the status message counts the videos each filter removed.
- "No new videos, no rows charged …" — nothing that the list
listNamehas not delivered before stood at the top of the results (or nothing of it passed your filters). - "… videos came with exact figures only … because YouTube did not give their pages" — the
fulllimit described under How it works. The rows are markeddetailLevel: "figures"; run those keywords again later for the rest. - "Stopped at maxVideos (1000)", with or without "The run stopped at maxVideos before it got to N of its M keywords" — the total limit was reached first. Raise
maxVideos, or lowermaxVideosPerKeywordso the keywords share the run. - "No videos delivered, no rows charged: none of the videos found could be delivered. … Loosen the filters to get results." — every video was filtered out; the dataset holds this one status row.
- "… another run of the list … is in progress, or was cut off in the last three minutes" — two runs of the same
listNamewould deliver the same videos; start the second when the first has finished.
🚧 What it does not do
- No channels or playlists as results: videos and Shorts only.
- No transcripts, no comment texts, no video or audio files.
- No tags and no category: they come with the player data, which YouTube refused to one of the two server addresses we tried; this Actor does not read it.
- No order by upload date (YouTube removed it); use
uploadedWithin. - Subscriber counts are YouTube's rounded figures. Comment counts of 1,000 and more are shortened by YouTube.
- After a restart by the platform the search is asked again, so the ranks of rows written after the restart belong to the new answer.
- Every request is made in English, so texts such as "7 months ago" are English;
countrysets the country of the search only. A keyword may be up to 200 characters; keywords that differ only in upper and lower case are one search. - A run reads at most 50 videos for every row it may deliver (
maxVideos), and at least 300; a run whose filters turn down nearly every video it reads in detail ends with "stopped after reading N videos" (videos a filter rules out from the search result alone are not counted as read; we have not seen this message on the platform). - YouTube can change its pages at any time; a number or date that cannot be read is
null. Four values are worked out rather than read:videoType, from the kind of result YouTube gave;publishedDatefrom "7 hours ago" for a video less than a day old (only where the hour named lies within one UTC day);commentsCount: 0for a page whose comments panel shows no number; andviewsPerDayon the day of publication, which is the views so far.
⚖️ Is it legal to scrape YouTube search results?
The Actor reads only what YouTube shows to every visitor who is not signed in: no login, no cookies, no CAPTCHA solving. Search results, video figures and channel figures are public information; a description can name people or contact details, so use the data for a lawful purpose under the law that applies to you and check that your use fits YouTube's terms. YouTube is a trademark of Google LLC; this Actor is not affiliated with, endorsed or sponsored by YouTube or Google.
🤝 Support & contact
- 🌐 Website: data.foxlabs.com.tr
- 📧 Email: info@foxlabs.com.tr
- 🐛 Issues: open a ticket in the Actor's Issues tab
- 🧰 More data actors: Fox Labs on Apify
Changelog
0.1.13 — 2026-10-08
- A run that delivers nothing now says "no rows charged" (it said "nothing charged"; the run-start event applies to every run). This README was corrected after an independent fact-check — the list is in the Changelog tab.
0.1.11 and 0.1.12 — 2026-10-08
- A Short whose owner has turned embedding off comes with its channel's @handle. A killed run of an "only new" list is made up for by the list's next run.
0.1 — 2026-10-07 — first version
- YouTube search for videos and Shorts in ranked order, followed to its end and again while that brings new videos.
- Three levels of detail per video — exact figures, the whole page, search results only — each with its own price; the channel behind each result and views per subscriber.
- Chapters, YouTube's AI summary, collaborators and tagged products from the result itself; YouTube's own filters and exact spelling; streams and premieres told apart.
- "Only new videos" lists for monitoring; runs that continue after a restart; a spending limit that is exact. The full list is in the Changelog tab.