# YouTube Scraper $2/1K — Videos, Channels, Comments, Transcripts (`blackfalcondata/youtube-data-scraper`) Actor

Scrape YouTube videos, channels, comments, and transcripts in one tool — by keyword or by video, channel, and playlist URL. Get rich per-video metadata, comments with replies, and translated transcripts. Incremental mode and RAG-ready output included.

- **URL**: https://apify.com/blackfalcondata/youtube-data-scraper.md
- **Developed by:** [Black Falcon Data](https://apify.com/blackfalcondata) (community)
- **Categories:** Videos, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

### What does YouTube Scraper $2/1K do?

YouTube Scraper extracts structured data from [youtube.com](https://youtube.com) — videos, channels, comments, and transcripts in one run. Pull rich video metadata (views, likes, duration, descriptions, chapters, hashtags), full channel stats, top or newest comments with replies, multi-format transcripts with translation, and topic-based trending. Search by keyword or paste video, channel, and playlist URLs. Comments automatically use US residential IPs when needed. Transcripts and direct video-URL detail need US residential IPs (choose the RESIDENTIAL group, country US, in the Proxy input); search, channel, and trending modes run without it.

**New to Apify?** [Sign up free](https://console.apify.com/sign-up?fpr=1h3gvi) and use the included $5 monthly platform credit to test this actor.

### Key features

<!-- KEY_FEATURES:START -->
- **🎛️ Six data types in one actor** — videos, channels, comments (with replies), transcripts, trending, and keyword search — all from one run. Mix pasted URLs, URL lists, and search queries as targets in the same job.
- **📝 Multi-format transcripts + translation** — pull full captions as timed JSON segments, plain text, SRT, WebVTT, or raw XML — every variant ships alongside `fullText`. Pick the track with `transcriptLanguage` or auto-translate with `translateTo`. **Transcripts** need **US residential IPs** (the `RESIDENTIAL` group, country `US`) and run slower; every other mode, including rich video detail, works on the default proxy.
- **🎬 Rich video metadata** — every video carries views, duration, publish date, description, category, keywords, hashtags, chapters, channel handle, and thumbnails at `detailLevel: standard`+ (`basic` = view-only). Like, comment, and subscriber counts populate when you use US residential IPs (abbreviated like/subscriber, exact comment).
- **📈 Trending + precise search filters** — rank the most-viewed recent videos for a topic with Trending mode, and shape search with native filters: sort, upload window, duration, result type, and HD/4K, subtitle, Creative Commons, and live flags. Pick a channel's tab and order with `channelVideoType` (videos/shorts/live) and `channelSortOrder`, then post-filter any field with a `customFilters` expression (e.g. `viewCount > 100000 AND durationSec < 600`).
- **🤖 RAG-ready output** — flip `ragOutput` to emit embedding-ready `{ id, text, metadata }` documents instead of raw records; `ragChunkSize`/`ragChunkOverlap` split long transcripts into overlapping chunks (chunking never changes billing).
- **♻️ Incremental mode** — re-run the same configuration and receive only what changed. Each record is classified `NEW`, `UPDATED`, `UNCHANGED`, or `REAPPEARED` and carries `changeType`, `firstSeenAt`, and `lastSeenAt`. Classification tracks content (title, description), not view/like counts, so stat drift never flags everything. Use a stable `stateKey` for a continuous feed.
<!-- KEY_FEATURES:END -->

### What data can you extract from youtube.com?

Each result includes Core listing fields (`datasetType`, `videoId`, `title`, `channelName`, `channelHandle`, `viewCount`, `viewCountText`, and `durationSec`, and more). All fields are always present — unavailable data points are returned as `null`, never omitted.

### Input

The main inputs are a result limit. Additional filters and options are available in the input schema.

Key parameters:

- **`scrapeVideos`** — Collect video items (metadata, stats, descriptions) from search results, channel pages, playlists, and pasted video URLs. This is the default mode. Default: true. (default: `true`)
- **`scrapeChannels`** — Collect channel items (name, subscriber count, video count, country, links) from channel URLs/@handles or channel results in a search. Combine with Channel URLs or a search using Result Type = Channels only. Default: false. (default: `false`)
- **`scrapeComments`** — Fetch comments for each scraped video. Requires a video target (search, channel, playlist, or pasted Video URL). Comments automatically use US residential IPs when needed (residential access required on your account). Tune volume/order in the Comments settings below. Default: false. (default: `false`)
- **`scrapeTranscripts`** — Download full transcripts (captions) for each scraped video. Requires a video target. ⚠️ Needs US residential IPs (RESIDENTIAL group, country US) or transcripts come back empty; also runs slower (a browser step). Configure format, language, and translation in the Transcripts settings below. Default: false. (default: `false`)
- **`scrapeTrending`** — Collect the most-viewed recent videos for your topic, ranked by view count over a recent upload window. Requires at least one Search Query, or a Trending Topic, to define what to rank. Default: false. (default: `false`)
- **`maxResults`** — Maximum number of videos and channels to collect across all tasks. Comments and transcripts are extra per-video records, not counted against this limit (set their volume with Comments per video / Scrape transcripts). Set 0 for unlimited. Default: 50. Aliases: `limit`, `max`, `maxItems`, `maxVideos`. (default: `50`)
- ...and 64 more parameters

### Input examples

**Basic search** — Targeted run scoped to a specific searchQueries.

→ Full payload per result — all standard fields populated where the source provides them.

```json
{
  "searchQueries": [
    "nodejs tutorial"
  ],
  "maxResults": 50
}
````

**Incremental tracking** — Only emit videos that changed since the previous run with this `stateKey`.

→ First run builds the baseline state. Subsequent runs emit only records that are new or whose tracked content changed. Set `emitUnchanged: true` to include unchanged records as well.

```json
{
  "searchQueries": [
    "nodejs tutorial"
  ],
  "maxResults": 200,
  "incrementalMode": true,
  "stateKey": "youtube-tracker"
}
```

### Output

Each run produces a dataset of structured video records. Results can be downloaded as JSON, CSV, or Excel from the Dataset tab in Apify Console.

### Example video record

```json
{
  "datasetType": "video",
  "videoId": "n61ULEU7CO0",
  "title": "Best of lofi hip hop 2021 ✨ [beats to relax/study to]",
  "channelName": "Lofi Girl",
  "channelHandle": "@LofiGirl",
  "viewCount": 55051243,
  "viewCountText": "55,051,243 views",
  "durationSec": 22258,
  "durationText": "6:10:58",
  "publishedAt": "2022-05-30T20:38:41.032Z",
  "publishedTimeText": "4 years ago",
  "isShort": false,
  "status": "OK",
  "url": "https://www.youtube.com/watch?v=n61ULEU7CO0",
  "embedUrl": "https://www.youtube.com/embed/n61ULEU7CO0",
  "shortUrl": "https://youtu.be/n61ULEU7CO0",
  "scrapedAt": "2026-05-31T12:00:00.000Z"
}
```

### Incremental fields

When `incremental: true`, each record also carries:

- `changeType` — one of `NEW`, `UPDATED`, `UNCHANGED`, `REAPPEARED`, `EXPIRED`. Default output covers `NEW` / `UPDATED` / `REAPPEARED`; set `emitUnchanged: true` or `emitExpired: true` to opt into the others.
- `firstSeenAt`, `lastSeenAt` — ISO-8601 timestamps tracking the listing across runs.

### How to scrape youtube.com

1. Go to [YouTube Scraper $2/1K](https://apify.com/blackfalcondata/youtube-data-scraper?fpr=1h3gvi) in Apify Console.
2. Configure the input.
3. Set `maxResults` to control how many results you need.
4. Click **Start** and wait for the run to finish.
5. Export the dataset as JSON, CSV, or Excel.

### Use cases

- Extract video data from youtube.com for market research and competitive analysis.
- Monitor new and changed listings on scheduled runs without processing the full dataset every time.
- Export clean, structured data to dashboards, spreadsheets, or data warehouses.

### How much does it cost to scrape youtube.com?

YouTube Scraper $2/1K uses [pay-per-event](https://docs.apify.com/platform/actors/paid-actors/pay-per-event) pricing. You pay a small fee when the run starts and then for each result that is actually produced.

- **Run start:** $0.005 per run
- **Per result:** $0.002 per video record

Example costs:

- 10 results: **$0.03**
- 25 results: **$0.06**
- 100 results: **$0.21**
- 200 results: **$0.41**
- 500 results: **$1**

#### Example: recurring monitoring savings

These examples compare full re-scrapes with incremental runs at different churn rates. Churn is the share of listings that are new or whose tracked content changed since the previous run. Actual churn depends on your query breadth, source activity, and polling frequency — the scenarios below are examples, not predictions.

Example setup: 200 results per run, daily polling (30 runs/month). Event-pricing examples scale linearly with result count.

Numbers below are for the primary **Result** event. Other events (**Transcript**) are billed separately when they fire and follow the same incremental logic — when the underlying record has not changed, no charge is emitted.

| Churn rate | Full re-scrape run cost | Incremental run cost | Savings vs full re-scrape | Monthly cost after baseline |
|---|---:|---:|---:|---:|
| 5% — stable niche query | $0.41 | $0.03 | $0.38 (94%) | $0.75 |
| 15% — moderate broad query | $0.41 | $0.07 | $0.34 (84%) | $1.95 |
| 30% — high-volume aggregator | $0.41 | $0.13 | $0.28 (69%) | $3.75 |

Full re-scrape monthly cost at daily polling: $12.15. First month with incremental costs $1.13 / $2.29 / $4.03 for the 5% / 15% / 30% scenarios because the first run builds baseline state at full cost before incremental savings apply.

Platform usage (compute and proxies) is billed separately by Apify based on actual consumption. Incremental runs consume less on result processing, though fixed per-run overhead stays the same.

### FAQ

#### How many results can I get from youtube.com?

The number of results depends on the search query and available listings on youtube.com. Use the `maxResults` parameter to control how many results are returned per run.

#### Does YouTube Scraper $2/1K support recurring monitoring?

Yes. Enable incremental mode to only receive new or changed listings on subsequent runs. This is ideal for scheduled monitoring where you want to track changes over time without re-processing the full dataset.

#### Can I integrate YouTube Scraper $2/1K with other apps?

Yes. YouTube Scraper $2/1K works with Apify's [integrations](https://apify.com/integrations?fpr=1h3gvi) to connect with tools like Zapier, Make, Google Sheets, Slack, and more. You can also use webhooks to trigger actions when a run completes.

#### Can I use YouTube Scraper $2/1K with the Apify API?

Yes. You can start runs, manage inputs, and retrieve results programmatically through the [Apify API](https://docs.apify.com/api/v2). Client libraries are available for JavaScript, Python, and other languages.

#### Can I use YouTube Scraper $2/1K through an MCP Server?

Yes. Apify provides an [MCP Server](https://apify.com/apify/actors-mcp-server?fpr=1h3gvi) that lets AI assistants and agents call this actor directly. Use a single `descriptionFormat`, RAG output, and `excludeEmptyFields` to keep payloads manageable for LLM context windows.

#### Is it legal to scrape youtube.com?

This actor extracts publicly available data from youtube.com. Web scraping of public information is generally considered legal, but you should always review the target site's terms of service and ensure your use case complies with applicable laws and regulations, including GDPR where relevant.

#### What counts as a billable result?

A "result" is one record written to the dataset, billed at the per-result price. What a single result is depends on what you collect:

- **Videos, trending, and playlist videos** — 1 result per video.
- **Channels** — the channel profile is 1 result, plus each listed video is 1 result.
- **Comments** — **1 result per top-level comment.** Replies (when `includeReplies` is on) are nested under their parent comment's `replies` field and are **not** billed separately. A single video with 300 top-level comments is 300 results, so set `commentsPerVideo` to cap how many you collect.
- **Transcripts** — billed at the separate transcript event price, **not** counted as a result.

When `ragOutput` is on, a long transcript split into many chunks still bills as **one** source item — chunking never multiplies your cost.

#### Do I need a proxy, and what does it cost?

Search, Channel, Comments, Trending, and per-video detail all work on the default proxy — including the rich video metadata enriched for search/channel/playlist/trending results. **Only Transcripts need US residential IPs** — in the Proxy input, choose the `RESIDENTIAL` group with country `US` (or supply your own US residential-IP proxy URLs in the same input). Without it, transcripts come back empty.

Platform usage (compute and proxy traffic) is billed separately by Apify based on actual consumption, on top of the per-event prices below. Residential traffic is the main variable cost on transcript-heavy runs, so budget for it when you enable transcripts at scale.

#### What should I know about coverage and limits?

- **Transcripts require captions and US residential IPs.** A transcript is only returned when the video has captions (uploaded or auto-generated) and the run routes through the `RESIDENTIAL` group with country `US`. Videos without captions yield no transcript item — this is normal, not an error.
- **Transcripts run slower.** The transcript step is heavier than the other modes, so transcript-heavy jobs take longer — set a generous run time limit.
- **Trending is topic-based.** There is no single global trending feed; Trending mode returns the most-viewed recent videos for the topic(s) you provide, so it needs at least one search query or a Trending Topic.
- **Age-restricted, private, or unavailable videos** return a `status` field with the basic info that can be seen, rather than failing — comments and transcripts cannot be collected for them.
- **Contact emails are not extracted.** The actor extracts links and social profiles found in descriptions, but does not mine personal email addresses.
- **Result counts are approximate.** YouTube limits how deep search and listing results can be paged, so a very high `maxResults` may return fewer items than requested.

#### Your feedback

If you have questions, need a feature, or found a bug, please [open an issue](https://apify.com/blackfalcondata/youtube-data-scraper/issues?fpr=1h3gvi) on the actor's page in Apify Console. Your feedback helps us improve.

### You might also like

- [Actiris Brussels Job Scraper](https://apify.com/blackfalcondata/actiris-scraper?fpr=1h3gvi) — Scrape all active job listings from actiris.brussels — official Brussels public employment service..
- [Adzuna Job Scraper — Global Jobs with Salary & Coordinates](https://apify.com/blackfalcondata/adzuna-scraper?fpr=1h3gvi) — Scrape adzuna.com job listings across 19 country markets with structured salary data.
- [APEC.fr Scraper - French Executive Jobs](https://apify.com/blackfalcondata/apec-scraper?fpr=1h3gvi) — Scrape apec.fr - French executive job listings with salary ranges, company, location, skills,.
- [Arbeitsagentur Jobs Feed — German Federal Employment Agency](https://apify.com/blackfalcondata/arbeitsagentur-jobs-feed?fpr=1h3gvi) — Extract job listings from arbeitsagentur.de — Germany's official public employment portal with 1M+.
- [Arbeitsagentur Scraper - German Jobs](https://apify.com/blackfalcondata/arbeitsagentur-scraper?fpr=1h3gvi) — Scrape arbeitsagentur.de - Germany’s official employment portal with 1M+ listings. Contact data,.
- [Arbetsformedlingen Job Scraper](https://apify.com/blackfalcondata/arbetsformedlingen-scraper?fpr=1h3gvi) — Scrape arbetsformedlingen.se (Platsbanken) — Sweden's official employment portal. Returns 84.
- [AutoScout24 Scraper — European Car Listings with Dealer Data](https://apify.com/blackfalcondata/autoscout24-scraper?fpr=1h3gvi) — Scrape autoscout24.com - Europe's largest used car marketplace with 770K+ listings. Structured.
- [Bayt.com Scraper — MENA Jobs with Salary & Skills Filter](https://apify.com/blackfalcondata/bayt-scraper?fpr=1h3gvi) — Scrape bayt.com — leading Middle East job board covering UAE, Saudi Arabia, Qatar, Egypt and 9 more.

### Getting started with Apify

New to Apify? [Create a free account with $5 credit](https://console.apify.com/sign-up?fpr=1h3gvi) — no credit card required.

1. Sign up — $5 platform credit included
2. Open this actor and configure your input
3. Click **Start** — export results as JSON, CSV, or Excel

Need more later? [See Apify pricing](https://apify.com/pricing?fpr=1h3gvi).

# Actor input Schema

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

YouTube video, channel, or playlist URLs to scrape directly (one per line). Each entry is routed automatically by type and processed as its own task. You can also paste a bare 11-character video ID (e.g. "dQw4w9WgXcQ") or a bare @handle (e.g. "@MrBeast"). Merged with Video / Channel / Playlist URLs below. Used by all modes. Default: empty. Also accepts the aliases `url`, `urls`, and `startURLs` (and the typed lists `videoUrls` / `channelUrls` / `playlistUrls` below all merge in here).

## `videoUrls` (type: `array`):

Video URLs or bare 11-character video IDs (one per line), e.g. "https://www.youtube.com/watch?v=dQw4w9WgXcQ" or "dQw4w9WgXcQ". Use this to paste a list of videos separately from channels and playlists. Merged with Start URLs. Feeds Video, Comments, and Transcripts modes. Default: empty. Also accepts the aliases `videoUrl`, `url`, and `urls`.

## `channelUrls` (type: `array`):

Channel URLs or bare @handles (one per line), e.g. "https://www.youtube.com/@MrBeast" or "@veritasium". Use this to paste a list of channels separately from videos and playlists. Merged with Start URLs. Feeds Video mode (channel uploads) and Channel mode (channel profiles). Default: empty. Also accepts the alias `channelUrl`.

## `playlistUrls` (type: `array`):

Playlist URLs or bare playlist IDs (one per line), e.g. "https://www.youtube.com/playlist?list=PLxxxx" or "PLxxxx". Each playlist's videos are collected and tagged with their source `playlistId`. Merged with Start URLs. Feeds Video mode. Default: empty. Also accepts the alias `playlistUrl`.

## `searchQueries` (type: `array`):

Keywords to search on YouTube (one per line), e.g. "nodejs tutorial". Each query runs as a separate search task and respects the Search Filters below. You can also paste several queries separated by commas. Required for the Trending mode (to define the topic to rank). Default: empty. Also accepts the aliases `query`, `q`, `keyword`, `keywords`, `searchQuery`, and `search`.

## `scrapeVideos` (type: `boolean`):

Collect video items (metadata, stats, descriptions) from search results, channel pages, playlists, and pasted video URLs. This is the default mode. Default: true.

## `scrapeChannels` (type: `boolean`):

Collect channel items (name, subscriber count, video count, country, links) from channel URLs/@handles or channel results in a search. Combine with Channel URLs or a search using Result Type = Channels only. Default: false.

## `scrapeComments` (type: `boolean`):

Fetch comments for each scraped video. Requires a video target (search, channel, playlist, or pasted Video URL). Comments automatically use US residential IPs when needed (residential access required on your account). Tune volume/order in the Comments settings below. Default: false.

## `scrapeTranscripts` (type: `boolean`):

Download full transcripts (captions) for each scraped video. Requires a video target. ⚠️ Needs US residential IPs (RESIDENTIAL group, country US) or transcripts come back empty; also runs slower (a browser step). Configure format, language, and translation in the Transcripts settings below. Default: false.

## `scrapeTrending` (type: `boolean`):

Collect the most-viewed recent videos for your topic, ranked by view count over a recent upload window. Requires at least one Search Query, or a Trending Topic, to define what to rank. Default: false.

## `trendingCategory` (type: `string`):

Optional extra topic to rank when Scrape Trending is on, e.g. "music", "gaming", or "movies". Added alongside your search queries as a topic to find the most-viewed recent videos for. Applies to Trending mode. Default: blank (rank only your search queries).

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

Order of search results. Applies to Search mode. Options: Relevance (YouTube's default ranking); Upload date (newest first); View count (most-viewed first); Rating (highest-rated first). Default: "relevance".

## `uploadDate` (type: `string`):

Restrict search results to videos uploaded within this window. Applies to Search mode. Options: Last hour; Today (last 24 hours); This week (last 7 days); This month (last 30 days); This year (last 365 days). Default: no restriction (any date).

## `videoDuration` (type: `string`):

Filter search results by video length. Applies to Search mode. Options: Short (under 4 minutes); Medium (4–20 minutes); Long (over 20 minutes). Default: no restriction (any length).

## `resultType` (type: `string`):

Which kind of YouTube results a search should return. Applies to Search mode. Options: Videos only; Channels only (use together with Scrape Channels to find channels by keyword); Any (mixed results). To scrape a playlist, paste its playlist URL into Start URLs instead. Default: "video".

## `filterHd` (type: `boolean`):

Only return videos available in high definition. Applies to Search mode. Default: false.

## `filterSubtitles` (type: `boolean`):

Only return videos that have subtitles or closed captions. Useful as a pre-filter before transcript scraping. Applies to Search mode. Default: false.

## `filterCreativeCommons` (type: `boolean`):

Only return videos published under a Creative Commons license. Applies to Search mode. Default: false.

## `filterLive` (type: `boolean`):

Only return videos that are currently live. Applies to Search mode. Default: false.

## `filter4k` (type: `boolean`):

Only return videos available in 4K resolution. Applies to Search mode. Default: false.

## `filter360` (type: `boolean`):

Only return 360-degree videos. Applies to Search mode. Default: false.

## `filterHdr` (type: `boolean`):

Only return videos available in HDR. Applies to Search mode. Default: false.

## `includeKeywords` (type: `array`):

Post-fetch filter: keep only results whose title or description contains at least one of these keywords (case-insensitive), e.g. \["react", "vue"]. Applies to all modes. Default: empty (no filtering).

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

Post-fetch filter: drop results whose title or description contains any of these keywords (case-insensitive), e.g. \["shorts", "reaction"]. Applies to all modes. Default: empty (no filtering).

## `fromDate` (type: `string`):

Post-fetch filter: only include videos published on or after this date. Accepts an absolute ISO 8601 date (e.g. "2024-01-01") or a relative offset into the past (e.g. "7d", "2 weeks", "3 months", "1 year"). Applies to all modes. Default: no lower bound.

## `toDate` (type: `string`):

Post-fetch filter: only include videos published on or before this date. Accepts an absolute ISO 8601 date (e.g. "2024-12-31") or a relative offset into the past (e.g. "1d"). Applies to all modes. Default: no upper bound.

## `maxAgeDays` (type: `integer`):

Post-fetch filter: only include videos published within the last N days (e.g. 30). When combined with From Date, the more restrictive cutoff wins. Applies to all modes. Default: blank (no age limit).

## `customFilters` (type: `string`):

Advanced post-fetch filter expression (DSL) evaluated against each output item, e.g. "viewCount > 100000 AND durationSec < 600". For power users; leave blank for no custom filtering. Applies to all modes. Note: enrichment-derived fields (category, keywords, hashtags, description) are only populated at detailLevel "standard" and above — filtering on one of these at detailLevel "basic" leaves it null and excludes every record. Default: blank.

## `channelVideoType` (type: `string`):

Which tab to scrape when visiting a channel. Applies to Channel URLs in Video mode. Options: Regular videos (the Videos tab, long-form uploads); Shorts (the Shorts tab); Live streams (past and upcoming live broadcasts). Default: "videos".

## `channelSortOrder` (type: `string`):

Order of videos listed on a channel page. Applies to the Videos tab of Channel URLs in Video mode (sort is not available on the Shorts or Live tabs and is ignored there). Options: Newest first; Oldest first; Most popular (by view count). Default: "newest".

## `fetchAbout` (type: `boolean`):

Fetch the channel About panel to fill in join date, country, total view count, and external links on channel items. Disable to skip the extra request for faster channel runs. Applies to Channel mode. Default: true.

## `transcriptFormat` (type: `string`):

Output format for transcript data. Applies to Transcripts mode. Options: Timed segments (JSON array of { text, startMs, durationMs }); Plain text (one continuous string in `fullText`); SRT subtitles (numbered, timestamped subtitle blocks); WebVTT subtitles (web-standard caption format); Raw XML (the unprocessed caption document). All variants also include the plain `fullText`. Default: "segments".

## `transcriptLanguage` (type: `string`):

BCP-47 language code for the desired transcript track, e.g. "en" or "de". Applies to Transcripts mode. Default: blank (use the video's default caption language).

## `translateTo` (type: `string`):

BCP-47 language code to auto-translate the transcript into, e.g. "en" or "es". Applies to Transcripts mode. Default: blank (no translation).

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

When both a manual and an auto-generated transcript exist for a video, prefer the auto-generated one. Applies to Transcripts mode. Default: false (prefer the manual transcript).

## `transcriptFields` (type: `array`):

Emit only this subset of transcript output fields, e.g. \["fullText", "srt"]. Applies to Transcripts mode. Default: empty (include all transcript fields).

## `commentsPerVideo` (type: `integer`):

Maximum number of comments to fetch per video. Set 0 for unlimited. Applies to Comments mode. Default: 100.

## `commentsSort` (type: `string`):

Comment retrieval order. Applies to Comments mode. Options: Top comments (YouTube's most-relevant ranking, usually most-liked first); Newest first (most recently posted). Default: "top".

## `includeReplies` (type: `boolean`):

Also fetch replies to each top-level comment (nested under the comment's `replies` field). Increases run time and result volume. Applies to Comments mode. Default: false.

## `maxResults` (type: `integer`):

Maximum number of videos and channels to collect across all tasks. Comments and transcripts are extra per-video records, not counted against this limit (set their volume with Comments per video / Scrape transcripts). Set 0 for unlimited. Default: 50. Aliases: `limit`, `max`, `maxItems`, `maxVideos`.

## `maxResultsPerQuery` (type: `integer`):

Cap on the number of videos and channels each individual search query or target (channel / playlist) may contribute, applied independently of Max Results (per run). Like Max Results, this caps videos and channels only — comments and transcripts are additional per-video records (controlled by Comments per video and Scrape transcripts) and are not counted against it. Useful for spreading a budget evenly across several queries. Default: blank (no per-query cap).

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

Maximum number of Shorts (vertical, short-form clips) to include, applied independently of Max Results. Extra Shorts are dropped while regular videos are kept. Set 0 to exclude Shorts entirely. Applies to Video and Trending modes. Default: blank (no separate Shorts cap).

## `maxRunSeconds` (type: `integer`):

Optional soft cap on how long the run may spend fetching, e.g. 300 for five minutes. When the run nears this limit it stops collecting new items and saves whatever it has gathered so far. Applies to all modes. Default: blank (no soft cap).

## `includeShorts` (type: `boolean`):

Include YouTube Shorts (vertical, short-form clips) in video results. Turn off to keep only regular long-form videos. Applies to Video and Trending modes. Default: true.

## `shortsOnly` (type: `boolean`):

Return only YouTube Shorts and drop regular videos. Takes precedence over Include Shorts. Applies to Video and Trending modes. Default: false.

## `detailLevel` (type: `string`):

How much metadata to fetch per video. Higher levels return more fields but may require an extra request per item (slower, higher cost). Applies to Video and Trending modes. Options: Basic (only the fields available from the listing — title, channel, view count, duration; no per-video request); Standard (adds video-page fields such as likes, full description, category, keywords); Detailed (adds extra metadata such as chapters, available captions, hashtags); Complete (every field the actor can extract). Default: "standard".

## `descriptionFormat` (type: `string`):

Output format for video and channel description text. Applies to Video and Channel modes. Options: Plain text (raw text in `descriptionText`); HTML (escaped, with <br> for newlines and <a> for links, in `descriptionHtml`); Markdown (line breaks preserved, URLs linkified, in `descriptionMarkdown`); All formats (every variant alongside the plain text). Default: "text".

## `excludeEmptyFields` (type: `boolean`):

Strip null and empty fields from output items to reduce dataset size and make records easier to read. Applies to all modes. Default: false.

## `includeRunMetadata` (type: `boolean`):

Append a `_meta` block (run id, actor id, start/finish time, a non-sensitive input summary, and per-mode counts) to every output item, useful for auditing which run produced a record. Applies to all modes. Default: false.

## `ragOutput` (type: `boolean`):

Output embedding-ready documents ({id, text, metadata}) instead of raw records — ready for RAG pipelines and vector databases. Applies to all modes. Default: false.

## `ragChunkSize` (type: `integer`):

Split long text into chunks of about this many characters (0 = one document per item). Useful for embedding long transcripts. Applies when RAG Output is on. Default: 0 (no chunking).

## `ragChunkOverlap` (type: `integer`):

Character overlap between consecutive chunks. Applies when RAG Output is on and a chunk size is set. Default: 0.

## `country` (type: `string`):

Two-letter ISO country code used to localize YouTube results, e.g. "US", "DE", or "GB". Affects which results and trending content are returned. Applies to all modes. Default: "US". Also accepts the aliases `gl`, `geo`, and `region`.

## `hl` (type: `string`):

BCP-47 language code for the YouTube interface language, e.g. "en" or "de". Affects the label text in responses (such as category names). Applies to all modes. Default: "en". Also accepts the aliases `lang` and `language`.

## `translateMetadataTo` (type: `string`):

Language code (e.g. "es" or "ja") to also fetch each video's title and description in. Uses YouTube's own localization (creator-supplied or auto-translated; coverage varies per video and language) and adds `translatedTitle` / `translatedDescription` alongside the originals. Adds an extra request per video. Applies to Video mode. Default: blank (no translation).

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

Route requests through a proxy or your own proxy URLs. ⚠️ Transcripts, direct video-URL detail, and engagement counts (likes/comments/subscribers) need US residential IPs — choose the RESIDENTIAL group with country US here, or supply your own US residential-IP proxy URLs. Comments automatically use US residential IPs when needed (requires residential access on your Apify account; billed as platform usage). Search, Channel, and Trending modes work on the default proxy. Recommended for larger runs to spread requests across IP addresses. Applies to all modes. Default: proxy enabled. Also accepts the alias `proxy`.

## `incrementalMode` (type: `boolean`):

Track which items have been seen before. On subsequent runs with the same inputs, output only new and changed items (the rest are skipped). Applies to all modes. Default: false.

## `stateKey` (type: `string`):

Optional stable key identifying the incremental state to load and update, e.g. "my-tech-feed". Use the same key across runs to continue the same incremental feed. Applies when Incremental Mode is on. Default: blank (a key derived from the search inputs is used).

## `emitUnchanged` (type: `boolean`):

When Incremental Mode is on, also output records whose tracked content has not changed since the last run (marked `changeType: "UNCHANGED"`). By default unchanged items are skipped so each run returns only new and changed items. Tracked content is title, description, channel, category, and the Short flag for videos (counts such as views/likes do not count as a change). Default: false.

## `emitExpired` (type: `boolean`):

When Incremental Mode is on, output a small stub record (id plus `changeType: "EXPIRED"`) for items that have disappeared since the last run. Only applies to fully-covered single-channel or single-playlist scrapes, where a missing item is a reliable signal it was removed; broad searches and capped runs never emit EXPIRED. Expired stubs carry no scraped fields and are not billed as results. Default: false.

## `telegramToken` (type: `string`):

Telegram bot token from @BotFather. Required to send Telegram notifications when a run finishes. Default: blank (Telegram notifications off).

## `telegramChatId` (type: `string`):

Telegram chat or channel ID to send notifications to, e.g. "-100123456789". Required when Telegram Bot Token is set. Default: blank.

## `discordWebhookUrl` (type: `string`):

Discord incoming webhook URL to post a run-summary message to. Default: blank (Discord notifications off).

## `slackWebhookUrl` (type: `string`):

Slack incoming webhook URL to post a run-summary message to. Default: blank (Slack notifications off).

## `whatsappAccessToken` (type: `string`):

WhatsApp Cloud API permanent access token (a System User token from Meta Business). Required to send WhatsApp notifications. Default: blank (WhatsApp notifications off).

## `whatsappPhoneNumberId` (type: `string`):

Your WhatsApp Business phone-number ID (numeric, from the Meta dashboard). Required when WhatsApp Access Token is set. Default: blank.

## `whatsappTo` (type: `string`):

Recipient phone number in E.164 format without the leading +, e.g. "14155552671". Required when WhatsApp Access Token is set. Default: blank.

## `webhookUrl` (type: `string`):

URL that receives a JSON POST with { metadata, items } after each run. Works with n8n, Make, Zapier, or any custom backend. Default: blank (no webhook).

## `webhookHeaders` (type: `object`):

Optional JSON object of custom HTTP headers sent with the webhook, e.g. {"Authorization": "Bearer token"}. Applies when Webhook URL is set. Default: none.

## `notificationLimit` (type: `integer`):

Maximum number of items included in each notification message. Range 1–20. Applies when any notification channel is configured. Default: 5.

## `notifyOnlyChanges` (type: `boolean`):

When Incremental Mode is on, only send notifications for NEW and UPDATED items (skip unchanged ones). Applies when a notification channel is configured. Default: false.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "@MrBeast"
  ],
  "videoUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "dQw4w9WgXcQ"
  ],
  "channelUrls": [
    "https://www.youtube.com/@MrBeast",
    "@veritasium"
  ],
  "playlistUrls": [
    "https://www.youtube.com/playlist?list=PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf"
  ],
  "searchQueries": [
    "nodejs tutorial",
    "machine learning crash course"
  ],
  "scrapeVideos": true,
  "scrapeChannels": false,
  "scrapeComments": false,
  "scrapeTranscripts": false,
  "scrapeTrending": false,
  "sortBy": "relevance",
  "resultType": "video",
  "filterHd": false,
  "filterSubtitles": false,
  "filterCreativeCommons": false,
  "filterLive": false,
  "filter4k": false,
  "filter360": false,
  "filterHdr": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "channelVideoType": "videos",
  "channelSortOrder": "newest",
  "fetchAbout": true,
  "transcriptFormat": "segments",
  "preferAutoGenerated": false,
  "transcriptFields": [],
  "commentsPerVideo": 100,
  "commentsSort": "top",
  "includeReplies": false,
  "maxResults": 10,
  "includeShorts": true,
  "shortsOnly": false,
  "detailLevel": "standard",
  "descriptionFormat": "text",
  "excludeEmptyFields": false,
  "includeRunMetadata": false,
  "ragOutput": false,
  "ragChunkSize": 0,
  "ragChunkOverlap": 0,
  "country": "US",
  "hl": "en",
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "notificationLimit": 5,
  "notifyOnlyChanges": false
}
```

# Actor output Schema

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

No description

# 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 = {
    "searchQueries": [
        "nodejs tutorial"
    ],
    "scrapeTranscripts": false,
    "maxResults": 10,
    "ragOutput": false,
    "emitUnchanged": false,
    "emitExpired": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("blackfalcondata/youtube-data-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 = {
    "searchQueries": ["nodejs tutorial"],
    "scrapeTranscripts": False,
    "maxResults": 10,
    "ragOutput": False,
    "emitUnchanged": False,
    "emitExpired": False,
}

# Run the Actor and wait for it to finish
run = client.actor("blackfalcondata/youtube-data-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "nodejs tutorial"
  ],
  "scrapeTranscripts": false,
  "maxResults": 10,
  "ragOutput": false,
  "emitUnchanged": false,
  "emitExpired": false
}' |
apify call blackfalcondata/youtube-data-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=blackfalcondata/youtube-data-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "YouTube Scraper $2/1K — Videos, Channels, Comments, Transcripts",
        "description": "Scrape YouTube videos, channels, comments, and transcripts in one tool — by keyword or by video, channel, and playlist URL. Get rich per-video metadata, comments with replies, and translated transcripts. Incremental mode and RAG-ready output included.",
        "version": "0.1",
        "x-build-id": "VkgMNWpBfKTSmc3EH"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/blackfalcondata~youtube-data-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-blackfalcondata-youtube-data-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/blackfalcondata~youtube-data-scraper/runs": {
            "post": {
                "operationId": "runs-sync-blackfalcondata-youtube-data-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/blackfalcondata~youtube-data-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-blackfalcondata-youtube-data-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "startUrls": {
                        "title": "🔗 Start URLs",
                        "type": "array",
                        "description": "YouTube video, channel, or playlist URLs to scrape directly (one per line). Each entry is routed automatically by type and processed as its own task. You can also paste a bare 11-character video ID (e.g. \"dQw4w9WgXcQ\") or a bare @handle (e.g. \"@MrBeast\"). Merged with Video / Channel / Playlist URLs below. Used by all modes. Default: empty. Also accepts the aliases `url`, `urls`, and `startURLs` (and the typed lists `videoUrls` / `channelUrls` / `playlistUrls` below all merge in here).",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "videoUrls": {
                        "title": "Video URLs",
                        "type": "array",
                        "description": "Video URLs or bare 11-character video IDs (one per line), e.g. \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\" or \"dQw4w9WgXcQ\". Use this to paste a list of videos separately from channels and playlists. Merged with Start URLs. Feeds Video, Comments, and Transcripts modes. Default: empty. Also accepts the aliases `videoUrl`, `url`, and `urls`.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "channelUrls": {
                        "title": "Channel URLs",
                        "type": "array",
                        "description": "Channel URLs or bare @handles (one per line), e.g. \"https://www.youtube.com/@MrBeast\" or \"@veritasium\". Use this to paste a list of channels separately from videos and playlists. Merged with Start URLs. Feeds Video mode (channel uploads) and Channel mode (channel profiles). Default: empty. Also accepts the alias `channelUrl`.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "playlistUrls": {
                        "title": "Playlist URLs",
                        "type": "array",
                        "description": "Playlist URLs or bare playlist IDs (one per line), e.g. \"https://www.youtube.com/playlist?list=PLxxxx\" or \"PLxxxx\". Each playlist's videos are collected and tagged with their source `playlistId`. Merged with Start URLs. Feeds Video mode. Default: empty. Also accepts the alias `playlistUrl`.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "searchQueries": {
                        "title": "Search Queries",
                        "type": "array",
                        "description": "Keywords to search on YouTube (one per line), e.g. \"nodejs tutorial\". Each query runs as a separate search task and respects the Search Filters below. You can also paste several queries separated by commas. Required for the Trending mode (to define the topic to rank). Default: empty. Also accepts the aliases `query`, `q`, `keyword`, `keywords`, `searchQuery`, and `search`.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "scrapeVideos": {
                        "title": "Scrape Videos",
                        "type": "boolean",
                        "description": "Collect video items (metadata, stats, descriptions) from search results, channel pages, playlists, and pasted video URLs. This is the default mode. Default: true.",
                        "default": true
                    },
                    "scrapeChannels": {
                        "title": "Scrape Channels",
                        "type": "boolean",
                        "description": "Collect channel items (name, subscriber count, video count, country, links) from channel URLs/@handles or channel results in a search. Combine with Channel URLs or a search using Result Type = Channels only. Default: false.",
                        "default": false
                    },
                    "scrapeComments": {
                        "title": "Scrape Comments",
                        "type": "boolean",
                        "description": "Fetch comments for each scraped video. Requires a video target (search, channel, playlist, or pasted Video URL). Comments automatically use US residential IPs when needed (residential access required on your account). Tune volume/order in the Comments settings below. Default: false.",
                        "default": false
                    },
                    "scrapeTranscripts": {
                        "title": "Scrape Transcripts",
                        "type": "boolean",
                        "description": "Download full transcripts (captions) for each scraped video. Requires a video target. ⚠️ Needs US residential IPs (RESIDENTIAL group, country US) or transcripts come back empty; also runs slower (a browser step). Configure format, language, and translation in the Transcripts settings below. Default: false.",
                        "default": false
                    },
                    "scrapeTrending": {
                        "title": "Scrape Trending",
                        "type": "boolean",
                        "description": "Collect the most-viewed recent videos for your topic, ranked by view count over a recent upload window. Requires at least one Search Query, or a Trending Topic, to define what to rank. Default: false.",
                        "default": false
                    },
                    "trendingCategory": {
                        "title": "Trending Topic",
                        "type": "string",
                        "description": "Optional extra topic to rank when Scrape Trending is on, e.g. \"music\", \"gaming\", or \"movies\". Added alongside your search queries as a topic to find the most-viewed recent videos for. Applies to Trending mode. Default: blank (rank only your search queries)."
                    },
                    "sortBy": {
                        "title": "🔀 Sort By",
                        "enum": [
                            "relevance",
                            "date",
                            "viewCount",
                            "rating"
                        ],
                        "type": "string",
                        "description": "Order of search results. Applies to Search mode. Options: Relevance (YouTube's default ranking); Upload date (newest first); View count (most-viewed first); Rating (highest-rated first). Default: \"relevance\".",
                        "default": "relevance"
                    },
                    "uploadDate": {
                        "title": "Upload Date Filter",
                        "enum": [
                            "hour",
                            "today",
                            "week",
                            "month",
                            "year"
                        ],
                        "type": "string",
                        "description": "Restrict search results to videos uploaded within this window. Applies to Search mode. Options: Last hour; Today (last 24 hours); This week (last 7 days); This month (last 30 days); This year (last 365 days). Default: no restriction (any date)."
                    },
                    "videoDuration": {
                        "title": "Video Duration",
                        "enum": [
                            "short",
                            "medium",
                            "long"
                        ],
                        "type": "string",
                        "description": "Filter search results by video length. Applies to Search mode. Options: Short (under 4 minutes); Medium (4–20 minutes); Long (over 20 minutes). Default: no restriction (any length)."
                    },
                    "resultType": {
                        "title": "Result Type",
                        "enum": [
                            "video",
                            "channel",
                            "any"
                        ],
                        "type": "string",
                        "description": "Which kind of YouTube results a search should return. Applies to Search mode. Options: Videos only; Channels only (use together with Scrape Channels to find channels by keyword); Any (mixed results). To scrape a playlist, paste its playlist URL into Start URLs instead. Default: \"video\".",
                        "default": "video"
                    },
                    "filterHd": {
                        "title": "HD Only",
                        "type": "boolean",
                        "description": "Only return videos available in high definition. Applies to Search mode. Default: false.",
                        "default": false
                    },
                    "filterSubtitles": {
                        "title": "Has Subtitles/CC",
                        "type": "boolean",
                        "description": "Only return videos that have subtitles or closed captions. Useful as a pre-filter before transcript scraping. Applies to Search mode. Default: false.",
                        "default": false
                    },
                    "filterCreativeCommons": {
                        "title": "Creative Commons",
                        "type": "boolean",
                        "description": "Only return videos published under a Creative Commons license. Applies to Search mode. Default: false.",
                        "default": false
                    },
                    "filterLive": {
                        "title": "Live Only",
                        "type": "boolean",
                        "description": "Only return videos that are currently live. Applies to Search mode. Default: false.",
                        "default": false
                    },
                    "filter4k": {
                        "title": "4K Only",
                        "type": "boolean",
                        "description": "Only return videos available in 4K resolution. Applies to Search mode. Default: false.",
                        "default": false
                    },
                    "filter360": {
                        "title": "360° Only",
                        "type": "boolean",
                        "description": "Only return 360-degree videos. Applies to Search mode. Default: false.",
                        "default": false
                    },
                    "filterHdr": {
                        "title": "HDR Only",
                        "type": "boolean",
                        "description": "Only return videos available in HDR. Applies to Search mode. Default: false.",
                        "default": false
                    },
                    "includeKeywords": {
                        "title": "Include Keywords",
                        "type": "array",
                        "description": "Post-fetch filter: keep only results whose title or description contains at least one of these keywords (case-insensitive), e.g. [\"react\", \"vue\"]. Applies to all modes. Default: empty (no filtering).",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "excludeKeywords": {
                        "title": "Exclude Keywords",
                        "type": "array",
                        "description": "Post-fetch filter: drop results whose title or description contains any of these keywords (case-insensitive), e.g. [\"shorts\", \"reaction\"]. Applies to all modes. Default: empty (no filtering).",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "fromDate": {
                        "title": "From Date",
                        "type": "string",
                        "description": "Post-fetch filter: only include videos published on or after this date. Accepts an absolute ISO 8601 date (e.g. \"2024-01-01\") or a relative offset into the past (e.g. \"7d\", \"2 weeks\", \"3 months\", \"1 year\"). Applies to all modes. Default: no lower bound."
                    },
                    "toDate": {
                        "title": "To Date",
                        "type": "string",
                        "description": "Post-fetch filter: only include videos published on or before this date. Accepts an absolute ISO 8601 date (e.g. \"2024-12-31\") or a relative offset into the past (e.g. \"1d\"). Applies to all modes. Default: no upper bound."
                    },
                    "maxAgeDays": {
                        "title": "Max age (days)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Post-fetch filter: only include videos published within the last N days (e.g. 30). When combined with From Date, the more restrictive cutoff wins. Applies to all modes. Default: blank (no age limit)."
                    },
                    "customFilters": {
                        "title": "Custom Filters",
                        "type": "string",
                        "description": "Advanced post-fetch filter expression (DSL) evaluated against each output item, e.g. \"viewCount > 100000 AND durationSec < 600\". For power users; leave blank for no custom filtering. Applies to all modes. Note: enrichment-derived fields (category, keywords, hashtags, description) are only populated at detailLevel \"standard\" and above — filtering on one of these at detailLevel \"basic\" leaves it null and excludes every record. Default: blank."
                    },
                    "channelVideoType": {
                        "title": "Channel Video Type",
                        "enum": [
                            "videos",
                            "shorts",
                            "live"
                        ],
                        "type": "string",
                        "description": "Which tab to scrape when visiting a channel. Applies to Channel URLs in Video mode. Options: Regular videos (the Videos tab, long-form uploads); Shorts (the Shorts tab); Live streams (past and upcoming live broadcasts). Default: \"videos\".",
                        "default": "videos"
                    },
                    "channelSortOrder": {
                        "title": "Channel Sort Order",
                        "enum": [
                            "newest",
                            "oldest",
                            "popular"
                        ],
                        "type": "string",
                        "description": "Order of videos listed on a channel page. Applies to the Videos tab of Channel URLs in Video mode (sort is not available on the Shorts or Live tabs and is ignored there). Options: Newest first; Oldest first; Most popular (by view count). Default: \"newest\".",
                        "default": "newest"
                    },
                    "fetchAbout": {
                        "title": "Fetch Channel About Info",
                        "type": "boolean",
                        "description": "Fetch the channel About panel to fill in join date, country, total view count, and external links on channel items. Disable to skip the extra request for faster channel runs. Applies to Channel mode. Default: true.",
                        "default": true
                    },
                    "transcriptFormat": {
                        "title": "Transcript Format",
                        "enum": [
                            "segments",
                            "plaintext",
                            "srt",
                            "vtt",
                            "xml"
                        ],
                        "type": "string",
                        "description": "Output format for transcript data. Applies to Transcripts mode. Options: Timed segments (JSON array of { text, startMs, durationMs }); Plain text (one continuous string in `fullText`); SRT subtitles (numbered, timestamped subtitle blocks); WebVTT subtitles (web-standard caption format); Raw XML (the unprocessed caption document). All variants also include the plain `fullText`. Default: \"segments\".",
                        "default": "segments"
                    },
                    "transcriptLanguage": {
                        "title": "Transcript Language",
                        "type": "string",
                        "description": "BCP-47 language code for the desired transcript track, e.g. \"en\" or \"de\". Applies to Transcripts mode. Default: blank (use the video's default caption language)."
                    },
                    "translateTo": {
                        "title": "Translate Transcript To",
                        "type": "string",
                        "description": "BCP-47 language code to auto-translate the transcript into, e.g. \"en\" or \"es\". Applies to Transcripts mode. Default: blank (no translation)."
                    },
                    "preferAutoGenerated": {
                        "title": "Prefer Auto-Generated Transcripts",
                        "type": "boolean",
                        "description": "When both a manual and an auto-generated transcript exist for a video, prefer the auto-generated one. Applies to Transcripts mode. Default: false (prefer the manual transcript).",
                        "default": false
                    },
                    "transcriptFields": {
                        "title": "Transcript Fields to Include",
                        "type": "array",
                        "description": "Emit only this subset of transcript output fields, e.g. [\"fullText\", \"srt\"]. Applies to Transcripts mode. Default: empty (include all transcript fields).",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "commentsPerVideo": {
                        "title": "Comments (per video)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of comments to fetch per video. Set 0 for unlimited. Applies to Comments mode. Default: 100.",
                        "default": 100
                    },
                    "commentsSort": {
                        "title": "Comments Sort Order",
                        "enum": [
                            "top",
                            "new"
                        ],
                        "type": "string",
                        "description": "Comment retrieval order. Applies to Comments mode. Options: Top comments (YouTube's most-relevant ranking, usually most-liked first); Newest first (most recently posted). Default: \"top\".",
                        "default": "top"
                    },
                    "includeReplies": {
                        "title": "Include Replies",
                        "type": "boolean",
                        "description": "Also fetch replies to each top-level comment (nested under the comment's `replies` field). Increases run time and result volume. Applies to Comments mode. Default: false.",
                        "default": false
                    },
                    "maxResults": {
                        "title": "Max results (per run)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of videos and channels to collect across all tasks. Comments and transcripts are extra per-video records, not counted against this limit (set their volume with Comments per video / Scrape transcripts). Set 0 for unlimited. Default: 50. Aliases: `limit`, `max`, `maxItems`, `maxVideos`.",
                        "default": 50
                    },
                    "maxResultsPerQuery": {
                        "title": "💯 Max results (per query)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Cap on the number of videos and channels each individual search query or target (channel / playlist) may contribute, applied independently of Max Results (per run). Like Max Results, this caps videos and channels only — comments and transcripts are additional per-video records (controlled by Comments per video and Scrape transcripts) and are not counted against it. Useful for spreading a budget evenly across several queries. Default: blank (no per-query cap)."
                    },
                    "maxShorts": {
                        "title": "Max Shorts",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of Shorts (vertical, short-form clips) to include, applied independently of Max Results. Extra Shorts are dropped while regular videos are kept. Set 0 to exclude Shorts entirely. Applies to Video and Trending modes. Default: blank (no separate Shorts cap)."
                    },
                    "maxRunSeconds": {
                        "title": "Max run time (seconds)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Optional soft cap on how long the run may spend fetching, e.g. 300 for five minutes. When the run nears this limit it stops collecting new items and saves whatever it has gathered so far. Applies to all modes. Default: blank (no soft cap)."
                    },
                    "includeShorts": {
                        "title": "Include Shorts",
                        "type": "boolean",
                        "description": "Include YouTube Shorts (vertical, short-form clips) in video results. Turn off to keep only regular long-form videos. Applies to Video and Trending modes. Default: true.",
                        "default": true
                    },
                    "shortsOnly": {
                        "title": "Shorts Only",
                        "type": "boolean",
                        "description": "Return only YouTube Shorts and drop regular videos. Takes precedence over Include Shorts. Applies to Video and Trending modes. Default: false.",
                        "default": false
                    },
                    "detailLevel": {
                        "title": "Detail Level",
                        "enum": [
                            "basic",
                            "standard",
                            "detailed",
                            "complete"
                        ],
                        "type": "string",
                        "description": "How much metadata to fetch per video. Higher levels return more fields but may require an extra request per item (slower, higher cost). Applies to Video and Trending modes. Options: Basic (only the fields available from the listing — title, channel, view count, duration; no per-video request); Standard (adds video-page fields such as likes, full description, category, keywords); Detailed (adds extra metadata such as chapters, available captions, hashtags); Complete (every field the actor can extract). Default: \"standard\".",
                        "default": "standard"
                    },
                    "descriptionFormat": {
                        "title": "Description Format",
                        "enum": [
                            "text",
                            "html",
                            "markdown",
                            "all"
                        ],
                        "type": "string",
                        "description": "Output format for video and channel description text. Applies to Video and Channel modes. Options: Plain text (raw text in `descriptionText`); HTML (escaped, with <br> for newlines and <a> for links, in `descriptionHtml`); Markdown (line breaks preserved, URLs linkified, in `descriptionMarkdown`); All formats (every variant alongside the plain text). Default: \"text\".",
                        "default": "text"
                    },
                    "excludeEmptyFields": {
                        "title": "Exclude Empty Fields",
                        "type": "boolean",
                        "description": "Strip null and empty fields from output items to reduce dataset size and make records easier to read. Applies to all modes. Default: false.",
                        "default": false
                    },
                    "includeRunMetadata": {
                        "title": "📣 Include Run Metadata",
                        "type": "boolean",
                        "description": "Append a `_meta` block (run id, actor id, start/finish time, a non-sensitive input summary, and per-mode counts) to every output item, useful for auditing which run produced a record. Applies to all modes. Default: false.",
                        "default": false
                    },
                    "ragOutput": {
                        "title": "RAG Output (embedding-ready)",
                        "type": "boolean",
                        "description": "Output embedding-ready documents ({id, text, metadata}) instead of raw records — ready for RAG pipelines and vector databases. Applies to all modes. Default: false.",
                        "default": false
                    },
                    "ragChunkSize": {
                        "title": "RAG Chunk Size (characters)",
                        "minimum": 0,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Split long text into chunks of about this many characters (0 = one document per item). Useful for embedding long transcripts. Applies when RAG Output is on. Default: 0 (no chunking).",
                        "default": 0
                    },
                    "ragChunkOverlap": {
                        "title": "RAG Chunk Overlap (characters)",
                        "minimum": 0,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "Character overlap between consecutive chunks. Applies when RAG Output is on and a chunk size is set. Default: 0.",
                        "default": 0
                    },
                    "country": {
                        "title": "🌍 Country (2-letter code)",
                        "type": "string",
                        "description": "Two-letter ISO country code used to localize YouTube results, e.g. \"US\", \"DE\", or \"GB\". Affects which results and trending content are returned. Applies to all modes. Default: \"US\". Also accepts the aliases `gl`, `geo`, and `region`.",
                        "default": "US"
                    },
                    "hl": {
                        "title": "UI Language",
                        "type": "string",
                        "description": "BCP-47 language code for the YouTube interface language, e.g. \"en\" or \"de\". Affects the label text in responses (such as category names). Applies to all modes. Default: \"en\". Also accepts the aliases `lang` and `language`.",
                        "default": "en"
                    },
                    "translateMetadataTo": {
                        "title": "Translate Title/Description To",
                        "type": "string",
                        "description": "Language code (e.g. \"es\" or \"ja\") to also fetch each video's title and description in. Uses YouTube's own localization (creator-supplied or auto-translated; coverage varies per video and language) and adds `translatedTitle` / `translatedDescription` alongside the originals. Adds an extra request per video. Applies to Video mode. Default: blank (no translation)."
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Route requests through a proxy or your own proxy URLs. ⚠️ Transcripts, direct video-URL detail, and engagement counts (likes/comments/subscribers) need US residential IPs — choose the RESIDENTIAL group with country US here, or supply your own US residential-IP proxy URLs. Comments automatically use US residential IPs when needed (requires residential access on your Apify account; billed as platform usage). Search, Channel, and Trending modes work on the default proxy. Recommended for larger runs to spread requests across IP addresses. Applies to all modes. Default: proxy enabled. Also accepts the alias `proxy`.",
                        "default": {
                            "useApifyProxy": true
                        }
                    },
                    "incrementalMode": {
                        "title": "Incremental Mode",
                        "type": "boolean",
                        "description": "Track which items have been seen before. On subsequent runs with the same inputs, output only new and changed items (the rest are skipped). Applies to all modes. Default: false.",
                        "default": false
                    },
                    "stateKey": {
                        "title": "State Key",
                        "type": "string",
                        "description": "Optional stable key identifying the incremental state to load and update, e.g. \"my-tech-feed\". Use the same key across runs to continue the same incremental feed. Applies when Incremental Mode is on. Default: blank (a key derived from the search inputs is used)."
                    },
                    "emitUnchanged": {
                        "title": "Emit Unchanged Items",
                        "type": "boolean",
                        "description": "When Incremental Mode is on, also output records whose tracked content has not changed since the last run (marked `changeType: \"UNCHANGED\"`). By default unchanged items are skipped so each run returns only new and changed items. Tracked content is title, description, channel, category, and the Short flag for videos (counts such as views/likes do not count as a change). Default: false.",
                        "default": false
                    },
                    "emitExpired": {
                        "title": "Emit Expired Items",
                        "type": "boolean",
                        "description": "When Incremental Mode is on, output a small stub record (id plus `changeType: \"EXPIRED\"`) for items that have disappeared since the last run. Only applies to fully-covered single-channel or single-playlist scrapes, where a missing item is a reliable signal it was removed; broad searches and capped runs never emit EXPIRED. Expired stubs carry no scraped fields and are not billed as results. Default: false.",
                        "default": false
                    },
                    "telegramToken": {
                        "title": "Telegram Bot Token",
                        "type": "string",
                        "description": "Telegram bot token from @BotFather. Required to send Telegram notifications when a run finishes. Default: blank (Telegram notifications off)."
                    },
                    "telegramChatId": {
                        "title": "💬 Telegram Chat ID",
                        "type": "string",
                        "description": "Telegram chat or channel ID to send notifications to, e.g. \"-100123456789\". Required when Telegram Bot Token is set. Default: blank."
                    },
                    "discordWebhookUrl": {
                        "title": "Discord Webhook URL",
                        "type": "string",
                        "description": "Discord incoming webhook URL to post a run-summary message to. Default: blank (Discord notifications off)."
                    },
                    "slackWebhookUrl": {
                        "title": "Slack Webhook URL",
                        "type": "string",
                        "description": "Slack incoming webhook URL to post a run-summary message to. Default: blank (Slack notifications off)."
                    },
                    "whatsappAccessToken": {
                        "title": "WhatsApp Access Token",
                        "type": "string",
                        "description": "WhatsApp Cloud API permanent access token (a System User token from Meta Business). Required to send WhatsApp notifications. Default: blank (WhatsApp notifications off)."
                    },
                    "whatsappPhoneNumberId": {
                        "title": "WhatsApp Phone Number ID",
                        "type": "string",
                        "description": "Your WhatsApp Business phone-number ID (numeric, from the Meta dashboard). Required when WhatsApp Access Token is set. Default: blank."
                    },
                    "whatsappTo": {
                        "title": "WhatsApp Recipient",
                        "type": "string",
                        "description": "Recipient phone number in E.164 format without the leading +, e.g. \"14155552671\". Required when WhatsApp Access Token is set. Default: blank."
                    },
                    "webhookUrl": {
                        "title": "Webhook URL",
                        "type": "string",
                        "description": "URL that receives a JSON POST with { metadata, items } after each run. Works with n8n, Make, Zapier, or any custom backend. Default: blank (no webhook)."
                    },
                    "webhookHeaders": {
                        "title": "Webhook Headers",
                        "type": "object",
                        "description": "Optional JSON object of custom HTTP headers sent with the webhook, e.g. {\"Authorization\": \"Bearer token\"}. Applies when Webhook URL is set. Default: none."
                    },
                    "notificationLimit": {
                        "title": "Max Items Per Notification",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Maximum number of items included in each notification message. Range 1–20. Applies when any notification channel is configured. Default: 5.",
                        "default": 5
                    },
                    "notifyOnlyChanges": {
                        "title": "Notify Only New/Updated",
                        "type": "boolean",
                        "description": "When Incremental Mode is on, only send notifications for NEW and UPDATED items (skip unchanged ones). Applies when a notification channel is configured. Default: false.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
