YouTube Search Scraper avatar

YouTube Search Scraper

Pricing

$0.20 / 1,000 results

Go to Apify Store
YouTube Search Scraper

YouTube Search Scraper

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.

Pricing

$0.20 / 1,000 results

Rating

0.0

(0)

Developer

apihq

apihq

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

Search YouTube and export the results as clean JSON from a keyword. No YouTube Data API key, no quota, no browser.

The contract is simple: a query that finds nothing never fails your run, and you only pay for results delivered. Search a batch of keywords, filter by type, date, or duration, and get one row per result. Pay-per-result at $0.20 per 1,000 results. Queries that return nothing cost $0.

See one run

Input:

{
"queries": ["lofi hip hop", "synthwave"],
"type": "video",
"sortBy": "views",
"uploadDate": "month",
"duration": "long",
"maxResults": 5
}

What comes back:

  • Up to 5 success: true video rows per query, billed: the most-viewed long lofi and synthwave videos from the past month
  • Each row carries the video, its channel, views, and thumbnail
  • Run status: SUCCEEDED
  • Charged: up to 10 results = $0.002

query alone works too. Every knob above is optional: type (videos, channels, or playlists), sortBy (relevance, date, views, or rating), uploadDate (last hour through this year), and duration (short, medium, or long). A query that returns nothing is a free success: false row, so one miss never blocks the batch.

Why this Actor

  • No YouTube Data API key or quota. Many search workflows lean on Google's official Data API, with its keys to provision, daily quota accounting, and per-call limits. This Actor reads YouTube's public search directly, so there is no key to provision and no 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, so a query that returns nothing sits in your dataset for free. There is no per-run start fee, so an empty run costs zero.
  • A bad filter never breaks the batch. An unusable filter value or a query that finds nothing returns a success: false record with a machine-readable code (NO_RESULTS, VALIDATION_FAILED, SEARCH_TIMEOUT, DEADLINE_EXCEEDED). Branch on code without parsing English.

Best for

Data and AI workflows that turn a keyword into a dataset: competitor and market research, trend and topic discovery, tracking who ranks for a term, and collecting video IDs to feed transcript or comment jobs. The failure-free billing and machine-readable error rows matter most when the search runs unattended inside a larger pipeline, where one query with no results should never take down the batch. It works fine for one-off manual pulls too.

Input example

A single search, videos only:

{
"query": "python tutorial",
"type": "video",
"maxResults": 100,
"sortBy": "views",
"uploadDate": "month"
}

A batch of keywords:

{
"queries": ["lofi hip hop", "synthwave", "jazz for studying"],
"type": "video",
"maxResults": 200
}

query and queries are merged and de-duplicated. Up to 50 unique queries run per job. Each query is walked page by page until it reaches maxResults or YouTube runs out of results. Filters (type, sortBy, uploadDate, duration) apply to every query in the run.

Output example

One record per result. The search term is copied onto every row so each row stands alone. A video result:

{
"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",
"thumbnail_url": "https://i.ytimg.com/vi/n61ULEU7CO0/hqdefault.jpg",
"view_count": "55,765,840 views",
"published": "4 years ago",
"duration": 22258,
"is_live": false,
"description_snippet": "The best lofi hip hop songs of 2021, all in one mix.",
"channel_name": "Lofi Girl",
"channel_id": "UCSJ4gkVC6NrvII8umztf0Ow",
"channel_url": "https://www.youtube.com/@LofiGirl"
}

A query that returns nothing lands in the same dataset and is not charged:

{
"success": false,
"search_query": "asdkjfhqwiuerypoxzcv",
"code": "NO_RESULTS",
"error": "Search returned no results for query: asdkjfhqwiuerypoxzcv",
"request_id": "req_911f37d2e55644ff9d9e4a3f",
"status_code": 404
}

Split hits from misses on the success field, and the kind of hit on result_type. Quote request_id in any support issue and we can trace the exact request.

What you get

Every result is one record with success: true. result_type tells you which kind, and which fields the row carries:

FieldTypeOn which rowsWhat it is
successbooleanalltrue for a result (billed), false for a query that returned nothing (not billed).
result_typestringallvideo, channel, playlist, or shorts.
search_querystringallThe search term that produced this row.
titlestringallVideo/playlist title, or the channel name.
urlstringallCanonical URL of the result (watch, shorts, channel, or playlist).
thumbnail_urlstringallURL of the largest available thumbnail. May be empty.
video_idstringvideo, shortsThe 11-character video ID.
view_countstringvideo, shortsView count as a display string. May be empty.
publishedstringvideoRelative publish string (for example 5 years ago). May be empty.
durationintegervideoLength in whole seconds. Absent for live streams.
is_livebooleanvideotrue for a live stream.
description_snippetstringvideo, channelA short description excerpt. May be empty.
channel_namestringvideo, playlistUploader or owner name.
channel_idstringvideo, channel, playlistThe UC... channel ID, where available.
channel_urlstringvideoUploader channel URL. May be empty.
channel_handlestringchannelThe channel @handle. May be empty.
subscriber_textstringchannelSubscriber count as a display string (for example 506M subscribers).
playlist_idstringplaylistThe playlist ID.
video_countstringplaylistPlaylist size as a display string (for example 34 videos).

Queries that returned nothing carry success: false, search_query, a machine-readable code, a human-readable error, the service request_id, and the HTTP status_code. They are not charged.

Pricing

Pay-per-result. One charge per result delivered: $0.0002 each, which is $0.20 per 1,000 results. The charge fires only after a result row lands in your dataset.

  • 1,000 delivered results cost $0.20.
  • A run whose queries all return nothing costs $0.
  • There is no per-run start fee, so an empty run is genuinely free.

Apify subscriber discounts apply automatically: roughly $0.16 per 1,000 on the Scale plan and $0.12 per 1,000 on Business. Platform compute is included in the per-result price. Cap the maximum spend of a single run from Apify's Run Limits panel; the Actor honors the cap and stops cleanly mid-walk when the budget runs out.

What this Actor does not do

Honest scope, so you know before you run it:

  • YouTube sets the depth, not you. YouTube stops serving results for a query when relevance runs out, usually in the low hundreds. A high maxResults returns everything available, which for many queries is fewer than the number you asked for. This is not a fixed cap like the Data API's 500, but it is not unlimited either.
  • video is the default and returns only videos. Set type to channel or playlist for those, or all for a mix (which also surfaces Shorts). There is no standalone shorts type; Shorts appear under all.
  • One row per result, with what search exposes. You get the title, channel, views, and thumbnail search shows. Full descriptions, like counts, comment counts, and tags require opening each video and are out of scope here.
  • Public results only. The search returns what a signed-out visitor sees.

How to use this Actor

  1. Open the Actor in the Apify Console.
  2. Set query (single), queries (a list), or both. Up to 50 unique queries run per job.
  3. Set maxResults to cap results per query. Optionally set type (video, channel, playlist, or all), sortBy (relevance, date, views, rating), uploadDate, and duration. Filters apply to every query.
  4. Click Start. Each result is one success: true record. Queries that return nothing produce one success: false record and do not stop the run. Only results are charged.

The Actor is also callable from the Apify API and every official integration (Make, Zapier, n8n, Slack, webhooks). The API tab in the Console has ready-to-paste JavaScript, Python, and curl snippets.

Reliability

A bad filter or a query with no results never fails the batch. An unusable filter value or a query that finds nothing becomes a success: false record with a specific code. The run keeps going and finishes successfully.

You never pay for a miss. Billing fires on an explicit per-result charge event, not on dataset writes, so success: false records are free. There is no per-run start fee either.

Hard 30-second deadline per page request. Each page of results is fetched under a 30-second deadline. If YouTube or the proxy network stalls, that query returns a 504 with code: DEADLINE_EXCEEDED as a success: false record instead of hanging your run.

FAQ

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, which for most queries is in the low hundreds. There is no fixed 500-result ceiling like the official Data API, but no query is unlimited either.

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.

Can I filter and sort?

Yes. sortBy takes relevance (default), date, views, or rating. uploadDate and duration narrow video results. Filters apply to every query in the run.

Why did I get fewer results than maxResults?

YouTube ran out of results for that query first. maxResults is a ceiling, not a guarantee; the depth of any search is set by YouTube, and the video filter is shallower than an unfiltered all search.

Can I also get transcripts, comments, or a channel's full uploads?

Yes, with the sibling Actors: YouTube Transcript Scraper for captions, YouTube Comments Scraper for comments, YouTube Channel Scraper for a channel's videos, and YouTube Shorts Scraper for Shorts. Search collects the video IDs; the sibling Actors go deep on each.

Can I use this Actor from my own code?

Yes. Use the Apify API or one of the official SDKs (Node.js: apify-client, Python: apify-client). The Console shows ready-to-paste code samples on the API tab.

How does billing know a query returned nothing?

Billing fires on an explicit per-result charge event, not on dataset writes. The Actor only fires it when a result is delivered, so success: false records sit in your dataset for free. You get every result in one place and still branch on success and code, with a request_id for support correlation.

Found a bug or want a feature?

Open an issue on this Actor's Issues tab and include the request_id from any error record you saw. We respond within one business day.