# YouTube Scraper With Creator Contact & Lead Enrichment (`api-empire/youtube-scraper`) Actor

YouTube Scraper: Extract creator profiles, videos, subscribers, views, engagement metrics, and publicly available contact details. Enrich creator leads with emails, websites, social links, categories, and channel URLs for influencer research, prospecting, outreach, and market intelligence.

- **URL**: https://apify.com/api-empire/youtube-scraper.md
- **Developed by:** [API Empire](https://apify.com/api-empire) (community)
- **Categories:** Videos, Lead generation, Social media
- **Stats:** 14 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.00005 / actor start

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### YouTube Scraper — Extract Creator Leads, Emails and Videos as JSON

YouTube Scraper With Creator Contact & Lead Enrichment discovers YouTube creators by niche keyword or direct URL and returns one row per channel — subscriber/view totals, country, join date, and, when published, a business email, phone, and structured social links. A legacy mode also returns per-video search results with transcripts and filters. Every response is typed, normalized JSON — no HTML, no parsing. After reading this, you'll be able to configure discovery keywords, enrich creator leads with contact data, and route outreach-ready results into a CRM or agent pipeline.

### What is YouTube Scraper With Creator Contact & Lead Enrichment?

YouTube Scraper With Creator Contact & Lead Enrichment is an Apify Actor that turns YouTube into a creator lead list. Point it at niche keywords or a list of channel URLs/@handles and it opens each channel's public About page, then returns one row per creator with subscriber/view/video totals, country, join date, verification status, and — only when the creator has actually published one — a business email, phone number, and structured social links. No YouTube account or Google API key is required to run it. A legacy per-video search mode (`scrapeMode: "videos"`) is also built in, reproducing the original per-video search engine's output unchanged for existing integrations.

- Discover creator channels by niche keyword, or enrich a known list of channel URLs/@handles/IDs directly
- Extract real, published business email and phone number from each channel's About page — never guessed or fabricated
- Structure external links into website, Linktree, Instagram, TikTok, X/Twitter, Facebook, and Discord fields
- Filter to leads that actually carry contact info with `requireEmail` / `requirePhone`
- Run the legacy per-video search engine (search terms, quality/date filters, transcripts) from the same input schema

### What data does YouTube Scraper With Creator Contact & Lead Enrichment collect?

The Actor returns two structurally different row types depending on `scrapeMode`: channel-level creator leads (default) and legacy per-video search rows.

| Data Type | Key Fields | JSON Field Names |
| --- | --- | --- |
| Creator leads (channel-level) | channel name/URL/ID, subscriber/view/video totals, country, join date, verification | `channelName`, `channelUrl`, `numberOfSubscribers`, `totalViews`, `totalVideos`, `country`, `joinedDate`, `isVerified` |
| Contact & social enrichment | business email, phone, website, and per-platform social handles found on the About page | `email`, `phone`, `website`, `linktreeUrl`, `instagramHandle`, `tiktokHandle`, `twitterHandle`, `facebookUrl`, `discordUrl`, `hasContactInfo` |
| Per-video search results (legacy mode) | title, view count, likes, duration, hashtags, subtitles/transcript | `title`, `viewCount`, `likes`, `duration`, `hashtags`, `subtitles`, `transcript` |

#### Need more YouTube data?

If you only need channel discovery with lighter contact extraction — no subscriber/view breadth, no legacy per-video engine — **YouTube Channel Finder With Contact Info Extraction** is a narrower, purpose-built alternative for that single job. For comment-level data instead of channel or video data, **YouTube Comments Scraper: Comment Analytics & Keyword Search** pulls per-video comments plus channel- and playlist-wide engagement rollups. And if what you actually need from a video is the spoken content rather than the channel behind it, **YouTube Transcript Scraper With AI Insights** collects transcripts with optional AI summaries, key points, and topic tags.

### How does YouTube Scraper With Creator Contact & Lead Enrichment differ from the official YouTube API?

The YouTube Data API v3 gives you structured metadata through Google-approved endpoints under a quota; it does not expose a creator's business email, phone number, or social links through any public field. YouTube Scraper With Creator Contact & Lead Enrichment reads the same About page a human visitor sees and extracts whatever contact info the creator has actually chosen to publish there.

| Feature | YouTube Data API v3 | YouTube Scraper With Creator Contact & Lead Enrichment |
| --- | --- | --- |
| Contact/lead data (email, phone, social) | Not exposed by any resource or endpoint | Regex-extracted from the channel's own published About-page text and links, left `null` when unpublished |
| Setup | Google Cloud project + API key/OAuth, Data API enabled | Input JSON on Apify — no Google credentials |
| Daily allocation | Default 10,000 units/day per project (Google's getting-started docs) | No quota-unit system; size controlled by `maxLeadsPerKeyword` / `maxChannelsTotal` |
| Entity coverage | Channel and video metadata resources, queried separately | Channel leads (contact + social) and legacy per-video search/transcripts, one Actor |
| Output consistency | Raw API JSON; fields can change across API versions | Actor-normalized JSON, field set documented in this README |
| Approval process | Key is self-serve; quota increases need a Google review form | None; scales through Apify's own usage |

The official API suits teams that already have a Google Cloud project and only need standard public metadata within quota. This Actor suits creator contact/lead generation, or per-video search with filters and transcripts, without building that pipeline yourself.

### Why do developers and teams scrape YouTube?

#### For marketers and influencer/brand teams

Sponsorship and partnership teams use `discoveryKeywords` to pull a shortlist of creators in a niche (e.g. "fitness coach", "crypto trading") and immediately see `numberOfSubscribers`, `totalViews`, and `country` for size and geography fit, alongside `email` and `website` when the creator has published outreach contacts. Instead of manually opening dozens of About pages, a single run with `enrichContactInfo: true` and `requireEmail: true` produces a shortlist of creators who are actually reachable, ready to load into an outreach sequence or spreadsheet without further cleanup.

#### For sales and business development teams

Teams selling tools, services, or sponsorships to creators use `creatorChannels` to enrich a known list of prospects, or `discoveryKeywords` to build a fresh pipeline from a target niche. The `hasContactInfo` flag and `discoveryMethod`/`sourceKeyword` fields make it easy to filter a dataset down to contactable leads and trace each one back to the search that found it, which matters when reporting pipeline source and conversion by niche back to a CRM. Setting `requireEmail: true` before export means the list a rep works from never contains a dead-end row with no way to make contact.

#### For AI engineers and agent builders

An outreach or research agent can call this Actor as a tool, pass in a niche keyword, and receive typed JSON rows — `channelName`, `email`, `phone`, `instagramHandle` — with no HTML or selector logic in the agent loop. Because every field is either a real value or `null` (never fabricated), an agent can safely branch on `hasContactInfo` to decide whether to draft an outreach message or fall back to a different discovery step, without a parsing layer between the tool call and the LLM context.

#### For researchers and analysts

Creator-economy researchers use `discoveryKeywords` across several niches to build a public dataset of channel size (`numberOfSubscribers`, `totalViews`, `totalVideos`) alongside `joinedDate` and `country`, useful for studying niche growth or geographic concentration over time. Because the Actor only reads each channel's own public About page, the resulting dataset is limited to information the channel owner has chosen to make publicly visible — the same scope any visitor to that page could see. Running the same keyword set on a schedule turns this into a longitudinal panel of niche-level growth rather than a single snapshot.

### How to scrape YouTube (step by step)

1. Open **YouTube Scraper With Creator Contact & Lead Enrichment** on its Apify Store listing and click **Try for free** (or **Start**, if already added to your account).
2. Provide either `discoveryKeywords` (niche keywords to search) or `creatorChannels` (direct channel URLs/@handles/IDs) — leave `scrapeMode` at its default `"leads"` for channel-level creator leads.
3. Set `maxLeadsPerKeyword` and `maxChannelsTotal` to control run size, and toggle `requireEmail` / `requirePhone` if you only want contactable leads. For the legacy per-video engine instead, set `scrapeMode` to `"videos"` and fill in `searchTerms`/`startUrls`.
4. Click **Start** to run the Actor. `proxyConfiguration` can be left at its default; the Actor escalates its own connection automatically if YouTube blocks a request.
5. Download results as JSON, CSV, Excel, or the other export formats Apify's dataset view supports, or read them back over the API.

#### What to do when YouTube changes its structure

The Actor is maintained, and the field names and types documented in this README are the contract integrations are built against — a page-structure change on YouTube's end is expected to be absorbed by an Actor update rather than a change to your downstream code. No specific turnaround time is promised for any given fix.

### ⬇️ Input

No input field is required — every parameter has a default, and the Actor falls back to a demo keyword if you provide nothing at all.

| Parameter | Required | Type | Description | Example Value |
| --- | --- | --- | --- | --- |
| `discoveryKeywords` | No | array | Niche/topic keywords used to discover creator channels via YouTube search; also accepts the base actor's `searchTerms` key | `["fitness coach"]` |
| `creatorChannels` | No | array | Direct YouTube channel URLs, @handles, or channel IDs (UC...) to enrich directly, skipping discovery; also accepts the base actor's `startUrls` key | `["https://www.youtube.com/@MrBeast"]` |
| `maxLeadsPerKeyword` | No | integer | Unique channels to discover and enrich per discovery keyword. Default 5, min 1, max 200 | `5` |
| `maxChannelsTotal` | No | integer | Global cap on total channel leads across all keywords/channels combined. Default 0, min 0, max 5000 (0 = unlimited) | `0` |
| `enrichContactInfo` | No | boolean | Regex-scan the About page for a business email and/or phone number. Default `true` | `true` |
| `enrichSocialLinks` | No | boolean | Classify About-page external links into website/Linktree/Instagram/TikTok/X/Facebook/Discord fields. Default `true` | `true` |
| `requireEmail` | No | boolean | Skip channels where no email could be found, instead of emitting a null-email row. Default `false` | `false` |
| `requirePhone` | No | boolean | Skip channels where no phone number could be found. Default `false` | `false` |
| `scrapeMode` | No | string (enum: `leads`, `videos`) | `leads` = this Actor's channel-level creator-lead mode; `videos` = the original per-video search engine, base-compatible. Default `"leads"` | `"leads"` |
| `searchTerms` | No | array | YouTube search keywords, used only when `scrapeMode` = `"videos"`; ignored in leads mode | `["Crawlee"]` |
| `startUrls` | No | array | Direct YouTube URLs scraped only when `scrapeMode` = `"videos"`; ignored in leads mode | `["https://www.youtube.com/watch?v=dQw4w9WgXcQ"]` |
| `maxVideos` | No | integer | Regular (non-Shorts, non-live) videos to scrape per search term in per-video mode. Default 10, min 0, max 9999 (0 = skip) | `10` |
| `maxShorts` | No | integer | Shorts to collect per keyword in per-video mode. Default 0, min 0, max 9999 (0 = skip) | `0` |
| `maxStreams` | No | integer | Live/upcoming streams to scrape per search term in per-video mode. Default 0, min 0, max 9999 (0 = skip) | `0` |
| `downloadSubtitles` | No | boolean | Download video subtitles/transcripts when available (per-video mode only). Default `false` | `false` |
| `saveSubtitlesToKvs` | No | boolean | Store every downloaded transcript in the run's key-value store under its own key. Default `false` | `false` |
| `subtitlesLanguage` | No | string (enum, 20 languages) | Primary subtitle/transcript language. Default `"en"` | `"en"` |
| `preferAutoGenerated` | No | boolean | Prefer auto-generated captions over manually uploaded ones. Default `false` | `false` |
| `subtitlesFormat` | No | string (enum: `srt`, `text`, `timestamp`) | SRT, plain text, or timestamped JSON. Default `"srt"` | `"srt"` |
| `sortingOrder` | No | string (enum: ``, `relevance`, `date`, `viewCount`, `rating`) | Sort the final per-video dataset by relevance, date, view count, or rating. Default `""` | `""` |
| `dateFilter` | No | string (enum: ``, `hour`, `today`, `week`, `month`, `year`) | YouTube's built-in upload-date filter. Default `""` | `""` |
| `videoTypeFilter` | No | string (enum: ``, `video`, `channel`, `playlist`, `movie`) | Filter to only standard videos (exclude Shorts). Default `""` | `""` |
| `lengthFilter` | No | string (enum: ``, `short`, `medium`, `long`) | YouTube's length presets. Default `""` | `""` |
| `publishedAfter` | No | string (date) | Only include videos published after this date (per-video mode). Default `""` | `"2025-01-01"` |
| `sortBy` | No | string (enum: \`\`, `date`, `viewCount`, `likes`) | Sort the final per-video dataset view by date, view count, or likes. Default `""` | `""` |
| `isHD` | No | boolean | Only include HD videos (720p+). Default `false` | `false` |
| `hasCC` | No | boolean | Only include videos with a proper closed-caption track. Default `false` | `false` |
| `isCreativeCommons` | No | boolean | Filter for Creative Commons licensed videos. Default `false` | `false` |
| `is3D` | No | boolean | Only stereoscopic 3D videos. Default `false` | `false` |
| `isLive` | No | boolean | Restrict to live/live-style content. Default `false` | `false` |
| `isPurchased` | No | boolean | Best-effort filter for purchased/paid content. Default `false` | `false` |
| `is4K` | No | boolean | Only videos offering a 2160p (4K) stream. Default `false` | `false` |
| `is360` | No | boolean | Only immersive 360° videos. Default `false` | `false` |
| `hasLocation` | No | boolean | Only videos with explicit location metadata. Default `false` | `false` |
| `isHDR` | No | boolean | Only High Dynamic Range videos. Default `false` | `false` |
| `isVR180` | No | boolean | Only VR180 immersive content. Default `false` | `false` |
| `proxyConfiguration` | No | object | Starting proxy setup. Auto-escalates none → Apify datacenter → residential (up to 3 retries) if YouTube blocks a request, applied to both modes | `{"useApifyProxy": false}` |

Example JSON input:

```json
{
  "discoveryKeywords": ["fitness coach"],
  "creatorChannels": ["https://www.youtube.com/@MrBeast"],
  "maxLeadsPerKeyword": 5,
  "maxChannelsTotal": 0,
  "enrichContactInfo": true,
  "enrichSocialLinks": true,
  "requireEmail": false,
  "requirePhone": false,
  "scrapeMode": "leads",
  "searchTerms": [],
  "startUrls": [],
  "maxVideos": 10,
  "maxShorts": 0,
  "maxStreams": 0,
  "downloadSubtitles": false,
  "saveSubtitlesToKvs": false,
  "subtitlesLanguage": "en",
  "preferAutoGenerated": false,
  "subtitlesFormat": "srt",
  "sortingOrder": "",
  "dateFilter": "",
  "videoTypeFilter": "",
  "lengthFilter": "",
  "publishedAfter": "",
  "sortBy": "",
  "isHD": false,
  "hasCC": false,
  "isCreativeCommons": false,
  "is3D": false,
  "isLive": false,
  "isPurchased": false,
  "is4K": false,
  "is360": false,
  "hasLocation": false,
  "isHDR": false,
  "isVR180": false,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

The most common input mistake is mixing input shapes without setting `scrapeMode` explicitly: if both `discoveryKeywords`/`creatorChannels` and `searchTerms`/`startUrls` are present, the Actor resolves to `leads` mode and silently ignores the per-video fields — always set `scrapeMode` yourself when combining an old per-video input JSON with the new lead-discovery fields.

### ⬆️ Output

Every run pushes typed, normalized JSON rows to the Actor's dataset — no HTML, no manual parsing. Results can be exported as JSON, CSV, Excel, or the other formats Apify's dataset view supports. The row shape depends on `scrapeMode`: `leads` mode produces one creator-lead row per channel, `videos` mode produces one row per video/Short/stream.

#### Scraped creator lead (`scrapeMode: "leads"`)

```json
{
  "type": "channelLead",
  "channelName": "Example Fitness Co.",
  "channelUrl": "https://www.youtube.com/@examplefitnessco",
  "channelId": "UCxxxxxxxxxxxxxxxxxxxxxx",
  "channelUsername": "examplefitnessco",
  "numberOfSubscribers": 482000,
  "totalViews": 61500000,
  "totalVideos": 312,
  "country": "US",
  "joinedDate": "Feb 3, 2016",
  "isVerified": true,
  "avatarUrl": "https://yt3.googleusercontent.com/abc123.jpg",
  "bannerUrl": "https://yt3.googleusercontent.com/def456.jpg",
  "description": "Certified coach sharing fitness programs. Business: hello@examplefitnessco.com",
  "email": "hello@examplefitnessco.com",
  "phone": "+14155550123",
  "website": "https://examplefitnessco.com/",
  "linktreeUrl": "https://linktr.ee/examplefitnessco",
  "instagramHandle": "examplefitnessco",
  "tiktokHandle": "examplefitnessco",
  "twitterHandle": "examplefit",
  "facebookUrl": "https://facebook.com/examplefitnessco",
  "discordUrl": "https://discord.gg/examplefit",
  "otherLinks": [
    { "title": "Merch store", "url": "https://examplefitnessco.store/" }
  ],
  "hasContactInfo": true,
  "discoveryMethod": "keywordSearch",
  "sourceKeyword": "fitness coach"
}
```

#### Scraped video (`scrapeMode: "videos"`, legacy per-video mode)

```json
{
  "title": "Full Body Fitness Routine for Beginners",
  "type": "video",
  "id": "abc123XYZ89",
  "url": "https://www.youtube.com/watch?v=abc123XYZ89",
  "thumbnailUrl": "https://i.ytimg.com/vi/abc123XYZ89/hq720.jpg",
  "viewCount": 954211,
  "date": "2025-11-02T00:00:00.000Z",
  "likes": 41230,
  "location": null,
  "channelName": "Example Fitness Co.",
  "channelUrl": "https://www.youtube.com/channel/UCxxxxxxxxxxxxxxxxxxxxxx",
  "channelUsername": "examplefitnessco",
  "channelId": "UCxxxxxxxxxxxxxxxxxxxxxx",
  "numberOfSubscribers": 482000,
  "duration": "00:14:32",
  "commentsCount": 1876,
  "text": "A full-body beginner routine you can do at home. No equipment needed. #fitness #homeworkout",
  "descriptionLinks": [
    { "url": "https://www.youtube.com/hashtag/fitness", "text": "#fitness" },
    { "url": "https://www.youtube.com/hashtag/homeworkout", "text": "#homeworkout" }
  ],
  "subtitles": ["en", "es"],
  "order": 0,
  "commentsTurnedOff": false,
  "fromYTUrl": "https://www.youtube.com/results?search_query=fitness+coach",
  "hashtags": ["#fitness", "#homeworkout"],
  "isCreativeCommons": false,
  "isPurchased": false,
  "transcript": "1\n00:00:00,000 --> 00:00:03,500\nWelcome back to the channel...\n",
  "transcriptLanguage": "en",
  "transcriptFormat": "srt"
}
```

### How many results can you scrape with YouTube Scraper With Creator Contact & Lead Enrichment?

In leads mode, there is no hard cap in the Actor itself unless you set one: `maxLeadsPerKeyword` bounds discovery to 1–200 unique channels per keyword (default 5), and `maxChannelsTotal` optionally caps the combined total across all keywords and direct channels at up to 5,000 (0 = unlimited). Keyword discovery paginates the YouTube search endpoint internally up to 20 pages per keyword while collecting unique channels. In legacy per-video mode, `maxVideos`, `maxShorts`, and `maxStreams` each accept 0–9,999 per search term, and the search-result pagination for a single query stops after a built-in safety limit of 50 pages regardless of the limits set. There is no platform-side result cap beyond what YouTube's own search index returns for a given query. Larger runs simply take proportionally longer since each channel lead requires its own About-page fetch and each video requires its own metadata fetch.

### Integrate YouTube Scraper With Creator Contact & Lead Enrichment and automate your workflow

YouTube Scraper With Creator Contact & Lead Enrichment works with any language or tool that can send an HTTP request.

#### REST API integration

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_API_TOKEN>")

run = client.actor("youtube-scraper-with-creator-contact-lead-enrichment").call(
    run_input={
        "discoveryKeywords": ["fitness coach"],
        "maxLeadsPerKeyword": 5,
        "requireEmail": True,
    }
)

for lead in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(lead["channelName"], lead.get("email"))
```

Works in Python, Node.js, Go, Ruby, cURL — anything that can call the Apify API.

#### MCP for AI agents

This Actor is reachable through Apify's own Actors MCP Server (`https://mcp.apify.com`), which exposes any Actor by its store ID as a callable tool for MCP-compatible clients (Claude Desktop, Cursor, VS Code with GitHub Copilot). Add it with a `tools` query parameter, e.g. `https://mcp.apify.com?tools=<your-username>/youtube-scraper-with-creator-contact-lead-enrichment`, or install the local stdio server with `npx -y @apify/actors-mcp-server`.

#### Automation platforms (n8n, Make)

Apify publishes an official n8n integration that lets an "Apify" node run this Actor and pass its dataset items into the rest of an n8n workflow — useful for piping fresh creator leads straight into a CRM node on a schedule. Apify's Make integration works the same way: an "Apify" module runs the Actor and returns its dataset results as a Make scenario step, so a new batch of creator leads can trigger downstream modules (email, spreadsheet, CRM) automatically.

### Is it legal to scrape YouTube?

Scraping publicly accessible YouTube pages is generally lawful; this Actor only reads channel About pages and search results that any visitor can already see without logging in — it does not access private, login-gated, or restricted content. That said, the email addresses and phone numbers this Actor extracts are personal data under regulations like GDPR and CCPA once you store or use them, even though the creator chose to publish them. Having a lawful basis for further processing (e.g. legitimate interest for B2B outreach, honoring opt-out/deletion requests) is your responsibility as the data controller, not the Actor's. Consult legal counsel for commercial use cases involving bulk personal data, especially outreach campaigns run at scale across multiple jurisdictions.

### Frequently asked questions

#### Does YouTube Scraper With Creator Contact & Lead Enrichment work without a YouTube account?

Yes. The Actor reads public channel About pages and YouTube's search endpoint directly; no YouTube account, login, or Google API key is required to run it.

#### How often is the scraped data updated?

Every run performs a live fetch against YouTube at the time it executes — there is no cache layer, so results reflect the channel or video's public state as of that run.

#### What happens if a creator hasn't published an email or phone number?

The `email` and `phone` fields are left `null` for that lead rather than guessed or fabricated. Set `requireEmail` and/or `requirePhone` to `true` if you only want leads that actually carry that contact signal — channels without one are skipped entirely instead of appearing as a null-value row.

#### Can I scrape private or restricted YouTube channels?

No. Only publicly accessible channel About pages and public search results are returned. Channels that are terminated, region-locked, or otherwise inaccessible without authentication will fail to fetch and are logged as a skipped target rather than returned as empty data.

#### Does YouTube Scraper With Creator Contact & Lead Enrichment work for AI agent workflows and LLM pipelines?

Yes. It's callable as a plain HTTP endpoint through the Apify API from any agent framework, and it's also reachable through Apify's Actors MCP Server for MCP-compatible clients. Every response is typed JSON with a stable field set, so there's no parsing step before passing results into an LLM context or agent tool call.

#### How does this Actor handle YouTube's anti-bot defenses?

Requests start with no proxy and automatically escalate to Apify datacenter proxy, then residential proxy, on a 403/429 response, retrying the residential connection up to 3 times before locking onto whichever level worked for the rest of the run. This applies to both channel About-page fetches and the legacy per-video search engine.

#### Does this Actor return data in a format LLMs can use directly?

Yes. Output is typed, normalized JSON with stable field names — no HTML, no selectors, no parsing. It can be passed directly into an LLM context window, indexed into a vector store, or routed through an agent tool call.

#### Can I use this Actor without managing proxies?

Yes. The Actor handles its own proxy escalation (none → datacenter → residential) automatically. You can still supply your own `proxyConfiguration` if you want to start from a specific proxy group instead of the default.

#### What happens when YouTube changes its structure or blocks the scraper?

The Actor is maintained, and its output schema is designed to stay stable — field names and types on your end don't change even when the underlying page structure does. No specific turnaround time is promised for any given fix.

### Your feedback

Found a bug or missing a field? We want to know. Open an issue through the **Issues** tab on this Actor's Apify Store page, or reach out through Apify Console's support channel — reports like this directly shape what gets fixed and maintained next.

# Actor input Schema

## `discoveryKeywords` (type: `array`):

Niche/topic keywords (e.g. "fitness coach", "crypto trading") used to discover creator channels via YouTube search. The actor searches each keyword, collects the unique channels behind the matching videos, and enriches each one into a lead row. Also accepts the base actor's original 'searchTerms' key.

## `creatorChannels` (type: `array`):

Direct YouTube channel URLs, @handles, or channel IDs (UC...) to enrich into lead rows — skips discovery and goes straight to the About page. Example: "https://www.youtube.com/@MrBeast" or "@MrBeast" or "UCX6OQ3DkcsbYNE6H8uQQuVA". Also accepts the base actor's original 'startUrls' key.

## `maxLeadsPerKeyword` (type: `integer`):

How many unique channels to discover (and enrich into a lead row) per discovery keyword. Example: maxLeadsPerKeyword=5 + 3 keywords -> up to 15 channel leads from discovery. Default is 5.

## `maxChannelsTotal` (type: `integer`):

Global cap on the total number of channel leads produced across ALL keywords and direct channels combined in this run. Use 0 for unlimited (bounded only by maxLeadsPerKeyword per keyword).

## `enrichContactInfo` (type: `boolean`):

Regex-scan each channel's real, published About-page description and external links for a business email address and/or phone number. Left null when the creator hasn't published one — contact fields are never guessed or fabricated.

## `enrichSocialLinks` (type: `boolean`):

Classify each channel's About-page external links into queryable lead fields: website, Linktree, Instagram, TikTok, X/Twitter, Facebook, Discord — instead of a single raw links array.

## `requireEmail` (type: `boolean`):

When enabled, channels where no email address could be found on the About page are skipped entirely (not emitted as a null-email row).

## `requirePhone` (type: `boolean`):

When enabled, channels where no phone number could be found on the About page are skipped entirely.

## `scrapeMode` (type: `string`):

'Creator leads (channel-level)' is this actor's own mode: one row per channel with contact/social enrichment (uses the Lead Discovery + Contact Enrichment sections above). 'Per-video search (base-compatible)' runs the original YouTube-Scraper per-video engine unchanged, using the fields below — pick this to keep using an existing YouTube-Scraper input JSON as-is.

## `searchTerms` (type: `array`):

Same as the base actor's 'searchTerms': YouTube search keywords used only when Scrape mode = 'Per-video search'. Ignored in Creator leads mode (use 'Discovery keywords' there instead).

## `startUrls` (type: `array`):

Same as the base actor's 'startUrls': direct YouTube URLs scraped only when Scrape mode = 'Per-video search'. Ignored in Creator leads mode (use 'Creator channels' there instead).

## `maxVideos` (type: `integer`):

Set how many regular (non-Shorts, non-live) videos to scrape for each search term when Scrape mode = 'Per-video search'. Use 0 to skip long-form videos completely.

## `maxShorts` (type: `integer`):

Control how many YouTube Shorts to collect per keyword in per-video mode. Use 0 to skip Shorts.

## `maxStreams` (type: `integer`):

Limit how many live/upcoming streams are scraped per search term in per-video mode. Use 0 to ignore live content.

## `downloadSubtitles` (type: `boolean`):

Download video subtitles/transcripts when available (per-video mode only).

## `saveSubtitlesToKvs` (type: `boolean`):

Store every downloaded transcript in the default key-value store under its own key.

## `subtitlesLanguage` (type: `string`):

Primary subtitle/transcript language.

## `preferAutoGenerated` (type: `boolean`):

Prefer auto-generated captions over manually uploaded ones.

## `subtitlesFormat` (type: `string`):

SRT, plain text, or timestamped JSON.

## `sortingOrder` (type: `string`):

Sort the final per-video dataset by relevance, date, view count, or rating.

## `dateFilter` (type: `string`):

YouTube's built-in Upload date filter.

## `videoTypeFilter` (type: `string`):

Filter to only standard videos (exclude Shorts).

## `lengthFilter` (type: `string`):

YouTube's length presets.

## `publishedAfter` (type: `string`):

Only include videos published after this date (per-video mode).

## `sortBy` (type: `string`):

Sort the final per-video dataset view by date, view count, or likes.

## `isHD` (type: `boolean`):

Only include HD videos (720p+).

## `hasCC` (type: `boolean`):

Only include videos with a proper closed-caption track.

## `isCreativeCommons` (type: `boolean`):

Filter for Creative Commons licensed videos.

## `is3D` (type: `boolean`):

Only stereoscopic 3D videos.

## `isLive` (type: `boolean`):

Restrict to live/live-style content.

## `isPurchased` (type: `boolean`):

Best-effort filter for purchased/paid content.

## `is4K` (type: `boolean`):

Only videos offering a 2160p (4K) stream.

## `is360` (type: `boolean`):

Only immersive 360° videos.

## `hasLocation` (type: `boolean`):

Only videos with explicit location metadata.

## `isHDR` (type: `boolean`):

Only High Dynamic Range videos.

## `isVR180` (type: `boolean`):

Only VR180 immersive content.

## `proxyConfiguration` (type: `object`):

Starting proxy setup. By default the actor uses no proxy and, if YouTube blocks requests (About pages or search), automatically escalates to Apify datacenter proxy and then residential proxy with up to 3 retries, locking onto residential for the rest of the run. Applies to both Creator leads and Per-video search modes.

## Actor input object example

```json
{
  "discoveryKeywords": [
    "fitness coach"
  ],
  "creatorChannels": [],
  "maxLeadsPerKeyword": 5,
  "maxChannelsTotal": 0,
  "enrichContactInfo": true,
  "enrichSocialLinks": true,
  "requireEmail": false,
  "requirePhone": false,
  "scrapeMode": "leads",
  "searchTerms": [],
  "startUrls": [],
  "maxVideos": 10,
  "maxShorts": 0,
  "maxStreams": 0,
  "downloadSubtitles": false,
  "saveSubtitlesToKvs": false,
  "subtitlesLanguage": "en",
  "preferAutoGenerated": false,
  "subtitlesFormat": "srt",
  "sortingOrder": "",
  "dateFilter": "",
  "videoTypeFilter": "",
  "lengthFilter": "",
  "publishedAfter": "",
  "sortBy": "",
  "isHD": false,
  "hasCC": false,
  "isCreativeCommons": false,
  "is3D": false,
  "isLive": false,
  "isPurchased": false,
  "is4K": false,
  "is360": false,
  "hasLocation": false,
  "isHDR": false,
  "isVR180": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per creator channel (Creator leads mode): subscriber/view totals, country, join date, and — where published — email, phone, and structured social links.

## `videos` (type: `string`):

One row per video (legacy Per-video search mode): title, stats, description, subtitles availability, and filter flags — same shape as the base YouTube-Scraper actor.

## `transcripts` (type: `string`):

Downloaded per-video transcripts, saved to the key-value store only when 'Save subtitles to key-value store' is enabled in Per-video search mode.

# 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 = {
    "discoveryKeywords": [
        "fitness coach"
    ],
    "creatorChannels": [],
    "scrapeMode": "leads",
    "searchTerms": [],
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("api-empire/youtube-scraper").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 = {
    "discoveryKeywords": ["fitness coach"],
    "creatorChannels": [],
    "scrapeMode": "leads",
    "searchTerms": [],
    "startUrls": [],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("api-empire/youtube-scraper").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 '{
  "discoveryKeywords": [
    "fitness coach"
  ],
  "creatorChannels": [],
  "scrapeMode": "leads",
  "searchTerms": [],
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call api-empire/youtube-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/ITQ6PaUfANsO7uK32/builds/Yw5weVerzaVdbBDNo/openapi.json
