YouTube Search Scraper
Pricing
from $0.45 / 1,000 results
YouTube Search Scraper
Search YouTube by keyword, hashtag, Trending chart, Hype chart, or Home feed. Filter by content type, upload date, and duration, paginate automatically, and export structured video, channel, and playlist rows.
Pricing
from $0.45 / 1,000 results
Rating
0.0
(0)
Developer
The Netaji
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
The Actor collects public YouTube listings from six different surfaces — keyword search, hashtag feeds, the regional Trending charts, the Hype chart, the localized Home feed, and search autocomplete — and returns them as structured rows. It follows YouTube's own pagination where pagination exists, and stops cleanly where it does not. No YouTube account, API key, or cookie is required.
Selecting a workflow
scraperType decides what a run collects, and it is the only required field.
| Value | Collects | Needs |
|---|---|---|
search | Keyword search results | search_term |
hashtag | Videos or Shorts carrying a hashtag | hashtag |
trending | A regional Trending chart | region_code |
hype | The localized Hype chart | Nothing |
home | The localized Home feed | Nothing |
suggestions | Search autocomplete phrases | search_term |
Because one Actor covers six surfaces, every field is visible in every mode. Each field's description names the workflow it belongs to, and fields belonging to other workflows are ignored rather than rejected.
Accepted input
| Field | Type | Default | Description |
|---|---|---|---|
scraperType | enum | search | Required. Workflow to run. |
search_term | string | — | Keyword search and Search suggestions. Suggestions also accepts partial text. |
hashtag | string | — | Hashtag workflow. Text without the #. |
maxItems | integer | 50 | Maximum rows saved. 0 continues to the last available page. |
resume_cursor | string | — | Continue a previous run. Paste the resume token from that run's log. |
region_code | string | US | Two-letter country code used to localize results. |
language_code | string | en | Language code for result text, such as en, es, pt-BR. |
Keyword search only:
| Field | Type | Description |
|---|---|---|
result_kind | enum | video, shorts, channel, playlist, movie. |
length_filter | enum | under_3_minutes, between_3_and_20_minutes, over_20_minutes. |
published_within | enum | today, week, month, year. |
sort_order | enum | relevance or popularity. |
Hashtag and Trending:
| Field | Type | Default | Description |
|---|---|---|---|
content_kind | enum | all | Hashtag workflow. all reads the hashtag's video feed, shorts reads its Shorts feed. |
trend_category | enum | now | Trending workflow. now, music, or games. |
{"scraperType": "search","search_term": "indoor herb garden","result_kind": "video","published_within": "month","sort_order": "popularity","maxItems": 100,"region_code": "US"}
How much each surface returns
This is the single most useful thing to know before setting maxItems, because only three of the six surfaces paginate at all.
| Workflow | Paginates | Typical ceiling per run |
|---|---|---|
| Keyword search | Yes | Continues while YouTube serves pages |
| Home feed | Yes | Continues while YouTube serves pages |
Hashtag, content_kind: shorts | Yes | Continues while YouTube serves pages |
Hashtag, content_kind: all | No | One page, around 25 rows |
| Trending | No | One chart: about 49 rows for now and games, about 30 for music |
| Hype | No | One chart, about 100 rows |
| Search suggestions | No | One response, usually under 20 phrases |
Setting maxItems to 500 on Trending returns the chart and stops. That is the chart's real length, not a truncated run.
Page sizes are not fixed even where pagination works. Keyword search has returned 21 rows on a first page and 11 on the next, so maxItems is enforced on rows saved rather than on pages fetched.
Response fields
One row per result. Fields present depend on the surface — Hype returns a compact row, keyword search returns the richest one.
| Field | Contents |
|---|---|
recordType | Which workflow produced the row, such as search_result or trending_result |
source | The query, hashtag, or workflow that produced the row |
type | YouTube's own label: video, shorts, channel, playlist |
videoId | Video or Shorts ID |
channelId, channelTitle, channelHandle | Publishing channel |
title | Public title |
url | Canonical URL, derived from the identifier |
description | Description snippet as shown in the listing |
thumbnail | Thumbnail images, largest last |
viewCount, viewCountText | Numeric and human-readable view counts |
lengthText | Duration, such as 2:22 |
publishedTimeText, publishedAt | Relative and ISO 8601 publication time |
isVerifiedChannel | Whether YouTube shows a verified badge |
suggestion | The suggested phrase, in the Search suggestions workflow |
position | One-based position within the run |
meta | Context for the listing, where YouTube supplies it |
{"recordType": "trending_result","type": "video","videoId": "G6VHDpCtvLU","title": "VonOff1700 - All Is (Official Video)","channelTitle": "VonOff1700","url": "https://www.youtube.com/watch?v=G6VHDpCtvLU","viewCount": "82195","likeCount": "6741","commentCount": "385","lengthText": "2:22","publishedAt": "2026-07-29T19:00:38Z","position": 1}
YouTube does not return a URL on any of these surfaces — it returns bare identifiers — so url is derived from the row's own ID. Shorts get the /shorts/ form, playlists the ?list= form.
Trending is the only listing that carries likeCount and commentCount, because the chart is the only surface where YouTube publishes them alongside the listing.
Behaviour on partial results
Promoted results are removed before rows are saved. YouTube injects advertisements into search and browse feeds marked type: "ad"; they are dropped, so they are neither saved nor billed.
A failing page is retried rather than abandoned: three attempts, waiting 3 and then 10 seconds. Three is deliberate rather than cautious — transient failures are already retried closer to the source before this Actor sees them, so a longer ladder here would multiply into a great many redundant requests without improving the odds. What it adds is patience, since the waits nearer the source are only seconds apart and do nothing for a source that is briefly refusing traffic.
Pages cannot be skipped. The cursor for the next page arrives inside the current page's response, so a page that never returns takes the rest of the walk with it; retrying it is the only way forward. When the retries are spent, collection ends, the rows already gathered are kept, and the log prints a resume token.
The exception is the first page: if that fails, the run fails. An empty run reported as successful would read as "nothing matched" when the truth is "the source could not be reached", so that case is surfaced as an error rather than an empty dataset.
Resuming a run
Whenever a run stops with more results still available — because maxItems was reached, or because a page could not be fetched — the log ends with:
Resume cursor for the next run: EpUDEhJpbmRvb3IgaGVyYiBnYXJkZW4a_gJTQlND…
Paste that into resume_cursor on the next run, keeping the query and filters the same, and collection continues from that point instead of paying to re-collect rows you already have.
Two caveats, both YouTube's. The feed occasionally re-serves an item across a cursor boundary, so a resumed run can repeat one or two rows from the previous one — deduplicate on videoId if that matters. And cursors are tied to the query that produced them: reusing one against a different search_term or a different set of filters gives meaningless results rather than an error.
Trending, Hype, and the hashtag video feed are single pages with no cursor, so nothing is printed for them and there is nothing to resume.
Frequently asked questions
Why did Trending return 49 rows when maxItems was 500?
The chart is 49 entries long. Trending, Hype, and the hashtag video feed are single pages that YouTube serves complete, with no cursor to follow. maxItems caps those runs but cannot extend them.
Why do fields for other workflows still appear in the input form? One Actor covers six surfaces, and Apify input forms are static. Every field's description names the workflow it applies to; the rest are ignored at run time, so leaving them filled in causes no error.
What is the difference between the two hashtag options?
They are two separate YouTube feeds, not a filter. content_kind: all reads the hashtag's video feed, which comes back as a single page of about 25 rows. content_kind: shorts reads its Shorts feed, which paginates and returns considerably more. The two never mix.
Does region_code change which results are returned?
Yes, and substantially so for Trending, Hype, and Home, which are region-specific by definition. Keyword search is also localized. language_code is separate: it controls the language of the returned text, not which results are selected.
Is a YouTube API key or account needed? No. Only publicly visible listings are read, and no credentials, cookies, or logged-in session are supplied. There is no YouTube Data API quota involved, so the 10,000-unit daily cap that applies to the official API does not apply here.
Why is description empty on some rows?
YouTube omits the description snippet on compact listings — Hype rows and hashtag Shorts rows carry little more than an ID, a title, and a view count. The video's full description is available from the YouTube Video Scraper.
Can more than about 20 autocomplete phrases be returned?
No. Search suggestions is one request returning YouTube's own suggestion list, which is short by design. maxItems can reduce it but not extend it.
Related Actors
| Actor | Purpose |
|---|---|
| YouTube Video Scraper | Full metadata and transcripts for known videos and Shorts |
| YouTube Channel Scraper | Channel details, videos, Shorts, playlists, and community posts |
| YouTube Comments Scraper | Comments from videos, Shorts, and community posts |
| YouTube Playlist Scraper | Playlist metadata and every video in it |