YouTube Channel Search Scraper: Subscribers, Views, Country
Pricing
from $0.50 / 1,000 channels
YouTube Channel Search Scraper: Subscribers, Views, Country
YouTube channel finder: find YouTube channels, creators and influencers by keyword, search URL or similar channel. Each channel's record: handle, subscriber count, exact video and view counts, country, joined date, links, business e-mail flag. Filter by subscribers, country, activity. No login.
Pricing
from $0.50 / 1,000 channels
Rating
0.0
(0)
Developer
Hyperbach
Maintained by CommunityActor stats
0
Bookmarked
424
Total users
4
Monthly active users
a day ago
Last modified
Categories
Share
Find YouTube channels by keyword and get each channel's public record, every count in the right place: handle, title, subscribers (YouTube's rounded count, as a number and as text), the exact number of videos and views, country, joined date, every external link with its real URL, whether the channel shows a business e-mail button, and any e-mail address written in the description. Search by keywords, hashtags or YouTube search URLs, look up a list of channels, or start from a channel and find the ones like it. Filter by subscribers, videos, country, verified badge, joined date and recent uploads before a row is delivered or charged. Each row says how it was found — the query, rank, page, region and time — and each search says whether it reached YouTube's own end. No login, no cookies, no API key, proxies handled for you. Ready-made: a weekly watch for new channels on a keyword.
Why this channel search scraper
- Every count in the right place. YouTube's search card puts the channel's
@handlewhere the subscriber count belongs and the subscriber count where the video count belongs. In our test of other channel search actors on the same keyword, 3 of 14 card scrapers passed that mislabel on, and two truncated "32.3K" to 32,299. Here the handle is the handle,subscribersis 32,300 withsubscribers_text"32.3K subscribers" andsubscribers_exact: false(YouTube rounds it for everyone), andvideo_countandview_countare YouTube's exact figures. - The About record on every row. Exact views and videos, joined date, country (with its ISO code), the full description and every external link with its real address, read from each channel's own About panel: on our test channel (My Sourdough Bread) that is 1,450 videos, 59,935,089 views, Canada, two links — where the leading actor returned no links. A channel with no country or no links says so with an empty field, never a guess.
- A walk with a stated end. YouTube's channel results for a keyword end by themselves (100 to 500 channels for most keywords) and repeat 17–19 % of their channels from page to page. Each search walks to the count you ask or to that end, delivers each channel once, and reports in the run summary how many it read, delivered and skipped, YouTube's own count when its last page gives one, and whether it reached the end —
minecraftread to the end gave 108 unique channels,watch repair345. - Drift made visible. YouTube's results for a keyword change within minutes. Every row carries the query, the rank and page it was found at, the region and the time it was read (
read_at), so a changed list reads as a changed list, not a defect. - More ways in. Search URLs keep YouTube's own sort and filters; the video results give the channels behind them, each with the video that surfaced it;
bothinterleaves the two; autocomplete adds the variants people type; a seed channel gives the channels it features and a search on its own keywords. Ready-made: similar channels to a channel you know, the channels behind the most-viewed videos. - Filters before the charge, misses for free. Subscribers, videos, country, verified badge, the business e-mail button, joined date and recent uploads are checked before a row is delivered — a channel left out is never charged. A handle that does not exist, a search with no channel, a value that is not a channel: a free row that says why. Ready-made: mid-size US fitness creators active this month, channels with a business e-mail button.
- Fast and plain. No browser: 40 channels with the full record in 7 seconds, one exit; 56 regions measured.
Who it's for
- Influencer marketers and agencies — creator lists for a niche with audience size, exact views and videos, country, links and recent uploads, filtered to the size and market you want.
- Partnerships and sales teams — channels with their websites and social links and a flag for the business e-mail button, deduplicated, with only new channels on each scheduled run.
- Researchers and analysts — who publishes on a topic, in which country, since when and how actively, with the query, rank and read time on every row.
- Developers and agents — one row shape, typed fields, a free labelled row for every miss, and a run summary that states each search's end.
Quick start
Channels for a keyword
{"searchQueries": ["sourdough bread"],"maxChannelsPerQuery": 20}
Mid-size US creators who uploaded in the last 90 days
{"searchQueries": ["sourdough bread","home baking"],"minSubscribers": 10000,"maxSubscribers": 200000,"countries": ["US"],"activeWithinDays": 90,"recentVideos": 3}
Look up channels you already have
{"channels": ["@GrantBakes","@OhmyBread.online","UCozBpyoi-j7plavuZKLIgQg"]}
Channels like a channel you know
{"similarToChannels": ["@ellyswholegrainsourdough"],"maxChannelsPerQuery": 30}
Channel and video results, with autocomplete variants
{"searchQueries": ["mechanical keyboard"],"discoveryMode": "both","expandQueries": 3,"maxChannelsPerQuery": 30}
Output
One row per channel: the identity, the About record, the profile, the recent uploads when asked, and how the run found it — or, for a value that gave no channel, the same row with status and reason saying why (free):
| field | meaning |
|---|---|
status | ok = a channel row (charged). Otherwise free, with reason saying why: not_found (a handle, id or video that gives no channel), no_results (a search or seed that delivered nothing), invalid (a value that is not a channel or a search). |
reason | Why the row carries no channel, in words (null on ok rows). |
channel_id | The channel's id (UC + 22 characters). Deduplicate on this. |
channel_url | The channel's URL: https://www.youtube.com/@handle, or /channel/<id> for a channel without a handle. |
handle | The channel's @handle as YouTube writes it (dots and any script kept); null for a channel without one. |
title | The channel's name. |
description | The channel's full About description (not the search card's snippet). |
verified | Whether the channel has YouTube's verified badge (true / false). |
subscribers | Subscribers as a number, from YouTube's rounded count ("32.3K" = 32,300). Null when YouTube shows no count (a new channel, or one that hides it). |
subscribers_text | YouTube's own subscriber text, e.g. "32.3K subscribers". |
subscribers_exact | Always false when there is a count: YouTube rounds subscriber counts for everyone. |
video_count | The exact number of public videos, from the channel's About panel (0 for a channel with no upload). |
view_count | The exact total of views, from the channel's About panel. |
avg_views_per_video | view_count ÷ video_count, rounded. |
views_per_subscriber | view_count ÷ subscribers, two decimals. |
country | The country the owner set, as YouTube names it in English; null when none is set (about a third of channels). |
country_code | The same country as an ISO 3166 two-letter code (US, GB, DE). |
joined_date | The day the channel was created, YYYY-MM-DD. |
joined_text | YouTube's own joined line, as shown (Joined Dec 28, 2023). |
links | The external links on the About panel, each {title, url} with the real URL (YouTube's redirect removed). |
link_domains | The domains of those links, deduplicated (instagram.com, linktr.ee, the channel's own site). |
has_business_email | Whether the About panel shows YouTube's 'View email address' button. The address itself sits behind a sign-in and a captcha and is not read. |
emails_in_description | The e-mail addresses the channel wrote in its own About description, deduplicated, lower-cased; null when it wrote none. Only what the description says: nothing is looked up, and the address behind the business e-mail button is not read. |
avatar_url | The channel's avatar, the largest size YouTube lists (the URL takes =s<N> for another size). |
banner_url | The channel's banner, the largest size; null when the channel has none. |
keywords | The channel's own keywords (tags), as a list, quoted phrases kept. |
tabs | The tabs the channel shows: Home, Videos, Shorts, Live, Podcasts, Playlists, Posts, Store … |
family_safe | YouTube's family-safe flag for the channel. |
unlisted | YouTube's unlisted flag for the channel page. |
noindex | Whether the channel page asks search engines not to index it. |
auto_generated | Whether YouTube made the channel itself (a '- Topic' channel or a placeholder: the About says 'Auto-generated by YouTube'). |
rss_url | The channel's RSS feed of new videos. |
available_country_count | In how many of YouTube's 249 countries the channel is available. |
unavailable_country_codes | The countries where the channel is not available (ISO codes); empty for most channels. |
last_upload_ago | How long ago the latest long-form video went up, as YouTube says it ("3 days ago"). Null when the channel has none (Shorts only, or no video) or recent uploads were not asked. |
last_upload_days | The same in days: the lower bound ("2 weeks ago" = 14), or the exact count when activeWithinDays needed the upload's own date to decide. |
uploads_last_30_days | How many of the channel's latest 30 long-form videos went up in the last 30 days. |
recent_avg_views | The average views of those latest long-form videos. |
recent_videos | The latest long-form videos (recentVideos of them), each {video_id, title, views, published, url}. |
query | What found the channel: the keyword or URL you gave, the autocomplete variant, the seed's keyword, or the channel value you listed. |
expanded_from | The keyword an autocomplete variant came from (expandQueries); null otherwise. |
discovered_via | channel_search (YouTube's channel results), video_search (the channel behind a video result), channel_input (you listed it), seed_featured (a seed features it), seed_keywords (a search on a seed's keywords). |
rank | The position at which the search showed the channel (every result counted, repeats included); for a listed channel, its position in your list. |
page | The results page the channel was on (20 results a page). |
source_url | The YouTube results URL of the search that found the channel (or the URL you listed). |
source_video_id | For a channel found through the video results: the video that surfaced it. |
source_video_title | That video's title. |
seed_channel_id | For a lookalike row: the seed channel's id. |
region | The region the search was read from (two-letter code). |
language | YouTube's interface language for the search. |
exit_kind | How the run reached YouTube: residential (a residential proxy exit in the region) or direct. |
read_at | When the row was read, UTC (ISO 8601). |
notes | Anything the row could not hold, in words (e.g. no subscriber count shown, no dated long-form upload). |
Example record:
{"status": "ok","reason": null,"channel_id": "UCPqKi2hJgQjAJ-XAJzMT3VA","channel_url": "https://www.youtube.com/@keepitsweetkitchen","handle": "@keepitsweetkitchen","title": "Keep it Sweet Kitchen","description": "🥖 Tips & Tricks for Sourdough\n❤️ Sourdough Mentor\n👩🏼🍳 Bakery Owner\n","verified": true,"subscribers": 121000,"subscribers_text": "121K subscribers","subscribers_exact": false,"video_count": 491,"view_count": 24387775,"avg_views_per_video": 49670,"views_per_subscriber": 201.55,"country": "United States","country_code": "US","joined_date": "2018-06-26","joined_text": "Joined Jun 26, 2018","links": [{"title": "Website","url": "https://keepitsweetkitchen.com/"},{"title": "Facebook","url": "https://www.facebook.com/keepitsweetkitchen"},{"title": "Instagram","url": "https://www.instagram.com/keepitsweetkitchen/"}],"link_domains": ["facebook.com","instagram.com","keepitsweetkitchen.com"],"has_business_email": true,"emails_in_description": null,"avatar_url": "https://yt3.googleusercontent.com/whSoLfg9_VksnZozNq0fDaO5iFW-2AzrTNEpo5lHUNmaWI4p1YQgY5Ji30Uc3U0OlcVUiSem=s900-c-k-c0x00ffffff-no-rj","banner_url": "https://yt3.googleusercontent.com/vzBy2NEkpQnt9P-J4660J_Ug-cbO1S9EE9nKsmXB2eNG-tOY4VeIIFcDAkOQQ9XLYRLclCOY=w2560-fcrop64=1,00005a57ffffa5a8-k-c0xffffffff-no-nd-rj","keywords": ["sourdough","how to make sourdough","sourdough starter","troubleshooting sourdough","how to make perfect sourdough","sourdough for beginners","keep it sweet kitchen"],"tabs": ["Home","Videos","Shorts","Playlists","Search"],"family_safe": true,"unlisted": false,"noindex": false,"auto_generated": false,"rss_url": "https://www.youtube.com/feeds/videos.xml?channel_id=UCPqKi2hJgQjAJ-XAJzMT3VA","available_country_count": 249,"unavailable_country_codes": [],"last_upload_ago": "3 days ago","last_upload_days": 3,"uploads_last_30_days": 4,"recent_avg_views": 28620,"recent_videos": [{"video_id": "xeTAq3Eg4ZA","title": "Easy Sourdough Bread Bowls | Step-by-Step Recipe","views": 9000,"published": "3 days ago","url": "https://www.youtube.com/watch?v=xeTAq3Eg4ZA"},{"video_id": "rGEGGwA0XZU","title": "Can I Make Sourdough Bread in Less Than 8 Hours?","views": 20000,"published": "10 days ago","url": "https://www.youtube.com/watch?v=rGEGGwA0XZU"},{"video_id": "Vhzad84ZkKo","title": "Stop Guessing When Your Sourdough Starter Is Ready","views": 21000,"published": "2 weeks ago","url": "https://www.youtube.com/watch?v=Vhzad84ZkKo"}],"query": "sourdough bread","expanded_from": null,"discovered_via": "channel_search","rank": 24,"page": 2,"source_url": "https://www.youtube.com/results?search_query=sourdough+bread&sp=EgIQAg%3D%3D&hl=en&gl=US","source_video_id": null,"source_video_title": null,"seed_channel_id": null,"region": "US","language": "en","exit_kind": "residential","read_at": "2026-10-07T03:26:50Z","notes": null}
Pricing
Pay only for the channels a run delivers, with no start fee and no platform usage billed to you. Prices fall with your Apify plan.
| per 1,000 | Free | Starter | Scale | Business |
|---|---|---|---|---|
Channel (channel) | $1.00 | $0.80 | $0.70 | $0.50 |
A channel is $1.00 per 1,000 on the Free plan and $0.50 on Business, with the full About record, the profile and the recent uploads when you ask for them: nothing on the row costs extra. Free: a channel a filter left out, a repeat, a channel an earlier run delivered (onlyNew), every labelled row (a handle that does not exist, a search with no channel, a value that is not a channel) and a run that failed before its first row. maxItems is exact, and a charge limit stops the run at the channels it pays for; before the first request the log says the most the run can cost at your plan's prices. Enterprise plans have their own rates — the Actor's Pricing tab shows the price for your plan.
Usage patterns
- A creator list for a niche — Several keywords,
maxChannelsPerQueryhigh enough to reach YouTube's end, the subscriber and country filters you need: one row per channel, each with the keyword that found it. The run summary says, per keyword, how many channels YouTube had and whether the walk reached them all. Ready-made: a channel list for a keyword and its autocomplete variants. - New channels every week — Save a task with your keywords,
onlyNewandmaxChannelsPerQueryhigh enough to reach YouTube's end (1,000 covers most keywords), and schedule it: the first run delivers the whole list, and each later run only the channels this task has not delivered before — new in the list, or newly past your filters. YouTube's list for a keyword moves between reads, so the first runs also add channels earlier reads missed (three full reads ofwatch repairminutes apart delivered 76, 26 and 11 channels, none twice); a run with nothing new delivers and charges nothing. Channels delivered before do not count againstmaxChannelsPerQuery, so with a lower cap each run delivers the next channels of the list instead. Ready-made: monitor new YouTube channels for a keyword. Apify's integrations send the rows to a sheet, a webhook or Slack. - Enrich a list you already have — Put handles, channel URLs, ids or video URLs in
channels(or a link to a text file or Google Sheet of them): each gets the full record, the filters still apply, and a channel that does not exist comes back as a free row that says so. Ready-made: channel stats for a list, with the latest uploads. - A local market —
regionreads the search from that country (56 measured) andlanguagesets YouTube's interface language, which can change the results for local keywords (Sauerteigbrotfrom Germany: German and English shared 9 of 20 channels in one test and 19 of 20 in another two hours later);countrieskeeps the channels whose owners set that country.
Input configuration
| field | type | default | what it does |
|---|---|---|---|
searchQueries | array | [] | Keywords to search YouTube's channels for, one per line: sourdough bread, "mechanical keyboard" -review, #asmr. A YouTube search URL (youtube.com/results?search_query=…) keeps its own sort and filters; a /hashtag/ link is searched as the tag. A link to a text file, a CSV or a published Google Sheet with one keyword per line is read as a list. Each keyword gives one row per channel it finds, up to the max per search. |
channels | array | [] | Channels you already know, for their full record: @handle (dots and any script work), a channel URL (/@name, /channel/UC…, /c/name, /user/name), a UC… id, or a video URL (the channel behind it). A list-file link works here too. A channel that does not exist is a free row that says so. |
similarToChannels | array | [] | Seed channels (same forms as above). For each seed: the channels it features on its home page (when it has that shelf) and the channels a search on the seed's own first 3 keywords finds, up to the max per search. Every row names its seed (seed_channel_id). A seed with neither gets a free row that says so. |
discoveryMode | channels / videos / both | "channels" | channels reads YouTube's own channel filter (it ends by itself, and the run reports its count). videos reads the video results and keeps each channel once with the video that surfaced it (source_video_id): another, deeper set. both interleaves the two. |
sortBy | relevance / views | "relevance" | YouTube's own order of the results. Rating and upload date are not offered: YouTube ignores them for channels. |
maxChannelsPerQuery | integer | 50 | How many channels each keyword, URL or seed delivers. Channels left out by your filters, repeats and channels found by an earlier search do not count. A search YouTube ends sooner says so in the run summary. Channels you list under 'Channels to look up' are all read. |
expandQueries | integer | 0 | For each keyword, also search this many of YouTube's own autocomplete suggestions (sourdough bread → sourdough bread recipe, …). Rows from a variant name it in query and the keyword in expanded_from. 0 = off. |
region | US / GB / CA / AU / NZ / IE / IN / PK / BD / PH / ID / MY / SG / TH / VN / JP / KR / TW / HK / DE / AT / CH / FR / BE / NL / ES / PT / IT / PL / CZ / RO / HU / GR / SE / NO / DK / FI / TR / UA / IL / AE / SA / EG / MA / NG / KE / ZA / BR / MX / AR / CO / CL / PE / LK / KZ / NP | "US" | The country the search is read from (YouTube's region and an exit in that country). The set of channels moves a little by region; every row carries it (region). |
language | string | "en" | YouTube's interface language for the search (en, de, ja, pt-BR). It changes the results for some local keywords. Counts and dates are always delivered as numbers and ISO dates. |
minSubscribers | integer | 0 | Only channels with at least this many subscribers (YouTube's rounded count, e.g. 32.3K = 32,300). A channel that shows no count is left out when a subscriber limit is set. 0 = no limit. |
maxSubscribers | integer | 0 | Only channels with at most this many subscribers. 0 = no limit. |
minVideos | integer | 0 | Only channels with at least this many public videos (the exact count). 0 = no limit. |
maxVideos | integer | 0 | Only channels with at most this many public videos. 0 = no limit. |
countries | array | [] | Only channels whose owner set one of these countries (two-letter codes: US, GB, DE). Many channels set none; they are left out when this is set. Empty = any country. |
verifiedOnly | boolean | false | Only channels with YouTube's verified badge. |
onlyWithBusinessEmail | boolean | false | Only channels whose About panel shows YouTube's 'View email address' button (has_business_email). The address itself is behind a sign-in and a captcha and is not read. |
joinedAfter | string | "" | Only channels created on or after this date, YYYY-MM-DD. Empty = no limit. |
joinedBefore | string | "" | Only channels created on or before this date, YYYY-MM-DD. Empty = no limit. |
activeWithinDays | integer | 0 | Only channels whose latest long-form video is at most this many days old (read from the channel's Videos tab; one more call a channel). A channel with only Shorts or no video has no dated upload and is left out. 0 = off. |
excludeChannels | array | [] | Channels never to deliver (same forms as 'Channels to look up'), e.g. the ones you already have. The first 1,000 are used and the rest are ignored. To skip more across runs, use onlyNew. |
recentVideos | integer | 0 | Add this many of the channel's latest long-form videos to each row (recent_videos: id, title, views, age), with the last upload's age and the uploads in the last 30 days. One more call a channel. 0 = off. |
onlyNew | boolean | false | Skip channels this task delivered in an earlier run: run a search daily and get only the channels that are new to you. Turns the memory on. |
stateStoreName | string | "" | Name of the memory between runs. Empty = derived from your searches and channels, so the same task always meets its own memory. |
maxItems | integer | 0 | The most channels this run delivers (and charges), over all searches. 0 = no limit. Free rows (not found, no results) do not count. |
Errors
A run does not fail because of your input. When an input cannot be used — a date that is not a date, an id in the wrong form, two settings that contradict each other — the run ends Succeeded, charges nothing, and says what to change:
- the status message starts with
INPUT REJECTED; - the dataset holds one row,
{"error": true, "code": "…", "message": "…"}, and no results; - the key-value store record
ERRORholds the same object.
From code, check error on the first row before reading results.
A search that matches nothing is not an error: the run writes one free row with status: no_results and the reason, and charges nothing. A run that ends Failed is a fault on our side, never your input; it charges nothing, and we are alerted.
FAQ
Are the subscriber counts exact?
No — and no logged-out reader gets them: YouTube rounds subscriber counts for everyone ("32.3K"). subscribers is that rounded value as a number, subscribers_text YouTube's text and subscribers_exact says false. The video and view counts are YouTube's exact figures.
Do I get the creators' e-mail addresses?
Those a channel writes in its own About description, yes: emails_in_description lists them (deduplicated, lower-cased). The address behind YouTube's business e-mail button sits behind a sign-in and a captcha and is not read; has_business_email says whether the channel shows the button (and onlyWithBusinessEmail keeps only those). The external links on the About panel — websites, Instagram, link-in-bio pages — are delivered with their real URLs.
How many channels does one keyword give?
As many as YouTube lists: its channel results end by themselves, usually after 100 to 500 channels. The run summary gives, per search, the channels delivered, YouTube's own count when its last page gives one (a list that ends on an empty page gives none) and whether the walk reached the end. discoveryMode: videos or both adds the channels behind the video results, a deeper and different set.
Why does the same keyword give a different list an hour later?
YouTube's results change within minutes (8 of 20 channels in 11 minutes in our test). Each row carries its rank, page, region and read_at, so you can tell a changed list from a defect.
What is charged?
Delivered channel rows only. Channels left out by a filter, repeats, channels an earlier run delivered (onlyNew), and free rows — a handle that does not exist, a search with no channel, a value that is not a channel — are never charged. maxItems is exact, and a maximum charge you set on the run stops it at the number of channels that charge pays for: no row is delivered unpaid and none is charged past it.
What happens when a search finds no channel?
You get one free row with status: no_results and the reason (for example YouTube found no channel for this search), so the search is not silently missing. A handle or channel id that does not exist gives a free not_found row the same way.
What does it not do?
It does not look up e-mail addresses, phone numbers or other contacts (it delivers the e-mails a channel wrote in its own description and whether the channel shows YouTube's business e-mail button, nothing more), does not score channels for fit or sponsorship, does not read sponsor history, does not label topics or content language, does not read memberships, and does not keep a subscriber or view history over time. It reads what YouTube shows a logged-out visitor today.
What do region and language change?
region reads the search from an exit in that country with YouTube's region set to it; the set of channels moves a little (10 to 19 of 20 in common with the US set in our test of 53 countries; 56 are offered). language is YouTube's interface language for the search; it matters most for local keywords. Counts and dates are always numbers and ISO dates.
Does it need a login, cookies or a YouTube API key?
No. It reads YouTube as a logged-out visitor.
Integration
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('hyperbach/youtube-channel-search-scraper').call({"searchQueries": ["sourdough bread"], "maxChannelsPerQuery": 20});const { items } = await client.dataset(run.defaultDatasetId).listItems();
Python
from apify_client import ApifyClientclient = ApifyClient('YOUR_TOKEN')run = client.actor('hyperbach/youtube-channel-search-scraper').call(run_input={'searchQueries': ['sourdough bread'], 'maxChannelsPerQuery': 20})items = client.dataset(run['defaultDatasetId']).list_items().items
CLI
$apify call hyperbach/youtube-channel-search-scraper --input '{"searchQueries": ["sourdough bread"], "maxChannelsPerQuery": 20}'
REST
curl -X POST "https://api.apify.com/v2/acts/hyperbach~youtube-channel-search-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H 'Content-Type: application/json' -d '{"searchQueries": ["sourdough bread"], "maxChannelsPerQuery": 20}'
Support
This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.