YouTube Search Scraper avatar

YouTube Search Scraper

Pricing

from $0.45 / 1,000 results

Go to Apify Store
YouTube Search Scraper

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

The Netaji

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

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.

ValueCollectsNeeds
searchKeyword search resultssearch_term
hashtagVideos or Shorts carrying a hashtaghashtag
trendingA regional Trending chartregion_code
hypeThe localized Hype chartNothing
homeThe localized Home feedNothing
suggestionsSearch autocomplete phrasessearch_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

FieldTypeDefaultDescription
scraperTypeenumsearchRequired. Workflow to run.
search_termstringKeyword search and Search suggestions. Suggestions also accepts partial text.
hashtagstringHashtag workflow. Text without the #.
maxItemsinteger50Maximum rows saved. 0 continues to the last available page.
resume_cursorstringContinue a previous run. Paste the resume token from that run's log.
region_codestringUSTwo-letter country code used to localize results.
language_codestringenLanguage code for result text, such as en, es, pt-BR.

Keyword search only:

FieldTypeDescription
result_kindenumvideo, shorts, channel, playlist, movie.
length_filterenumunder_3_minutes, between_3_and_20_minutes, over_20_minutes.
published_withinenumtoday, week, month, year.
sort_orderenumrelevance or popularity.

Hashtag and Trending:

FieldTypeDefaultDescription
content_kindenumallHashtag workflow. all reads the hashtag's video feed, shorts reads its Shorts feed.
trend_categoryenumnowTrending 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.

WorkflowPaginatesTypical ceiling per run
Keyword searchYesContinues while YouTube serves pages
Home feedYesContinues while YouTube serves pages
Hashtag, content_kind: shortsYesContinues while YouTube serves pages
Hashtag, content_kind: allNoOne page, around 25 rows
TrendingNoOne chart: about 49 rows for now and games, about 30 for music
HypeNoOne chart, about 100 rows
Search suggestionsNoOne 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.

FieldContents
recordTypeWhich workflow produced the row, such as search_result or trending_result
sourceThe query, hashtag, or workflow that produced the row
typeYouTube's own label: video, shorts, channel, playlist
videoIdVideo or Shorts ID
channelId, channelTitle, channelHandlePublishing channel
titlePublic title
urlCanonical URL, derived from the identifier
descriptionDescription snippet as shown in the listing
thumbnailThumbnail images, largest last
viewCount, viewCountTextNumeric and human-readable view counts
lengthTextDuration, such as 2:22
publishedTimeText, publishedAtRelative and ISO 8601 publication time
isVerifiedChannelWhether YouTube shows a verified badge
suggestionThe suggested phrase, in the Search suggestions workflow
positionOne-based position within the run
metaContext 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.

ActorPurpose
YouTube Video ScraperFull metadata and transcripts for known videos and Shorts
YouTube Channel ScraperChannel details, videos, Shorts, playlists, and community posts
YouTube Comments ScraperComments from videos, Shorts, and community posts
YouTube Playlist ScraperPlaylist metadata and every video in it