# YouTube Channel Search Scraper - Subscribers, Country & Stats (`neverempty/youtube-channel-search`) Actor

For influencer outreach, sponsorship lists and niche research: search YouTube by keyword and get one row per channel with handle, subscribers as a number, video count, total views, joined date, country and links. Filter by subscriber range and country. Export to CSV, Excel or JSON.

- **URL**: https://apify.com/neverempty/youtube-channel-search.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Videos, Social media, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 channel returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## YouTube Channel Search Scraper - subscribers, country and channel stats

Find YouTube channels in any niche by keyword and get one row per channel with its handle, URL,
**subscriber count as a real number**, **video count**, **total views**, **joined date**, **country** and the
links the channel lists on its About panel. Filter by **subscriber range** (for example the 10K-100K
creators) and by **country**, then export the list to CSV, Excel or JSON for influencer outreach,
sponsorship lists or niche research.

### What you can use it for

- **Influencer and creator marketing**: shortlist creators in a niche by audience size and country, sorted
  by subscribers or total views.
- **Sponsorship and partnership outreach**: each row carries the channel's own website and social links,
  ready for an outreach sheet. For the business emails creators publish in their About text or on the
  website they link, pass the handles to our
  [YouTube Channel Email Scraper](https://apify.com/neverempty/youtube-channel-emails).
- **Niche and competitor research**: who publishes on a topic, from which country, since when, and how big
  their audience is.
- **Ongoing creator discovery**: schedule it with **only new channels** turned on, and each run returns just
  the channels that appeared since the last one.

One broad keyword such as "woodworking" returned about 340 distinct channels in our tests. Several related
keywords in one run give you more, and a channel found by more than one keyword is returned once.

***

### What every row carries

| Field | Example | Where it comes from |
|---|---|---|
| `title`, `handle`, `channelId` | `Bourbon Moth Woodworking`, `@Bourbonmoth`, `UCQ_bmgSrYsQS0LboA_tZpEw` | search |
| `channelUrl`, `handleUrl` | `https://www.youtube.com/channel/UC...`, `https://www.youtube.com/@Bourbonmoth` | search |
| `subscriberCount` / `subscriberCountText` | `1260000` / `1.26M subscribers` | search |
| `isVerified`, `isVerifiedArtist` | `true`, `false` | search |
| `thumbnailUrl` | largest size YouTube offers, full `https://` URL | search |
| `descriptionSnippet` | the short text under the name in search | search |
| `videoCount` | `294` | About panel |
| `totalViews` | `150487226` | About panel |
| `country` | `United States` | About panel |
| `joinedDate` | `2015-05-08` | About panel |
| `description` | the full channel description | About panel |
| `links` | `[{ "title": "Patreon", "url": "https://www.patreon.com/..." }]` | About panel |
| `query`, `rank`, `page` | the keyword that found it and its position in YouTube's own order | this run |

Numbers are numbers. You can sort by `subscriberCount` or `totalViews` straight away in a spreadsheet,
without turning "1.26M" into 1,260,000 yourself.

Links on the About panel go through YouTube's redirect page; this Actor gives you the real destination
(`https://www.patreon.com/...`), not `youtube.com/redirect?...`.

***

### Filters

- **Subscriber range** - `minSubscribers` / `maxSubscribers`. Applied before the About panel is read,
  so channels outside your range cost no extra request and are never charged.
- **Country** - `countries`, e.g. `["United States", "UK", "Japan"]`. English names and common codes
  (US, UK, GB, JP, IN, DE, FR, BR...) are accepted.
- **Must contain / Must not contain** - words that must (or must not) appear in the channel name,
  handle or description snippet.
- **Channels per keyword** and **Maximum records** - stop exactly where you want. The maximum is shared
  between keywords, so three keywords and a maximum of 300 gives each keyword its share.

***

### Repeat runs: only new channels

Turn on **Only return channels that are new since the last run** and schedule the Actor. Each run
returns only the channels that are new to you for the same keywords. Only channels that were
actually delivered and charged are remembered, so channels cut by your spending limit arrive on the
next run.

***

### Example output (one row, shortened)

```json
{
  "query": "woodworking",
  "rank": 1,
  "channelId": "UCQ_bmgSrYsQS0LboA_tZpEw",
  "title": "Bourbon Moth Woodworking",
  "handle": "@Bourbonmoth",
  "channelUrl": "https://www.youtube.com/channel/UCQ_bmgSrYsQS0LboA_tZpEw",
  "handleUrl": "https://www.youtube.com/@Bourbonmoth",
  "subscriberCountText": "1.26M subscribers",
  "subscriberCount": 1260000,
  "subscriberCountIsRounded": true,
  "videoCount": 294,
  "totalViews": 150487226,
  "country": "United States",
  "joinedDate": "2015-05-08",
  "isVerified": true,
  "links": [
    { "title": "Bourbon Moth Homepage", "url": "http://www.bourbonmoth.com/" },
    { "title": "Patreon", "url": "https://www.patreon.com/bourbonmothwoodworking" }
  ],
  "detailsStatus": "ok"
}
```

***

### Input

```json
{
  "queries": ["woodworking", "home espresso"],
  "maxChannelsPerKeyword": 100,
  "minSubscribers": 10000,
  "maxSubscribers": 500000,
  "countries": ["United States", "UK"]
}
```

| Field | What it does |
|---|---|
| `queries` | Keywords. Each is searched with YouTube's "Channels" filter. |
| `maxChannelsPerKeyword` | Channels to return per keyword, after filters (default 50). |
| `maxRecords` | Total channel rows for the whole run (default 200). |
| `includeChannelDetails` | Read the About panel for video count, country, joined date, total views, description and links (default on). |
| `minSubscribers`, `maxSubscribers` | Subscriber range. 0 means no limit. |
| `countries` | Keep only channels showing one of these countries. |
| `keywords`, `keywordMatch`, `excludeKeywords` | Word filters on name, handle and snippet. |
| `monitoringMode`, `resetMonitoringState` | Return only channels new since the last run. |
| `maxRequests` | Hard ceiling on requests to YouTube (default 500). |
| `useProxy` | Use an Apify proxy if YouTube answers with a bot check (default off). |

***

### Frequently asked

**How do I find YouTube channels in a niche with their subscriber counts?**
Put the niche keyword in `queries` and run. Every row has `subscriberCount` as a plain number, so you
can sort or filter the list in a spreadsheet right away.

**How do I find small or mid-size YouTubers for sponsorships?**
Set `minSubscribers` and `maxSubscribers`, for example 10,000 and 100,000. Channels outside the range
are dropped before anything else is read, and you are not charged for them.

**Can I get only channels from one country?**
Yes. Put the country in `countries`. The country comes from the channel's own About panel.

**Can I get the channel's total views and number of videos?**
Yes, with `includeChannelDetails` on (the default). Both come from the About panel as numbers.

**Can I export the channel list to CSV or Excel?**
Yes. Open the run's dataset and download it as CSV, Excel or JSON, or read it through the Apify API.

**Do I get the creators' email addresses?**
This Actor returns the channel data and the links on the About panel. For the business emails creators
publish in their About text or on the website they link, pass the handles to our
[YouTube Channel Email Scraper](https://apify.com/neverempty/youtube-channel-emails).

**Do I need a YouTube API key or a login?**
No. You type keywords; nothing else is needed.

**Can I run it every week and get only new channels?**
Yes. Turn on `monitoringMode` and add a schedule in Apify.

**Do I need a proxy?**
No. A plain connection returned results both from a home connection and from Apify's cloud in our
tests. If YouTube ever answers with a bot check, turn `useProxy` on; the bot check is reported as its
own free row, never as "no channels".

***

### Pricing

Pay per event: you are charged for each **channel returned**. Rows that explain something - a keyword
YouTube rewrote, a keyword with no channels, a bot check, About details that could not be read, filters
that matched nothing, the request limit, or a result cut by your spending limit - are never charged.

***

### Limitations

- **Subscriber counts are rounded by YouTube itself** ("1.26M subscribers"). `subscriberCount` is that
  rounded number, and `subscriberCountIsRounded` says so. Exact counts are not public.
- **Not every channel shows a country.** In our production test 44 of 60 channels (73%) did. Channels without one have
  `country: null`, and when you filter by country they are left out, because their country cannot be
  confirmed.
- **Video count, country, joined date, total views, description and links need the About panel**, one
  extra request per channel. With `includeChannelDetails` off the run is faster and these fields are
  `null` with `detailsStatus: "not-requested"`.
- **YouTube's channel search has a depth limit.** A broad keyword such as "woodworking" ran out after
  about 340 distinct channels. For more, use several related keywords; channels found by more than one
  keyword are returned only once.
- **Email addresses and phone numbers in channel descriptions are replaced with `[email removed]` /
  `[phone removed]`.** Business emails that YouTube hides behind its "View email address" button are not
  collected. For the contacts creators publish in their About text or on the website they link, use our
  [YouTube Channel Email Scraper](https://apify.com/neverempty/youtube-channel-emails).
- If the About panel could not be read for some channels, those rows keep the search fields, carry
  `detailsStatus` and `detailsNote` explaining why, and nothing is guessed. One free summary row tells
  you how many.

### Thanks for using this Actor

We build these tools for people who run them every day, and we improve them from what users tell us.

- **Missing a field, or need another filter?** Tell us in the **Issues** tab. If the data is there, we add it.
- **Found a bug or a wrong value?** Post the run ID in the **Issues** tab. Wrong data is the thing we fix first.

If this Actor saved you time, a short review helps other people find it.

# Actor input Schema

## `queries` (type: `array`):

What to search for on YouTube. Each keyword is searched separately with YouTube's own "Channels" filter, and every row says which keyword found it.

## `maxChannelsPerKeyword` (type: `integer`):

How many channels to return for each keyword, after your filters. YouTube shows 20 channels per page and this Actor follows the pages for you. A broad keyword such as "woodworking" ran out after about 340 channels in our tests.

## `maxRecords` (type: `integer`):

The most channel rows this run may return and charge for, across all keywords. The limit is shared evenly between keywords, and a keyword that finds fewer channels leaves its share to the next ones.

## `includeChannelDetails` (type: `boolean`):

Reads each channel's About panel, which is where YouTube shows these fields. Turn it off for a faster run that returns only what the search itself shows (id, name, handle, subscribers, verified badge, thumbnail, description snippet).

## `minSubscribers` (type: `integer`):

0 means no minimum. YouTube rounds subscriber counts ("1.26M subscribers"), and this compares that rounded number. Channels that hide their subscriber count are left out when you set a range.

## `maxSubscribers` (type: `integer`):

0 means no maximum. Use it with the minimum to find small and mid-size channels, for example 10,000 to 100,000.

## `countries` (type: `array`):

Keep only channels whose About panel shows one of these countries, for example "United States", "Japan" or "UK". English country names and common codes (US, UK, JP, IN, DE...) are accepted. Channels that do not show a country are left out when this is set.

## `keywords` (type: `array`):

Keep only channels whose name, handle or description snippet contains these words.

## `keywordMatch` (type: `string`):

any = at least one of the words must appear. all = every word must appear.

## `excludeKeywords` (type: `array`):

Drop channels whose name, handle or description snippet contains any of these words.

## `monitoringMode` (type: `boolean`):

Remembers which channels this Actor has already returned for these keywords and skips them next time, so a scheduled run only brings channels you have not seen. Only channels that were actually returned and charged are remembered.

## `resetMonitoringState` (type: `boolean`):

Clears the memory of what was already returned, once, so this run returns everything again.

## `maxRequests` (type: `integer`):

A hard ceiling on how many requests this run may send to YouTube, counting search pages and About panels together. Each returned channel with details costs about one request.

## `useProxy` (type: `boolean`):

Off by default: a plain connection worked in our tests and is faster. Turn this on if you see bot-check rows in the output.

## Actor input object example

```json
{
  "queries": [
    "woodworking"
  ],
  "maxChannelsPerKeyword": 20,
  "maxRecords": 200,
  "includeChannelDetails": true,
  "minSubscribers": 0,
  "maxSubscribers": 0,
  "keywordMatch": "any",
  "monitoringMode": false,
  "resetMonitoringState": false,
  "maxRequests": 500,
  "useProxy": false
}
```

# Actor output Schema

## `results` (type: `string`):

One row per YouTube channel: the keyword that found it and its rank, the channel id, name, handle, channel URL and handle URL, the subscriber count both as YouTube writes it and as a number, the video count, total views, country, joined date, verified badge, thumbnail, description and external links. A keyword YouTube silently rewrote, a search with no channels, a bot check, an unreadable answer, About details that could not be read, filters that matched nothing and the request or charge limit each come back as their own row and are not charged.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "woodworking"
    ],
    "maxChannelsPerKeyword": 20,
    "maxRecords": 200,
    "maxRequests": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/youtube-channel-search").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "queries": ["woodworking"],
    "maxChannelsPerKeyword": 20,
    "maxRecords": 200,
    "maxRequests": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/youtube-channel-search").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "woodworking"
  ],
  "maxChannelsPerKeyword": 20,
  "maxRecords": 200,
  "maxRequests": 500
}' |
apify call neverempty/youtube-channel-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/youtube-channel-search"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6pj9TKwpsoWbwtjZs/builds/vM60n8Qjc75VXZoVN/openapi.json
