# YouTube Scraper (`vortex_data/youtube-scraper`) Actor

⚡ Every YouTube field in one Actor — videos, channels, playlists, search, Shorts, comments, subtitles, hashtags — at 200+ videos/sec. Chrome TLS fingerprint, rotating residential IPs, full channel metadata on every row. Zero blocks, zero CAPTCHAs.

- **URL**: https://apify.com/vortex\_data/youtube-scraper.md
- **Developed by:** [VortexData](https://apify.com/vortex_data) (community)
- **Categories:** Videos, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 video (listing only)s

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## 📺 YouTube Scraper — fast, complete, residential-grade

> Scrape **videos, channels, playlists, search results, Shorts, live streams** and **comments** from YouTube — at residential-proxy speed with a Chrome TLS fingerprint.

### ✨ Why this scraper

- **Complete data.** Returns the full set: video metadata, channel `/about` metadata duplicated on every channel item, parsed `descriptionLinks`, `hashtags`, `commentsCount`, `isMonetized`, full `thumbnails` array, captions metadata, `streamingData` (opt-in), plus inline comments and subtitles.
- **Fast.** ~85 videos/s from a channel, ~210 videos/s from a playlist, 50 watch records in parallel without throttling — benchmarked live.
- **Anti-detection by default.** `curl_cffi` with `impersonate="chrome"` (real Chrome TLS/JA3 fingerprint) and a **fresh Apify Residential session ID per HTTP request** — every outbound call uses a different residential IP.
- **PoToken-proof subtitles.** Automatically falls back to YouTube's iOS player API when the WEB caption baseUrl is empty (post-PoToken rollout), so subtitles actually download.
- **Channel `/about` enrichment.** Every channel item carries `channelDescription`, `channelDescriptionLinks`, `channelJoinedDate`, `channelLocation`, `channelTotalVideos`, `channelTotalViews`, `numberOfSubscribers`, `inputChannelUrl`.
- **Comments inline.** Walked through `/youtubei/v1/next` continuation — no separate actor needed.
- **Parallel everywhere.** Multiple source URLs scrape concurrently. `/about` and tab listings on a channel fetch in parallel.

### 🚀 Quick start

1. Paste a YouTube link (video, channel, playlist, search, Shorts) into **Start URLs** — *or* type keywords into **Search Queries** — *or* drop channel handles (`@MrBeast`) into **YouTube Handles**.
2. Click **Start**.
3. Download results from the **Dataset** tab in JSON, CSV, Excel, XML or HTML.

The default settings already have a sample video URL pre-filled, so a one-click run returns one full video record immediately.

### 🎯 What you can scrape

| Source URL | What you get |
|---|---|
| `https://www.youtube.com/watch?v=...` | Single video: title, description, **likes, views, commentsCount**, channel info, **subscribers**, hashtags, `descriptionLinks`, full thumbnails array, dates, captions metadata, isLive / isMonetized / isFamilySafe, optional `streamingData` |
| `https://www.youtube.com/shorts/...` | Same shape as a normal video |
| `https://www.youtube.com/@handle` or `/c/Name` or `/channel/UC...` | Channel **/about** metadata + every requested tab (videos / shorts / streams), each item enriched with channel-level fields |
| `https://www.youtube.com/playlist?list=...` | Playlist videos with `channelName`, `channelUrl`, `viewCount`, relative date, thumbnail |
| `https://www.youtube.com/results?search_query=...` | Search results with full listing-level fields |
| `https://www.youtube.com/hashtag/...` | Hashtag feed |
| **Search Queries input** | Same as above, plus you can pick sort order / date / 4K / HD / CC / Live / etc. |

### ⚙️ Input examples

#### Scrape one video, including subtitles & comments

```json
{
  "startUrls": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "downloadSubtitles": true,
  "subtitlesLanguage": "en",
  "subtitlesFormat": "srt",
  "downloadComments": true,
  "maxComments": 200
}
````

#### Scrape an entire channel (videos + shorts + streams)

```json
{
  "youtubeHandles": ["@MrBeast"],
  "maxResults": 200,
  "maxResultsShorts": 50,
  "maxResultStreams": 10,
  "sortVideosBy": "POPULAR"
}
```

#### Search with filters (HD videos uploaded this week, sorted by views)

```json
{
  "searchQueries": ["climate change"],
  "maxResults": 100,
  "sortingOrder": "views",
  "dateFilter": "week",
  "isHD": true
}
```

#### Multi-source batch, with a global cap

```json
{
  "startUrls": [
    "https://www.youtube.com/playlist?list=PL...",
    "https://www.youtube.com/@apify/videos",
    "https://www.youtube.com/results?search_query=apify"
  ],
  "maxResults": 50,
  "maxItems": 500,
  "concurrency": 8
}
```

### 📤 Output example

```json
{
  "type": "video",
  "id": "wwSzpaTHyS8",
  "title": "Did The Future Already Happen? - The Paradox of Time",
  "url": "https://www.youtube.com/watch?v=wwSzpaTHyS8",

  "description": "Go to https://brilliant.org/nutshell/ to dive deeper...",
  "descriptionLinks": [
    { "text": "https://brilliant.org/nutshell/", "url": "https://brilliant.org/nutshell/" }
  ],
  "hashtags": ["#science"],
  "keywords": ["physics", "time"],
  "category": "Education",

  "views": 14613126,
  "likes": 461357,
  "commentsCount": 18432,
  "commentsTurnedOff": false,

  "date": "2024-01-30",
  "publishDate": "Jan 30, 2024",
  "uploadDate": "Jan 30, 2024",
  "duration": "00:12:35",
  "durationSeconds": 755,

  "thumbnailUrl": "https://i.ytimg.com/vi/wwSzpaTHyS8/maxresdefault.jpg",
  "thumbnails": [
    { "url": "...hqdefault.jpg", "width": 168, "height": 94 },
    { "url": "...maxresdefault.jpg", "width": 1920, "height": 1080 }
  ],
  "embedUrl": "https://www.youtube.com/embed/wwSzpaTHyS8",

  "channel": {
    "id": "UCsXVk37bltHxD1rDPwtNM8Q",
    "name": "Kurzgesagt – In a Nutshell",
    "url": "https://www.youtube.com/@kurzgesagt"
  },
  "numberOfSubscribers": 22500000,

  "isLive": false,
  "isPrivate": false,
  "isUnlisted": false,
  "isFamilySafe": true,
  "isMonetized": true,
  "playabilityStatus": "OK",
  "availableCountries": ["US", "GB", "DE", "..."],

  "captions": {
    "captionTracks": [
      { "base_url": "...", "language_code": "en", "kind": null }
    ]
  },

  "subtitles": [
    { "type": "manual", "language": "en", "format": "srt", "content": "1\n00:00:02,440 --> 00:00:09,520\nDo your past..." }
  ],

  "comments": [
    {
      "id": "Ug...",
      "author": "@kelving420",
      "text": "The fact they can use all of these trademarked characters...",
      "likeCount": 16,
      "replyCount": 16,
      "publishedTime": "3 weeks ago"
    }
  ],

  "fromYTUrl": "https://www.youtube.com/watch?v=wwSzpaTHyS8",
  "status": "OK"
}
```

When scraping a **channel**, each item additionally carries:

```json
"channelDescription": "...",
"channelDescriptionLinks": [{"text": "...", "url": "https://..."}],
"channelJoinedDate": "Feb 1, 2015",
"channelLocation": "United Kingdom",
"channelTotalVideos": 418,
"channelTotalViews": "2,473,486,020",
"inputChannelUrl": "https://www.youtube.com/@RickAstleyYT/about"
```

### ⚡ Performance (live benchmark)

| Workload | Items | Time | Rate |
|---|---|---|---|
| Channel videos (with continuation) | 100 | 1.17s | **85 vid/s** |
| Playlist (with continuation) | 100 | 0.47s | **210 vid/s** |
| Search results (with continuation) | 100 | 1.49s | 41 vid/s |
| 3 listings in parallel | 180 | 1.07s | 167 vid/s |
| 8 channels × 200 videos in parallel | 1294 | 2.0s | **656 vid/s** |
| 500 comments via `/next` continuation | 500 | 3.3s | 150 com/s |
| Single full `/watch` record | 1 | 0.81s | — |

### 🧰 Advanced options

- **`includeStreamingData`** — attach raw `playerResponse.streamingData` (mp4 formats, adaptive formats, URLs). Off by default because most format URLs are signature-protected and the payload is large.
- **`saveSubsToKVS`** — write subtitles to the key-value store, keep the dataset record slim.
- **`concurrency`** — number of in-flight HTTP requests. Default 5; the actor is happy at 16+.
- **`maxItems`** — global cross-source cap (e.g. set 1000 to stop the run after 1000 items regardless of how many start URLs).
- **`sortVideosBy`** — channel-tab sort: `NEWEST`, `POPULAR`, `OLDEST`.

### 🌍 Country / language (`gl` / `hl`)

YouTube respects the `gl=US` / `hl=en` URL parameters for results localization. The actor threads them through to:

- Every HTML fetch (appended as query parameters)
- The `Accept-Language` header
- The Innertube `context.client.gl` / `hl` for `/browse`, `/search`, `/next`, `/player` continuation calls
- **The residential proxy's country routing** — picking `gl=de` means traffic exits from a German residential IP and you get German-localized results.

### ❓ FAQ

**Why is `getTrending` returning nothing?**
YouTube removed the public Trending feed for unauthenticated visitors in 2024 — `/feed/trending` now serves a "Try searching to get started" placeholder. As a workaround, use `searchQueries` with `"sortingOrder": "views"` and `"dateFilter": "today"`.

**Why is `streamingData` empty in my output?**
It's off by default — flip `includeStreamingData: true`. Note that for most popular videos the playback URLs inside are signature-ciphered and need a JS decipher step (see `signatureCipher` vs `url` keys).

**Why are some subtitle tracks missing for a video?**
Either the video has no captions, or YouTube returned an empty body for the WEB caption URL (post-PoToken rollout). The actor auto-falls back to the iOS-client player, which fixes the vast majority of cases.

**Why `location: null`?**
The video's uploader didn't tag a location. The field exists on YT's microformat but is rarely populated.

**Can I scrape dislikes?**
No — YouTube made dislike counts non-public in 2021.

**What's `isMonetized` based on?**
The actor checks `playerResponse.adPlacements` and `playerResponse.playerAds`. If either is non-empty, the video runs ads and is monetized.

### 📞 Support

Open an issue on the **Issues** tab with a sample input that reproduces the problem. We aim to respond same-day for blockers.

# Actor input Schema

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

Any YouTube URL: video, channel, playlist, search results, Shorts, hashtag. Paste many — they are scraped in parallel.

## `youtubeHandles` (type: `array`):

Channel handles like @MrBeast or @apify. Automatically resolved to channel URLs.

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

Words to type into the YouTube search bar. Filters from the section below are applied to every query.

## `getTrending` (type: `boolean`):

⚠️ YouTube no longer exposes /feed/trending to unauthenticated visitors in most regions. As a workaround, search with sort=views and date=today.

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

Cap on the number of regular videos to fetch per channel / search / playlist URL. For a single video URL this is ignored.

## `maxResultsShorts` (type: `integer`):

Only applies when scraping a channel URL — sets the cap on the /shorts tab.

## `maxResultStreams` (type: `integer`):

Only applies when scraping a channel URL — sets the cap on the /streams tab.

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

Shortcut. When ON and `Maximum Shorts per channel` is 0, we copy the regular-videos cap onto Shorts.

## `maxItems` (type: `integer`):

Hard cross-source ceiling on the dataset size. 0 means unlimited.

## `sortVideosBy` (type: `string`):

Sort buttons on a channel's Videos / Shorts / Streams tabs.

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

Only applies when scraping search keywords / a /results URL.

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

Restrict search results to videos uploaded within this window.

## `videoType` (type: `string`):

Limit results to regular videos or full-length movies.

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

Limit results to videos shorter or longer than the given bucket.

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

Match only videos available in HD (720p or higher).

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

Match only videos available in 4K (2160p).

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

Match only videos available in HDR.

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

Match only stereoscopic 3D videos.

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

Match only 360° videos.

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

Match only VR180 videos.

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

Match only live streams.

## `hasSubtitles` (type: `boolean`):

Match only videos that have subtitles / CC available.

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

Match only videos uploaded under a Creative Commons licence.

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

Match only videos that have a geographic location tagged.

## `isBought` (type: `boolean`):

Match only videos that have been purchased by the YouTube user.

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

Fetch subtitles for every scraped video. ⚠️ This triggers a per-video /watch fetch even on search/channel sources.

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

Two-letter language code (en, ru, de, …). Use `any` to grab whatever's available.

## `preferAutoGeneratedSubtitles` (type: `boolean`):

Pick the ASR (auto-generated) track over manually uploaded subtitles when both exist.

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

How subtitles should be encoded in the dataset.

## `saveSubsToKVS` (type: `boolean`):

Instead of embedding the SRT in the dataset, write it to the run's key-value store and keep a `keyValueStoreKey` reference. Useful for very long videos.

## `downloadComments` (type: `boolean`):

Walk the /youtubei/v1/next continuation chain. Triggers a /watch fetch even on listing-only sources.

## `maxComments` (type: `integer`):

Maximum number of comments to scrape per video. Only used when `Scrape comments` is enabled.

## `gl` (type: `string`):

Two-letter country code (us, gb, de, ru, …). Affects which results YouTube returns AND which residential-proxy country we route through.

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

Two-letter language code (en, ru, de, …). Drives YouTube interface texts and the `Accept-Language` header.

## `includeStreamingData` (type: `boolean`):

Attach the raw `playerResponse.streamingData` block. ⚠️ Off by default because the payload can be 100s of KB per video, and most format URLs are signature-protected (you still need to run a JS decipher).

## `concurrency` (type: `integer`):

How many HTTP requests run in parallel. The actor scales well up to ~16; defaults to 5 for proxy-friendliness.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    }
  ],
  "youtubeHandles": [],
  "searchQueries": [],
  "getTrending": false,
  "maxResults": 10,
  "maxResultsShorts": 0,
  "maxResultStreams": 0,
  "includeShorts": false,
  "maxItems": 0,
  "sortVideosBy": "NEWEST",
  "isHD": false,
  "is4K": false,
  "isHDR": false,
  "is3D": false,
  "is360": false,
  "isVR180": false,
  "isLive": false,
  "hasSubtitles": false,
  "hasCC": false,
  "hasLocation": false,
  "isBought": false,
  "downloadSubtitles": false,
  "subtitlesLanguage": "en",
  "preferAutoGeneratedSubtitles": false,
  "subtitlesFormat": "srt",
  "saveSubsToKVS": false,
  "downloadComments": false,
  "maxComments": 100,
  "gl": "us",
  "hl": "en",
  "includeStreamingData": false,
  "concurrency": 5
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

All scraped items.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
        }
    ]
};

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

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

# Prepare the Actor input
run_input = { "startUrls": [{ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }] }

# Run the Actor and wait for it to finish
run = client.actor("vortex_data/youtube-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 '{
  "startUrls": [
    {
      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    }
  ]
}' |
apify call vortex_data/youtube-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "YouTube Scraper",
        "description": "⚡ Every YouTube field in one Actor — videos, channels, playlists, search, Shorts, comments, subtitles, hashtags — at 200+ videos/sec. Chrome TLS fingerprint, rotating residential IPs, full channel metadata on every row. Zero blocks, zero CAPTCHAs.",
        "version": "0.1",
        "x-build-id": "l5DaReHew5dctlNTy"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/vortex_data~youtube-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-vortex_data-youtube-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/vortex_data~youtube-scraper/runs": {
            "post": {
                "operationId": "runs-sync-vortex_data-youtube-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/vortex_data~youtube-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-vortex_data-youtube-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": "Any YouTube URL: video, channel, playlist, search results, Shorts, hashtag. Paste many — they are scraped in parallel.",
                        "default": [
                            {
                                "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
                            }
                        ],
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "youtubeHandles": {
                        "title": "YouTube handles",
                        "type": "array",
                        "description": "Channel handles like @MrBeast or @apify. Automatically resolved to channel URLs.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "searchQueries": {
                        "title": "Search queries",
                        "type": "array",
                        "description": "Words to type into the YouTube search bar. Filters from the section below are applied to every query.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "getTrending": {
                        "title": "Get Trending feed",
                        "type": "boolean",
                        "description": "⚠️ YouTube no longer exposes /feed/trending to unauthenticated visitors in most regions. As a workaround, search with sort=views and date=today.",
                        "default": false
                    },
                    "maxResults": {
                        "title": "Maximum videos per source",
                        "minimum": 0,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Cap on the number of regular videos to fetch per channel / search / playlist URL. For a single video URL this is ignored.",
                        "default": 10
                    },
                    "maxResultsShorts": {
                        "title": "Maximum Shorts per channel",
                        "minimum": 0,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Only applies when scraping a channel URL — sets the cap on the /shorts tab.",
                        "default": 0
                    },
                    "maxResultStreams": {
                        "title": "Maximum streams per channel",
                        "minimum": 0,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Only applies when scraping a channel URL — sets the cap on the /streams tab.",
                        "default": 0
                    },
                    "includeShorts": {
                        "title": "Include Shorts on a channel scrape",
                        "type": "boolean",
                        "description": "Shortcut. When ON and `Maximum Shorts per channel` is 0, we copy the regular-videos cap onto Shorts.",
                        "default": false
                    },
                    "maxItems": {
                        "title": "Maximum total items (global cap)",
                        "minimum": 0,
                        "maximum": 1000000,
                        "type": "integer",
                        "description": "Hard cross-source ceiling on the dataset size. 0 means unlimited.",
                        "default": 0
                    },
                    "sortVideosBy": {
                        "title": "Channel tab sort",
                        "enum": [
                            "NEWEST",
                            "POPULAR",
                            "OLDEST"
                        ],
                        "type": "string",
                        "description": "Sort buttons on a channel's Videos / Shorts / Streams tabs.",
                        "default": "NEWEST"
                    },
                    "sortingOrder": {
                        "title": "Sort search results by",
                        "enum": [
                            "relevance",
                            "rating",
                            "date",
                            "views"
                        ],
                        "type": "string",
                        "description": "Only applies when scraping search keywords / a /results URL."
                    },
                    "dateFilter": {
                        "title": "Upload date",
                        "enum": [
                            "hour",
                            "today",
                            "week",
                            "month",
                            "year"
                        ],
                        "type": "string",
                        "description": "Restrict search results to videos uploaded within this window."
                    },
                    "videoType": {
                        "title": "Type",
                        "enum": [
                            "video",
                            "movie"
                        ],
                        "type": "string",
                        "description": "Limit results to regular videos or full-length movies."
                    },
                    "lengthFilter": {
                        "title": "Duration",
                        "enum": [
                            "under4",
                            "between420",
                            "plus20"
                        ],
                        "type": "string",
                        "description": "Limit results to videos shorter or longer than the given bucket."
                    },
                    "isHD": {
                        "title": "Only HD",
                        "type": "boolean",
                        "description": "Match only videos available in HD (720p or higher).",
                        "default": false
                    },
                    "is4K": {
                        "title": "Only 4K",
                        "type": "boolean",
                        "description": "Match only videos available in 4K (2160p).",
                        "default": false
                    },
                    "isHDR": {
                        "title": "Only HDR",
                        "type": "boolean",
                        "description": "Match only videos available in HDR.",
                        "default": false
                    },
                    "is3D": {
                        "title": "Only 3D",
                        "type": "boolean",
                        "description": "Match only stereoscopic 3D videos.",
                        "default": false
                    },
                    "is360": {
                        "title": "Only 360°",
                        "type": "boolean",
                        "description": "Match only 360° videos.",
                        "default": false
                    },
                    "isVR180": {
                        "title": "Only VR180",
                        "type": "boolean",
                        "description": "Match only VR180 videos.",
                        "default": false
                    },
                    "isLive": {
                        "title": "Only Live",
                        "type": "boolean",
                        "description": "Match only live streams.",
                        "default": false
                    },
                    "hasSubtitles": {
                        "title": "Only with subtitles",
                        "type": "boolean",
                        "description": "Match only videos that have subtitles / CC available.",
                        "default": false
                    },
                    "hasCC": {
                        "title": "Only Creative Commons",
                        "type": "boolean",
                        "description": "Match only videos uploaded under a Creative Commons licence.",
                        "default": false
                    },
                    "hasLocation": {
                        "title": "Only with location tag",
                        "type": "boolean",
                        "description": "Match only videos that have a geographic location tagged.",
                        "default": false
                    },
                    "isBought": {
                        "title": "Only purchased",
                        "type": "boolean",
                        "description": "Match only videos that have been purchased by the YouTube user.",
                        "default": false
                    },
                    "downloadSubtitles": {
                        "title": "Download subtitles",
                        "type": "boolean",
                        "description": "Fetch subtitles for every scraped video. ⚠️ This triggers a per-video /watch fetch even on search/channel sources.",
                        "default": false
                    },
                    "subtitlesLanguage": {
                        "title": "Preferred subtitles language",
                        "type": "string",
                        "description": "Two-letter language code (en, ru, de, …). Use `any` to grab whatever's available.",
                        "default": "en"
                    },
                    "preferAutoGeneratedSubtitles": {
                        "title": "Prefer auto-generated tracks",
                        "type": "boolean",
                        "description": "Pick the ASR (auto-generated) track over manually uploaded subtitles when both exist.",
                        "default": false
                    },
                    "subtitlesFormat": {
                        "title": "Output format",
                        "enum": [
                            "srt",
                            "vtt",
                            "xml",
                            "plaintext"
                        ],
                        "type": "string",
                        "description": "How subtitles should be encoded in the dataset.",
                        "default": "srt"
                    },
                    "saveSubsToKVS": {
                        "title": "Save subtitles to key-value store",
                        "type": "boolean",
                        "description": "Instead of embedding the SRT in the dataset, write it to the run's key-value store and keep a `keyValueStoreKey` reference. Useful for very long videos.",
                        "default": false
                    },
                    "downloadComments": {
                        "title": "Scrape comments",
                        "type": "boolean",
                        "description": "Walk the /youtubei/v1/next continuation chain. Triggers a /watch fetch even on listing-only sources.",
                        "default": false
                    },
                    "maxComments": {
                        "title": "Comments per video",
                        "minimum": 0,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Maximum number of comments to scrape per video. Only used when `Scrape comments` is enabled.",
                        "default": 100
                    },
                    "gl": {
                        "title": "Country",
                        "type": "string",
                        "description": "Two-letter country code (us, gb, de, ru, …). Affects which results YouTube returns AND which residential-proxy country we route through.",
                        "default": "us"
                    },
                    "hl": {
                        "title": "Interface language",
                        "type": "string",
                        "description": "Two-letter language code (en, ru, de, …). Drives YouTube interface texts and the `Accept-Language` header.",
                        "default": "en"
                    },
                    "includeStreamingData": {
                        "title": "Include streamingData (mp4 / adaptive formats)",
                        "type": "boolean",
                        "description": "Attach the raw `playerResponse.streamingData` block. ⚠️ Off by default because the payload can be 100s of KB per video, and most format URLs are signature-protected (you still need to run a JS decipher).",
                        "default": false
                    },
                    "concurrency": {
                        "title": "Concurrent requests",
                        "minimum": 1,
                        "maximum": 32,
                        "type": "integer",
                        "description": "How many HTTP requests run in parallel. The actor scales well up to ~16; defaults to 5 for proxy-friendliness.",
                        "default": 5
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
