apihq/youtube-search-scraper · YouTube
YouTube Search Scraper
Search YouTube by keyword and export one JSON row per result — video, channel, or playlist. No YouTube Data API key or quota.
$0.0002/result · failed items $0.0000 — on your existing Apify account, a one-item first run costs under a cent.
What does YouTube Search Scraper do?
Search YouTube and export results to JSON by keyword. No YouTube Data API key or quota. One record per result (video, channel, or playlist) with title, views, and channel. Filter by type, date, and duration. Queries that return nothing are free. $0.20 per 1,000 results.
Turning a keyword into a dataset: competitor and market research, trend discovery, tracking who ranks for a term, and collecting video IDs to feed transcript or comment jobs.
YouTube sets the search depth, not you. Results stop when relevance runs out — usually in the low hundreds per query. maxResults is a ceiling, not a guarantee.
Example run
{
"queries": ["lofi hip hop", "synthwave"],
"type": "video",
"sortBy": "views",
"uploadDate": "month",
"maxResults": 5
}outcome
- Up to 5 success: true video rows per query — the most-viewed long-form lofi and synthwave videos of the month — billed
- Each row carries the video, its channel, views, and thumbnail
- Run status: SUCCEEDED
- Charged: up to 10 results = $0.002
Good input returns billed rows. Bad input returns free error rows in the same dataset, and the run still succeeds.
Why pipelines pick it
No YouTube Data API key or quota
The actor reads YouTube's public search directly. No key to provision, no daily quota to ration, and it returns as many results as YouTube serves for the query.
You pay only for results
Billing fires on an explicit per-result event, not on dataset writes. A query that returns nothing sits in your dataset for free, and there is no per-run start fee.
A bad filter never breaks the batch
An unusable filter value or a query that finds nothing returns a success: false record with a stable code (NO_RESULTS, VALIDATION_FAILED, SEARCH_TIMEOUT, DEADLINE_EXCEEDED). Branch on the code, not on English.
One search feeds the other actors
Search collects video IDs and channels for a keyword; the transcript, comments, and channel actors go deep on each hit.
Best for: Turning a keyword into a dataset: competitor and market research, trend discovery, tracking who ranks for a term, and collecting video IDs to feed transcript or comment jobs.
Input & output
{
"queries": ["lofi hip hop", "synthwave", "jazz for studying"],
"type": "video",
"maxResults": 200,
"sortBy": "views",
"uploadDate": "month"
}{
"success": true,
"result_type": "video",
"search_query": "lofi hip hop",
"video_id": "n61ULEU7CO0",
"title": "Best of lofi hip hop 2021",
"url": "https://www.youtube.com/watch?v=n61ULEU7CO0",
"view_count": "55,765,840 views",
"duration": 22258,
"channel_name": "Lofi Girl",
"channel_id": "UCSJ4gkVC6NrvII8umztf0Ow"
}{
"success": false,
"search_query": "asdkjfhqwiuerypoxzcv",
"code": "NO_RESULTS",
"error": "Search returned no results for query: asdkjfhqwiuerypoxzcv",
"request_id": "req_911f37d2e55644ff",
"status_code": 404
}Branch on the success field to split hits from misses. Quote the request_id in any support issue and we can trace the exact request.
output fields
| field | type | what it is |
|---|---|---|
| success | boolean | true for a result (billed), false for a query that returned nothing (not billed). |
| result_type | string | video, channel, playlist, or shorts. |
| search_query | string | The search term that produced this row; every row stands alone. |
| title | string | Video or playlist title, or the channel name. |
| url | string | Canonical URL of the result (watch, shorts, channel, or playlist). |
| video_id | string | The 11-character video ID (video and shorts rows). |
| view_count | string | View count as a display string. May be empty. |
| duration | integer | Video length in whole seconds. Absent for live streams. |
| channel_name | string | Uploader or owner name (video and playlist rows). |
| channel_id | string | The UC… channel ID, where available. |
| subscriber_text | string | Subscriber count as a display string (channel rows). |
| playlist_id | string | The playlist ID (playlist rows). |
Error codes, stable across releases
Every failure record carries one of these machine-readable codes. None of them are ever charged.
| code | billed | meaning |
|---|---|---|
| NO_RESULTS | $0.0000 | The query returned no results. The row is retained, unbilled. |
| VALIDATION_FAILED | $0.0000 | The input was not a usable query or filter value. |
| SEARCH_TIMEOUT | $0.0000 | The search request itself timed out. |
| DEADLINE_EXCEEDED | $0.0000 | The 30-second per-page deadline was hit. Returned as an unbilled row with status_code 504. |
What a run costs
The charge fires only when a result is delivered, and platform compute is included in the per-result price. To cap the spend of a run, set a limit in Apify's Run Limits panel. The actor stops at the cap and reports how far it got.
What this actor doesn't do
- YouTube sets the search depth, not you. Results stop when relevance runs out — usually in the low hundreds per query. maxResults is a ceiling, not a guarantee.
- type: video is the default and returns only videos. Set channel, playlist, or all for the rest; Shorts appear under all.
- One row per result, with what search exposes: title, channel, views, thumbnail. Full descriptions, like counts, and tags require opening each video and are out of scope.
- Public results only — the search returns what a signed-out visitor sees.
Frequently asked questions
- Do I need a YouTube Data API key?
- No. The actor reads YouTube's public search directly and does not consume Google API quota.
- How many results can I get per query?
- As many as YouTube serves for that term, capped by maxResults. YouTube stops paging when relevance runs out — for most queries that is in the low hundreds. There is no fixed 500-result ceiling like the official Data API, but depth is finite and set by YouTube.
- Can I search for channels or playlists, not just videos?
- Yes. Set type to channel or playlist. all returns a mix of videos, channels, playlists, and Shorts. The default, video, returns only videos.
- Why did I get fewer results than maxResults?
- YouTube ran out of results for that query first. maxResults is a ceiling, not a guarantee, and the video filter is shallower than an unfiltered all search.
- How does billing know a query returned nothing?
- Billing fires on an explicit per-result charge event, not on dataset writes. success: false records sit in your dataset for free, with a code and a request_id for support.
- Can I also get transcripts, comments, or a channel's uploads?
- Yes — search collects the video IDs, and the sibling actors go deep: YouTube Transcript Scraper for captions, YouTube Comments Scraper for comments, YouTube Channel Scraper for a channel's videos.
Automation templates
Pairs with
YouTube Transcript Scraper
Scrape YouTube transcripts, captions, and subtitles as timestamped JSON. One video or a batch of 50. No YouTube Data API key or quota, no browser.
YouTube Comments Scraper
Export a YouTube video's comments and replies to JSON from a URL or video ID. One record per comment with author, likes, replies, and timestamp.
Run it on the Apify account you already have
Paste one input into the actor's console and check the dataset it returns. A one-item first run costs under a cent — no new subscription, pay only for delivered results.
Search one keyword