# YouTube Ultimate Scraper (`ultimate/youtube-scraper`)

Scrape videos, comments, replies, transcripts, and channel metadata with YouTube Ultimate Scraper. Designed for flexibility, speed, and reliability, it’s perfect for everything from one-off research to large-scale automation.

- **URL**: https://beta-securitybyobscurity.apify.com/ultimate/youtube-scraper.md
- **Developed by:** [Ultimate Insight](https://beta-securitybyobscurity.apify.com/ultimate) (community)
- **Categories:** Videos, Social media, Automation
- **Stats:** 34 total users, 29 monthly users, 100.0% runs succeeded, 3 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

Pay per event

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

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

# README

![Banner Image](https://i.imgur.com/xPLGvs1.png)
[![Onboarding Service](https://i.imgur.com/WzUFVH2.png)](#support-and-onboarding-service)

<br><br>

### 🧭 How it Works

*YouTube Ultimate Scraper* is built for flexibility and optimized for cost efficiency. Whether you're targeting a few specific videos or extracting large volumes of content across multiple discovery paths, the scraper gives you full control over how content is selected, processed, and returned.

#### Many Ways to Crawl & Scrape YouTube

You can launch a scraping run using a variety of input types, depending on your goals:

- Use a mixed list of YouTube URLs, including videos, channels, hashtags, and searches,  as your crawl/scrape targets. The scraper will automatically infer what you want from the URLs.
- Provide an explicit list of video, short, or livestream IDs to scrape them directly.
- Crawl one or more channels (using channel IDs or @handles) to discover and scrape their video content.
- Submit a list of hashtags to crawl videos tagged with those terms.
- Define one or more global search queries to discover relevant video results across YouTube.
- Include a 'skip list' of video IDs to ignore, enabling you to scrape the same source multiple times and always get just the freshest content.

#### Just the Results You Need

Once your crawl targets are defined, you can specify exactly which types and format of data you want to collect:

- For channel crawls, choose whether to include videos, shorts, livestreams, or any combination.
- Enable or disable video comments, and optionally include their replies.
- Enable video transcripts, with support for multiple language variants where available.
- Include extended channel metadata for each scraped video, if desired.

#### Sensible Value-based Pricing

Thanks to Apify's Pay-per-Event (PPE) pricing model, you'll never be billed for platform fees or other unexpected running costs; just pay for the YouTube data that you actually receive.

- Pay a fixed rate for each result delivered (with per item add-on charges if you choose to activate optional content, like comments, transcripts or channel metadata).
- Set precise limits for the number of results returned per channel, hashtag, or search.
- Set similar limits on individual add-on items, such as the number of comments per video or replies per comment.

Please refer to [our pricing](https://apify.com/ultimate/youtube-scraper/pricing) for full details of the charges that may be raised during a scraping run. Note that we participate in Apify's tiered pricing scheme, which means that you'll get progressively larger discounts on all our charges, according to your Apify subscription level. <br><br>

### 💡 Some Typical Use Cases

YouTube is full of valuable insights - you just need the right tools to extract them. Below are five of our favorite real-world examples, showing how scraping can help creators, marketers, and analysts turn YouTube data into actionable results.

#### YouTube Content Inspiration

You are a successful (or aspiring) YouTuber, looking for fresh content ideas that will take your channel to the next level.

Scrape videos and comments from one or more competitors' YouTube channels. Then feed the comment data into an AI assistant and ask it to summarize the recurring questions, complaints, and suggestions raised by viewers, optionally weighting the input based on likes or replies. Once you’ve isolated the topics your audience cares about most, prompt the AI to brainstorm video ideas, complete with compelling titles and structured outlines.

#### Content Repurposing

You are a web marketer, using YouTube as one of your promotional channels and you want to leverage your content for re-use across other platforms.

Popular long-form videos are goldmines for cross-platform content. Start by identifying your top-performing videos using YouTube analytics, then scrape them to retrieve their auto-generated transcripts. These transcripts can be transformed into blog posts, email newsletters, or scripts for TikTok/Instagram shorts - all with minimal effort using an AI content generator. With this approach, you dramatically expand your content footprint without increasing your production time.

#### Influencer Discovery and Outreach

You are a brand or agency scouting for micro-influencers to partner with in a specific niche.

Scrape videos based on niche-relevant keywords or hashtags and capture metadata such as view counts, likes, subscriber counts, and comment sentiment. Use AI to filter for creators with high engagement but modest follower bases (an indicator of authenticity and influence). Pair this with comment analysis to ensure their audience aligns with your brand values. You now have a curated list of potential partners, complete with campaign ideas grounded in real viewer conversations.

#### Sentiment Analysis for Product Feedback

You are a product team or customer success manager looking for honest, unsolicited feedback about your product or service.

Scrape all YouTube videos that mention your brand or product, along with their comments. Feed these into a sentiment analysis pipeline that classifies viewer reactions (positive, negative, neutral), identifies common pain points, and highlights praised features. This method surfaces high-signal feedback that may never make it into formal surveys or support tickets - giving you a more nuanced and actionable understanding of your customer experience.

#### Competitor Intelligence and Trend Monitoring

You are a product manager, strategist, or startup founder keeping a close eye on your industry’s key players.

Scrape recent uploads from competitors in your niche and analyze their video titles, descriptions, view counts, and publishing frequency to identify emerging content themes, product announcements, or campaign strategies. Use AI to cluster video content into topics and extract engagement metrics to discover which themes resonate most with audiences. This gives you a powerful, low-cost way to track market sentiment and stay one step ahead - without needing to rely on expensive competitive research tools.

<br><br>
![Your Opinion Matters](https://i.imgur.com/TupeBIp.png)
[![Leave a Review](https://i.imgur.com/gkYNjKK.png)](/actors/6E4kQL6o4PF9O0ApN/reviews) <br><br>

### 🚀 Quick Start

When we designed *YouTube Ultimate Scraper*, flexibility was one of our core goals. We knew users would need to scrape YouTube data in many different ways - ranging from quick tests to complex, large-scale extractions - so we built a tool that adapts to your needs without requiring a complex setup process.

With over 100 available settings, this scraper offers deep configurability. But instead of exposing everything up front, we’ve surfaced only the most essential options in the Apify **Input** tab - enough to get started quickly. Advanced configuration remains accessible when you need more control (and we're [ready to help](#support-and-onboarding-service), if you need it).

The **Input** tab in Apify exposes the scraper’s basic settings, allowing you to launch any supported crawl or scrape workflow in just a few clicks.

![Screenshot: Apify tabs](https://i.imgur.com/BBFrxLW.png)

Start by entering one or more YouTube URLs. This defines the content you want to scrape.

![Screenshot: setting target page URLs](https://i.imgur.com/k4RoMWk.png)

With each URL entered, you can target a single video, a hashtag, a search query or part or all of the content from a channel, and you're free to mix URL formats as you choose. For supported formats, refer to [this table](#supported-url-formats).

Next, configure how much content you want to retrieve. For example, you might scrape only the first 100 long-form videos from a channel, excluding shorts and livestreams.

![Screenshot: setting channel limits](https://i.imgur.com/GARpwCj.png)

Only the most commonly-used limit settings are exposed via the **Input** tab. A complete list is [available here](#limit-settings).

**Important:** By default, all crawling and scraping limits are set to zero. Unless you’re targeting a fixed list of video IDs or URLs, you must set at least one non-zero crawling limit. If not, the run will terminate immediately, reporting a configuration error.

As a final step, you may wish to add some optional content to your result set.

![Screenshot: setting content options](https://i.imgur.com/OCbMMJp.png)

If you add comments to your scraping run, you'll also need to configure their limit, to inform the scraper how many to retrieve for each target video.

![Screenshot: setting comment scraping limits](https://i.imgur.com/tB3Xx6Z.png)

Once your target URLs and scraping limits are set, and you have enabled any desired optional content, you can launch the run using standard Apify procedures. <br><br>

### 🛠️ Advanced Configuration

The basic settings are powerful enough for most users, but when you need full control over filtering, output formatting, sorting, or handling edge cases, you can use **advanced configuration**.

Advanced configuration is defined in a JSON snippet that you paste into the `Advanced configuration` field in the **Input** tab.

![Screenshot: input-advanced-settings](https://i.imgur.com/1jeIi5b.png)

You can override as little or as much of the default configuration as you want. For example, the following snippet tells the scraper to include embedded channel metadata with each video:

```json
{
    "output": {
        "channelMetadata": true
    }
}
```

To create an advanced configuration, the easiest approach is to [start from our template](#json-configuration-template), remove anything you don’t need, and then modify the relevant settings.

We’ve compiled a full [reference of all advanced settings](#configuration-settings-reference), including their descriptions and default values. If you need help, feel free to [reach out](https://apify.com/ultimate/youtube-scraper/issues). <br><br>

### 💥 Scraper Breakage Detection and Recovery

A scraper breakage occurs when a previously working and tested scraper stops functioning correctly or begins returning incomplete or incorrect results. These breakages are invariably caused by changes to the target website or its underlying APIs.

Unfortunately, this is a persistent and well-known challenge in the web scraping space. Most scrapers rely on a reactive approach: problems are only investigated once users report that something has gone wrong. The scraper developer must then manually debug the implementation - often without clear guidance - making diagnosis and resolution a time-consuming process.

*YouTube Ultimate Scraper* takes a fundamentally different approach. Our goal is to provide a higher standard of reliability and responsiveness by actively detecting and resolving breakages before they affect you.

To minimize downtime and ensure scraping reliability, we’ve implemented the following strategy:

- **Built-in Schema Validation**\
  Every scraper run performs detailed validation against a defined set of expected data schemas. This helps identify breakages immediately - even when they only affect a subset of the output structure.

- **Comprehensive Test Suite**\
  We maintain an automated test suite covering over 30 real-world YouTube scraping scenarios, spanning all major workflows, data types, and content formats.

- **Daily Test Runs**\
  Our test suite is executed daily, allowing us to detect breakages early - often before users are even aware an issue has occurred.

- **Rapid Response and Fixes**\
  When a breakage is detected, resolving it becomes our top development priority. Fixes are issued as quickly as possible, often the same day.

- **Expanding Coverage**\
  If a user reports a scraping failure that isn't yet covered by our test suite, we not only investigate and fix the issue, but also incorporate the new scenario into our test coverage to prevent future regressions.

This proactive approach allows us to deliver a more stable and reliable experience to our users, and to respond to platform changes with greater speed and precision.

If you ever notice a problem with your scraping results, please [report it](https://apify.com/ultimate/youtube-scraper/issues), so that we can address it immediately. <br><br>

### 🛡️ Anti-scraping Defenses

Websites like YouTube employ various anti-scraping defenses to detect and block automated access. These can include:

- IP-based rate limiting or blocking
- Cookie and session tracking
- Return of misleading or incomplete data to suspected bots

These measures are a persistent challenge for scrapers, particularly when performing high-volume or frequent operations.

Unlike most scrapers that rely on headless browsers to simulate user behavior, *YouTube Ultimate Scraper* takes a more efficient and resilient approach:

- **API-first Architecture**\
  The majority of YouTube data is retrieved directly via internal API endpoints, rather than parsed from HTML. This results in faster, cleaner data retrieval with fewer parsing risks and the ability to [proactively deal with breakages](#scraper-breakage-detection-and-recovery).

- **Lightweight Scraper Engine**\
  The scraper uses Apify's `BasicCrawler` instead of a headless browser, which optimizes scraping execution, while still achieving full feature coverage via API interaction.

- **Residential Proxies**\
  All requests are sent through residential proxies by default, helping to bypass IP-based detection and geo-specific restrictions.

- **Proxy Rotation and Session Management**\
  The scraper rotates proxies automatically and employs a fine-grained session management strategy, ensuring the optimum balance of speed, accuracy and resilience.

This architecture enables the scraper to operate with a lower detection profile while maintaining high throughput and stability.

<br><br>
![Help us to Climb to the Top](https://i.imgur.com/TUU3tbj.png)
[![Leave a Review](https://i.imgur.com/gkYNjKK.png)](/actors/6E4kQL6o4PF9O0ApN/reviews) <br><br>

### 📶 Tips for Effective Scraping

To get the best results from your YouTube scraping runs, a few simple practices can make a big difference. Whether you're aiming to reduce execution time and cost or improve the relevance of your output, these tips will help you configure your runs more effectively and avoid common pitfalls.

#### Content Sorting

The scraper supports three separate sorting mechanisms, which may initially appear redundant. However, they fall into two distinct categories - **pre-crawl sorting** and **post-scrape sorting** - each serving a specific purpose.

Understanding when and how to apply these options can significantly improve the relevance and structure of your output.

##### Pre-crawl Sorting

Pre-crawl sorting is used to prioritize which content gets selected *before* any scraping begins. This is especially important when applying fixed crawl limits - for example, retrieving the **first 100 videos** from a channel or the **top 50 search results**.

If you're looking for the most recent videos, for instance, we recommend applying a `'latest'` sort before the crawl begins, ensuring that your limited set of videos is chosen from the most relevant pool of candidates.

The following settings control pre-crawl sorting:

- `crawling.listSort` - sorts listed videos, shorts, and livestreams on channel pages ([reference](#crawling-settings))
- `crawling.searchFilters.sort` - sets sorting mode for global search results ([reference](#search-filter-settings))

##### Post-scrape Sorting

After all selected content has been crawled and scraped, you may want to apply sorting to the final output. This type of sorting operates across the **entire result set**, ensuring consistent ordering in the exported data - regardless of crawl order.

The following setting applies post-scrape sorting:

- `output.sort`  -  Sorts the complete set of scraped results before export

When output sorting is enabled, the result set will be exported in a single pass, when scraping is completed. This is because it is not possible to perform sorting until the entire result set is available. When sorting is disabled (the default setting), results will be exported periodically, as they are scraped.

#### Date Filtering

Many users want to scrape YouTube content within a specific date range (for example, videos published on a given channel in the past month).

While it would be preferable to apply a date filter during the crawling phase (to avoid scraping irrelevant items), this is not possible, for two key reasons:

- YouTube does not provide any reliable date-based filtering via its official APIs or page URLs.
- The publication dates shown in listings are approximate (e.g. “3 weeks ago”), inconsistent, and not always available (especially for shorts, livestreams, or some content categories).

As a result, the only dependable method of date filtering is to perform a broad scrape and then apply the date filter afterward, removing any items outside the desired range. This approach is less efficient but offers a practical workaround to the limitations imposed by YouTube's design.

##### Filtering Costs

When using date filtering, you will not be directly charged for any of the discarded results. However, because this process incurs some additional operating costs, your delivered result set will be subject to an add-on charge that marginally increases their unit cost. Please see [pricing](https://apify.com/ultimate/youtube-scraper/pricing) for details.

##### Filtering Caveats

If you're also applying a crawl limit (e.g. scraping the first 100 videos from a channel), be aware that the limit is applied before date filtering. This means your candidate pool might contain few or even no items that pass the date filter.

##### Filtering Best Practice

To improve results, combine date filtering with a [pre-crawl sorting strategy](#content-sorting) that complements it. For example, if you're interested in videos from the past month, apply a `'latest'` list sort to prioritize recent content during crawling.

This increases the likelihood that the scraped data includes videos that match your date criteria, even if a crawl limit is in place.

#### Authentication

Some platforms (such as Instagram and Facebook) severely restrict the content that is available without logging in. Thankfully YouTube doesn't (currently) work that way, so it is possible to scrape YouTube as an anonymous user.

Why is this important? Because, although it's a relatively straightforward task to configure a scraper to log into an account, on almost any platform, it comes with the risk that the platform will identify it as a bot and then ban the account that it's logged into.

With *YouTube Ultimate Scraper*, you don't have to worry about this issue. You will never be asked to provide identification and your YouTube scraping will always be carried out anonymously.

#### Incremental Scraping

In many scraping scenarios, you may wish to revisit previously scraped content sources, such as YouTube channels, hashtags, or search results, without duplicating data already collected in earlier runs. This is particularly relevant when:

- Scraping multiple related search terms that may return overlapping video results
- Periodically updating the video list for a channel, but only wishing to retrieve new uploads

To support these use cases efficiently, the scraper offers an incremental scraping feature (configured using the `discovery.ignoreIds` setting) that allows you to exclude previously-scraped video IDs from the current run.

Filtering out previously scraped content can deliver a significant cost saving, since you are only charged for results that are actually delivered. Ignored videos are never scraped, so no charge is incurred for them. This saving extends even further when you're also adding optional content, such as channel metadata, video transcripts, or comments/replies.

A small charge is applied for each video ID in the ignore list, but this is typically much lower than the combined cost of the duplicate content that it eliminates. Incremental scraping is therefore highly recommended when you want to keep your data fresh without paying for the same content more than once.<br><br>

### 🆘 Support & Onboarding Service

We want you to enjoy the best possible experience while using *YouTube Ultimate Scraper*, so we're laser focused on providing the support you need, when you need it.

If you run into an obstacle, while configuring or using the scraper, please [raise an issue](https://apify.com/ultimate/youtube-scraper/issues), and we'll give it our rapid attention. We treat bugs and breakages as an absolute priority, but we're also keen to help out with advice and guidance that will make your scraping task easier and more effective.

Some users also tell us that they feel a little overwhelmed by the sheer scope of the configuration options offered by this scraper. Most users appreciate its vast flexibility, but not everyone is certain how to harness it. If that's you, our onboarding service may be the answer. We'll schedule a short video call to understand your scraping goals, then we'll design a custom scraping configuration that you're free to use as you choose.

To claim your free session, simply leave us a rating in the Apify marketplace. 5 stars would be much appreciated, but it's definitely not a pre-condition. Then [contact us](https://apify.com/ultimate/youtube-scraper/issues) to schedule your free onboarding. We look forward to working with you. <br><br>

### ⚙️ Configuration Settings Reference

This section documents every supported configuration setting. Each sub-section below corresponds to an individual settings object within the advanced configuration JSON data hierarchy. While using this reference, we recommend also referring to the [JSON Configuration Template](#json-configuration-template), to better visualize the hierarchical relationships between objects.

##### Discovery Settings

Discovery settings tell the scraper exactly which YouTube content you wish to scrape. You can specify your requirements using either IDs or URLs and mix them as you choose. The full range of discovery settings may be configured in the `discovery` object. Additionally, URL-based discovery is also configurable via the Apify **Input** tab.

The settings in this section can potentially affect your run costs. Please see [pricing](https://apify.com/ultimate/youtube-scraper/pricing) for details.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `videoIds`                | string\[] | \[]                    | An array of strings, each being a valid YouTube video ID. |
| `channelIds`              | string\[] | \[]                    | An array of strings, each being a valid YouTube channel ID or channel handle. |
| `searchQueries`           | string\[] | \[]                    | An array of strings, each being a search term used to perform a YouTube global search. |
| `hashtags`                | string\[] | \[]                    | An array of strings, each being a keyword that identifies a valid YouTube hashtag. |
| `urls`                    | string\[] | \[]                    | An array of strings, each being a YouTube URL in one of the [supported formats](#supported-url-formats). |
| `ignoreIds`               | string\[] | \[]                    | An array of strings, each being the ID of a previously-scraped YouTube video that should be skipped in the current run. See [Incremental Scraping](#incremental-scraping). |

##### Crawling Settings

Crawling settings are configured in the `crawling` object and determine how the scraper will execute a run. Some settings are configured as direct properties of the `crawling` object, while others are exposed via nested objects.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `proxyCountry`            | enum     | 'US'                  | The 2-digit code of the country that hosts the Apify proxies that will be used for crawling/scraping. The proxy location determines how YouTube perceives the origin of your HTTP requests and may influence which content is available to you. In most cases we recommend using the default setting. However, if the content you are seeking to scrape is geographically restricted, you may need to choose a proxy country that provides better access to it.<br><br>Supported values are 'US', 'GB', 'DE', 'FR', 'CA', 'AU', 'IT', 'ES', 'NL', 'IN', 'BR' and 'MX'. |
| `searchFilters`           | object   | [Nested Settings](#search-filter-settings) | Contains a nested [search filter settings](#search-filter-settings) object, which enables the scraper to emulate YouTube's global search filters. |
| `limits`                  | object   | [Nested Settings](#limit-settings) | Contains a nested [limit settings](#limit-settings) object, which determines the limits that constrain crawling and scraping. |
| `listSort`                | enum     | 'latest'              | The order in which content listings on channel pages are sorted, prior to crawling. As [explained here](#date-filtering), this setting can have a significant effect on the quality and relevance of scraped results, (especially when using tight crawl limits).<br><br>Supported values are 'latest', 'popular' and 'oldest'. |

##### Search Filter Settings

Search filters are configured in the `crawling.searchFilters` object and emulate the native filter mechanism that YouTube offers for global searches. This is a convenience feature that allows you to configure a common search filter profile that will be used by all global searches targeted using the `discovery.searchQueries` setting. Note that this common profile is not used by global searches targeted using URLs, as YouTube's search URL format incorporates its own filter parameter. We recommend using URLs if you require individual filtering profiles for each search term.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `sort`                    | enum     | null                  | The sort order applied to global searches.<br><br>Supported values are 'relevance', 'upload', 'views' and 'rating'. |
| `recency`                 | enum     | null                  | The recency filter applied to global searches.<br><br>Supported values are 'hour', 'day', 'week', 'month' and 'year'. |
| `type`                    | enum     | null                  | The content type filter applied to global searches.<br><br>Supported values are 'video', 'channel', 'playlist' and 'movie'. |
| `duration`                | enum     | null                  | The duration filter applied to global searches.<br><br>Supported values are 'under4', '4to20' and 'over20', which represent the duration of the video in minutes. |
| `features`                | enum\[]   | \[]                    | The content feature filters applied to global searches. Multiple features may be specified.<br><br>Supported values are 'live', '4k', 'hd', 'subtitles', 'cc', '360', 'vr180', '3d', 'hdr', 'location' and 'purchased'. |

##### Limit Settings

Crawling limits determine the maximum number of results that will be retrieved within a given context (for example, the number of videos scraped for each target channel). All crawling limits may be configured in the `crawling.limits` object. Most of the limit settings are also exposed via the Apify **Input** tab.

Unless you’re targeting a fixed list of video IDs or URLs, you must set at least one non-zero crawling limit, otherwise no content will qualify for crawling and the run will not execute.

The settings in this section can potentially affect your run costs. Please see [pricing](https://apify.com/ultimate/youtube-scraper/pricing) for details.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `maxChannelVideos`        | integer  | 0                     | The maximum number of long-form videos to be retrieved while crawling each target channel. Each video will be subsequently scraped to yield a single video metadata result set. |
| `maxChannelShorts`        | integer  | 0                     | The maximum number of shorts to be retrieved while crawling each target channel. Each short will be subsequently scraped to yield a single video metadata result set. |
| `maxChannelStreams`       | integer  | 0                     | The maximum number of livestreams to be retrieved while crawling each target channel. Each livestream will be subsequently scraped to yield a single video metadata result set. |
| `maxChannelSearchResults` | integer  | 0                     | The maximum number of videos to be retrieved while crawling each target channel search. Each video will be subsequently scraped to yield a single video metadata result set. |
| `maxGlobalSearchResults`  | integer  | 0                     | The maximum number of videos to be retrieved while crawling each target global search. Each video will be subsequently scraped to yield a single video metadata result set. |
| `maxHashtagResults`       | integer  | 0                     | The maximum number of videos to be retrieved while crawling each target hashtag. Each video will be subsequently scraped to yield a single video metadata result set. |
| `maxVideoComments`        | integer  | 0                     | The maximum number of comments to be scraped for each scraped video. |
| `maxCommentReplies`       | integer  | 0                     | The maximum number of replies to be scraped for each scraped comment. |

##### Output Settings

Output settings are configured in the `output` object and determine the composition of the output result set. Some settings are configured as direct properties of the `output` object, while others are exposed via nested objects.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `sort`                    | enum     | false                 | An enum member value that indicates the order in which the output result set will be sorted, or **false** to indicate that output sorting is disabled.<br><br>Supported values are 'recency', 'views', 'likes', 'length' and **false**.<br><br>See [Content Sorting](#content-sorting). |
| `dateFilter`              | object   | [Nested Settings](#date-filter-settings) | A nested [date filter settings](#date-filter-settings) object, which determines how videos are filtered from the output result set, based on their publication date. |
| `videoMetadata`           | object   | [Nested Settings](#video-metadata-settings) | A nested [video metadata settings](#video-metadata-settings) object, which determines how video metadata scraping is executed. |
| `channelMetadata`         | multiple | [Nested Settings](#channel-metadata-settings) | Typically a nested [channel metadata settings](#channel-metadata-settings) object, which determines how channel metadata scraping is executed. This property may also be assigned the value **true**, indicating that channel metadata scraping is executed using default settings, or **false**, indicating that channel metadata scraping is disabled. |
| `transcript`              | multiple | [Nested Settings](#transcript-settings) | A nested [transcript settings](#transcript-settings) object, which determines how video transcript scraping is executed. This property may also be assigned the value **true**, indicating that transcript scraping is executed using default settings, or **false**, indicating that transcript scraping is disabled. |
| `comments`                | multiple | [Nested Settings](#comments-settings) | A nested [comments settings](#comments-settings) object, which determines how comment scraping is executed. This property may also be assigned the value **true**, indicating that comment scraping is executed using default settings, or **false**, indicating that comment scraping is disabled. |

##### Date Filter Settings

Date filter settings are configured in the `output.dateFilter` object and determine how videos are filtered from the output result set, based on their publication date.

The settings in this section can potentially affect your run costs. Please see [pricing](https://apify.com/ultimate/youtube-scraper/pricing) for details.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `startDate`               | string   | '1970-01-01T00:00:00' | A string in ISO 8601 extended datetime format (without an explicit timezone) that indicates a UTC date/time. Only videos published after this will be included in in output result set.<br><br>See [Date Filtering](#date-filtering). |
| `endDate`                 | string   | '2199-01-01T00:00:00' | A string in ISO 8601 extended datetime format (without an explicit timezone) that indicates a UTC date/time. Only videos published before this will be included in in output result set.<br><br>See [Date Filtering](#date-filtering). |

##### Video Metadata Settings

Video metadata settings are configured in the `output.videoMetadata` object and determine the composition of scraped video data in the output result set. By toggling individual data properties, you can shape the output result set to match your exact requirements. However, note that enabling a data property does not guarantee that it will be included in every result, as the completeness of YouTube video metadata can vary between videos.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `channelId`               | boolean  | true                  | Whether to include the video ID in output video metadata. |
| `author`                  | boolean  | true                  | Whether to include the video author name in output video metadata. |
| `title`                   | boolean  | true                  | Whether to include the video title in output video metadata. |
| `description`             | boolean  | true                  | Whether to include the video description in output video metadata. |
| `keywords`                | boolean  | true                  | Whether to include the video keywords in output video metadata. |
| `length`                  | boolean  | true                  | Whether to include the video duration in output video metadata. |
| `thumbnails`              | boolean  | true                  | Whether to include the video thumbnail data in output video metadata. |
| `metrics`                 | boolean  | true                  | Whether to include the video metrics in output video metadata. |
| `allowRatings`            | boolean  | true                  | Whether to include the the `allowsRatings` flag in output video metadata. |
| `isPrivate`               | boolean  | true                  | Whether to include the the `isPrivate` flag in output video metadata. |
| `isLiveContent`           | boolean  | true                  | Whether to include the the `isLiveContent` flag in output video metadata livestream. |
| `isUnlisted`              | boolean  | true                  | Whether to include the the `isUnlisted` flag in output video metadata. |
| `captionTracks`           | boolean  | true                  | Whether to include the video transcript languages list in output video metadata. |
| `category`                | boolean  | true                  | Whether to include the video category name in output video metadata. |
| `publishDate`             | boolean  | true                  | Whether to include the video publication date in output video metadata. |
| `ownerChannelName`        | boolean  | true                  | Whether to include the video owner channel name in output video metadata. |
| `viewCount`               | boolean  | true                  | Whether to include the video view count in output video metadata. |
| `likeCount`               | boolean  | true                  | Whether to include the video like count in output video metadata. |

##### Channel Metadata Settings

Channel metadata settings are configured in the `output.channelMetadata` object and determine the composition of scraped channel data in the output result set. By toggling individual data properties, you can shape the output result set to match your exact requirements. However, note that enabling a data property does not guarantee that it will be included in every result, as the completeness of YouTube channel metadata can vary between channels.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `handle`                  | boolean  | true                  | Whether to include the channel handle in output channel metadata. |
| `title`                   | boolean  | true                  | Whether to include the channel title in output channel metadata. |
| `description`             | boolean  | true                  | Whether to include the channel deescription in output channel metadata. |
| `keywords`                | boolean  | true                  | Whether to include the channel keywords in output channel metadata. |
| `country`                 | boolean  | true                  | Whether to include the channel country in output channel metadata. |
| `avatar`                  | boolean  | true                  | Whether to include the channel avatar URLs in output channel metadata. |
| `joinedDateText`          | boolean  | false                 | Whether to include the channel owner joined date in output channel metadata (in its original raw text form). |
| `joinedDate`              | boolean  | true                  | Whether to include the parsed channel owner joined date in output channel metadata. |
| `channelAgeDays`          | boolean  | true                  | Whether to include the parsed channel age (days) in output channel metadata. |
| `channelUrl`              | boolean  | true                  | Whether to include the channel URL in output channel metadata. |
| `canonicalUrl`            | boolean  | true                  | Whether to include the channel canonical URL in output channel metadata. |
| `rssUrl`                  | boolean  | true                  | Whether to include the channel RSS URL in output channel metadata. |
| `videosUrl`               | boolean  | true                  | Whether to include the channel videos page URL in output channel metadata. |
| `shortsUrl`               | boolean  | true                  | Whether to include the channel shorts page URL in output channel metadata. |
| `liveUrl`                 | boolean  | true                  | Whether to include the channel livestrams page URL in output channel metadata. |
| `playlistsUrl`            | boolean  | true                  | Whether to include the channel playlists page URL in output channel metadata. |
| `aboutUrl`                | boolean  | true                  | Whether to include the channel about page URL in output channel metadata. |
| `searchUrl`               | boolean  | true                  | Whether to include the channel search page URL in output channel metadata. |
| `ownerUrls`               | boolean  | true                  | Whether to include the channel owner URL in output channel metadata. |
| `links`                   | boolean  | true                  | Whether to include the channel link data in output channel metadata. |
| `hasBusinessEmailAddress` | boolean  | true                  | Whether to include the `hasBusinessEmailAddress` flag in output channel metadata. |
| `isFamilySafe`            | boolean  | true                  | Whether to include the `isFamilySafe` flag in output channel metadata. |
| `subscriberCountText`     | boolean  | false                 | Whether to include the channel subscriber count text in output channel metadata (in its original raw text form). |
| `subscriberCount`         | boolean  | true                  | Whether to include the parsed channel subscriber count in output channel metadata. |
| `viewCountText`           | boolean  | false                 | Whether to include the channel view count text in output channel metadata (in its original raw text form). |
| `viewCount`               | boolean  | true                  | Whether to include the parsed channel view count in output channel metadata. |
| `videoCountText`          | boolean  | false                 | Whether to include the channel video count text in output channel metadata (in its original raw text form). |
| `videoCount`              | boolean  | true                  | Whether to include the parsed channel video count in output channel metadata. |
| `averageViewCount`        | boolean  | true                  | Whether to include the calculated average video view count in output channel metadata. |
| `availableCountryCodes`   | boolean  | true                  | Whether to include the channel available country codes list in output channel metadata. |

##### Transcript Settings

Transcript settings are configured in the `output.transcript` object and determine the composition of scraped transcript data in the output result set.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `language`                | string   | 'en'                  | A 2-character ISO language code that indicates the desired language for scraped transcripts. Note that the transcripts for most videos are typically only available in limited range of languages and that some videos have no transcripts. If the specified language is not available, no transcript will be scraped, even if other languages are available. |
| `format`                  | enum     | 'timeline'            | The format in which scraped transcript data will be presented in the output result set. The default 'timeline' format is an array of JSON objects, representing individual transcript segments, and includes both the transcript text and its timestamp data. The alternative 'contionuous' format discards all timestamp data and concatenates the text of all transcript segments into a continuous string value.<br><br>Supported values are 'timeline' and 'continuous'. |

##### Comments Settings

Comments settings are configured in the `output.comments` object and determine the composition of scraped comment data in the output result set. By toggling individual data properties, you can shape the output result set to match your exact requirements.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `totalCount`              | boolean  | true                  | Whether to include the total video comment count in output comment data. |
| `publishedDateText`       | boolean  | false                 | Whether to include the comment published date/time in output comment data (in its original raw text form). |
| `publishedDate`           | boolean  | true                  | Whether to include the parsed comment published date/time in output comment data. |
| `isPinned`                | boolean  | true                  | Whether to include the `isPinned` flag in output comment data. |
| `isHearted`               | boolean  | true                  | Whether to include the `isHearted` flag in output comment data. |
| `hasDonation`             | boolean  | true                  | Whether to include the `hasDonation` flag in output comment data. |
| `level`                   | boolean  | true                  | Whether to include the comment level in output comment data. |
| `authorChannelId`         | boolean  | true                  | Whether to include the comment author channel ID in output comment data. |
| `authorDisplayName`       | boolean  | true                  | Whether to include the comment author display name in output comment data. |
| `isCreator`               | boolean  | true                  | Whether to include the `isCreator` flag in output comment data. |
| `isVerified`              | boolean  | true                  | Whether to include the `isVerified` flag in output comment data. |
| `likeCount`               | boolean  | true                  | Whether to include the comment like count in output comment data. |
| `replyCount`              | boolean  | true                  | Whether to include the comment reply count in output comment data. |
| `replies`                 | multiple | [Nested Settings](#replies-settings) | Typically a nested [replies settings](#replies-settings) object, which determines how comment reply scraping is executed. This property may also be assigned the value **true**, indicating that reply scraping is executed using default settings, or **false**, indicating that reply scraping is disabled. |

##### Replies Settings

Replies settings are configured in the `output.comments.replies` object and determine the composition of scraped comment reply data in the output result set. By toggling individual data properties, you can shape the output result set to match your exact requirements.

| Setting                   | Type     | Default               | Usage |
|-------------------------- |--------- |-----------------------| ----- |
| `publishedDateText`       | boolean  | false                 | Whether to include the reply published date/time in output reply data (in its original raw text form). |
| `publishedDate`           | boolean  | true                  | Whether to include the parsed reply published date/time in output reply data. |
| `isPinned`                | boolean  | true                  | Whether to include the `isPinned` flag in output reply data. |
| `isHearted`               | boolean  | true                  | Whether to include the `isHearted` flag in output reply data. |
| `hasDonation`             | boolean  | true                  | Whether to include the `hasDonation` flag in output reply data. |
| `level`                   | boolean  | true                  | Whether to include the reply level in output reply data. |
| `authorChannelId`         | boolean  | true                  | Whether to include the reply author channel ID in output reply data. |
| `authorDisplayName`       | boolean  | true                  | Whether to include the reply author display name in output reply data. |
| `isCreator`               | boolean  | true                  | Whether to include the `isCreator` flag in output reply data. |
| `isVerified`              | boolean  | true                  | Whether to include the `isVerified` flag in output reply data. |
| `likeCount`               | boolean  | true                  | Whether to include the reply like count in output reply data. |

<br><br>
![Fuel the Journey](https://i.imgur.com/4E5zyYh.png)
[![Leave a Review](https://i.imgur.com/gkYNjKK.png)](/actors/6E4kQL6o4PF9O0ApN/reviews) <br><br>

### 🧪 Sample Output Data

A successful scraper run yields one or more JSON output files, each containing the metadata for a scraped video. Each ouput file contains a single root-level JSON object, with optional nested objects, depending on your [output settings](#output-settings).

#### Video Metadata Sample

The root-level JSON object represents the metadata for a scraped video. The sample below reflects the most verbose form of video metadata output, but all data properties, including nested data objects, are [configurable](#video-metadata-settings).

```json
{
	"id": "99bgTARgKD8",
	"publishDate": "2025-07-27T19:53:39.000Z",
	"title": "England vs. Spain UEFA Women's Euro 2025 Highlights | FOX Soccer",
	"description": "Check out the highlights from the UEFA Women's Euro 2025 Finals clash between England and Spain.\n\n#FOXSoccer #England #Spain\n\nSUBSCRIBE to get the latest FOX Soccer content: http://foxs.pt/SubscribeFOXSOCCER\n\nThe FOX Sports App, built for the modern sports fan: https://t.co/CRhWt4ryp3\n\nAbout FOX Soccer:\nWith exclusive highlights, original programming, and behind the scenes footage, FOX Soccer’s YouTube channel provides the sports content that fans are hungry for. FOX Soccer presents: MLS, FIFA World Cup, FIFA Women’s World Cup, Copa America, Euros, Gold Cup and many more.\n\nEngland vs. Spain UEFA Women's Euro 2025 Highlights | FOX Soccer\nhttps://www.youtube.com/user/Foxsoccer",
	"category": "Sports",
	"author": "FOX Soccer",
	"ownerChannelName": "FOX Soccer",
	"channelId": "UCooTLkxcpnTNx6vfOovfBFA",
	"allowRatings": true,
	"isPrivate": false,
	"isLiveContent": false,
	"isUnlisted": false,
	"length": 592,
	"viewCount": 441384,
	"likeCount": 4374,
	"captionTracks": [
		{
			"language": "en",
			"kind": "asr"
		}
	],
	"keywords": [
		"soccer",
		"euros",
		"fox",
		"fox sports",
		"fox sports soccer",
		"fox soccer",
		"FOX Soccer",
		"sports highlights"
	],
	"thumbnails": [
		{
			"url": "https://i.ytimg.com/vi/99bgTARgKD8/hqdefault.jpg?sqp=-oaymwEmCKgBEF5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLCgdMqMttmHi1MPfNlDtfRuQBxIdg",
			"width": 168,
			"height": 94
		},
		{
			"url": "https://i.ytimg.com/vi/99bgTARgKD8/hqdefault.jpg?sqp=-oaymwEmCMQBEG5IWvKriqkDGQgBFQAAiEIYAdgBAeIBCggYEAIYBjgBQAE=&rs=AOn4CLAGGQ4K95vfjAps6J7dML86mxD8kA",
			"width": 196,
			"height": 110
		}
	],
    "metrics": {
        "captionTracks": 1,
        "keywords": 8,
        "channelLinks": 4,
        "channelCountries": 247,
        "transcriptSegments": 609,
        "comments": 2,
        "replies": 3
    },
    "channelMetadata": {
        An optional nested channel metadata object (see below)
    },
    "transcript": {
        An optional nested transcript data object (see below)
    },
    "comments": {
        An optional nested comments data object (see below)
    }
}  
```

#### Channel Metadata Sample

Nested within a video metadata object is an optional channel metadata object, representing the channel that owns the video. The sample below reflects the most verbose form of channel metadata output, but all data properties are individually [configurable](#channel-metadata-settings).

```json
{
    "id": "UCooTLkxcpnTNx6vfOovfBFA",
    "handle": null,
    "title": "FOX Soccer",
    "description": "Welcome to the official FOX Soccer YouTube channel, your ultimate destination for everything soccer! From Major League Soccer to international soccer action, we bring you the best highlights, expert analysis, and exclusive content. Stay ahead of the game with in-depth coverage of the upcoming 2026 Men's World Cup and more. Whether you're following the biggest global tournaments or the exciting moments from the MLS, we’ve got you covered. Subscribe now for non-stop soccer action, news, and top-tier analysis from the world’s most popular sport!",
    "keywords": "fs1 \"fox sports 1\" \"FOX Soccer\" \"UEFA Champions League\" Bundesliga FIFA \"fox sports\"",
    "country": "United States",
    "avatar": {
        "url": "https://yt3.googleusercontent.com/aveASTfRd2GwIdpThrMH4_3KPakK0i7V8LID2hKrg5Xw7qNZecSFvZdJIsDYTRpiC8yfrAQV=s900-c-k-c0x00ffffff-no-rj",
        "width": 900,
        "height": 900
    },
    "joinedDate": "2006-03-30T00:00:00.000Z",
    "channelAgeDays": 6995,
    "channelUrl": "https://www.youtube.com/channel/UCooTLkxcpnTNx6vfOovfBFA",
    "canonicalUrl": "http://www.youtube.com/@Foxsoccer",
    "rssUrl": "https://www.youtube.com/feeds/videos.xml?channel_id=UCooTLkxcpnTNx6vfOovfBFA",
    "videosUrl": "https://www.youtube.com/channel/UCooTLkxcpnTNx6vfOovfBFA/videos",
    "shortsUrl": "https://www.youtube.com/channel/UCooTLkxcpnTNx6vfOovfBFA/shorts",
    "liveUrl": "https://www.youtube.com/channel/UCooTLkxcpnTNx6vfOovfBFA/live",
    "playlistsUrl": "https://www.youtube.com/channel/UCooTLkxcpnTNx6vfOovfBFA/playlists",
    "aboutUrl": "https://www.youtube.com/channel/UCooTLkxcpnTNx6vfOovfBFA/about",
    "searchUrl": "https://www.youtube.com/channel/UCooTLkxcpnTNx6vfOovfBFA/search?query={query}",
    "ownerUrls": [
        "http://www.youtube.com/@Foxsoccer"
    ],
    "links": [
        {
            "title": "More from FOX Soccer",
            "url": "foxsports.com/soccer"
        },
        {
            "title": "FOX Soccer Facebook",
            "url": "facebook.com/foxsoccer"
        },
        {
            "title": "FOX Soccer Twitter",
            "url": "twitter.com/FOXSoccer"
        },
        {
            "title": "FOX Soccer Instagram",
            "url": "instagram.com/foxsoccer"
        }
    ],
    "hasBusinessEmailAddress": true,
    "isFamilySafe": true,
    "subscriberCount": 1450000,
    "viewCount": 843451421,
    "videoCount": 11591,
    "averageViewCount": 72767,
    "availableCountryCodes": [
        "LU",
        "ET",
        "SD",
        "BI",
        "CW",

        ... trimmed for brevity ... 

        "PL",
        "ZA",
        "SI",
        "CG",
        "JM"
    ]
}
```

#### Transcript Sample

Nested within a video metadata object is an optional transcript array (or string), representing the transcript of the video in one of its available languages. The sample below reflects the transcript output in 'timeline' format, but this may optionally be [configured](#transcript-settings) as a continuous stream of text.

```json
[
    {
        "start": 1520,
        "end": 5040,
        "texts": [
            "25 days and 30 action-packed matches"
        ]
    },
    {
        "start": 5040,
        "end": 8400,
        "texts": [
            "after Euro 2025 kicked off and we are"
        ]
    },
    {
        "start": 8400,
        "end": 11440,
        "texts": [
            "down to the final two in Basel. And the"
        ]
    },

    ... trimmed for brevity ... 

    {
        "start": 557200,
        "end": 560200,
        "texts": [
            "Yeah."
        ]
    },
    {
        "start": 568720,
        "end": 571720,
        "texts": [
            "Heat."
        ]
    },
    {
        "start": 574310,
        "end": 583620,
        "texts": [
            "[Applause]"
        ]
    }
]
```

#### Comments/Replies Sample

Nested within a video metadata object is an optional comments collection, representing a subset or all of the video's viewer comments. The sample below reflects the most verbose form of comments output, but all data properties, including replies, are individually [configurable](#comments-metadata-settings).

```json
{
    "totalCount": 885,
    "comments": [
        {
            "id": "Ugxb_EVDe8bNFSYcBlR4AaABAg",
            "content": "What was your favorite moment from this match?",
            "publishedDate": "2025-07-28T00:00:00.000Z",
            "isPinned": true,
            "isHearted": false,
            "hasDonation": false,
            "level": 0,
            "authorChannelId": "UCooTLkxcpnTNx6vfOovfBFA",
            "authorDisplayName": "@Foxsoccer",
            "isCreator": true,
            "likeCount": 55,
            "replyCount": 3,
            "replies": [
                {
                    "id": "Ugxb_EVDe8bNFSYcBlR4AaABAg.AL5Q-Hv6FIHAL5QX-pe8_B",
                    "content": "Kelly's winning penalty 🏴󠁧󠁢󠁥󠁮󠁧󠁿",
                    "publishedDate": "2025-07-28T00:00:00.000Z",
                    "isPinned": false,
                    "isHearted": false,
                    "hasDonation": false,
                    "level": 1,
                    "authorChannelId": "UCLpzh4ClMCLyAQUeDOY-9zw",
                    "authorDisplayName": "@richm23k",
                    "isCreator": false,
                    "likeCount": 37
                },
                {
                    "id": "Ugxb_EVDe8bNFSYcBlR4AaABAg.AL5Q-Hv6FIHAL5SXIct-fT",
                    "content": "Watching the women successfully score a good pen.",
                    "publishedDate": "2025-07-28T00:00:00.000Z",
                    "isPinned": false,
                    "isHearted": false,
                    "hasDonation": false,
                    "level": 1,
                    "authorChannelId": "UCOMLj9-Qn_LjrYSX-FvSEUA",
                    "authorDisplayName": "@FlipJohn",
                    "isCreator": false,
                    "likeCount": 13
                },
                {
                    "id": "Ugxb_EVDe8bNFSYcBlR4AaABAg.AL5Q-Hv6FIHAL5SeW5JNHG",
                    "content": "Hampton's super save.",
                    "publishedDate": "2025-07-28T00:00:00.000Z",
                    "isPinned": false,
                    "isHearted": false,
                    "hasDonation": false,
                    "level": 1,
                    "authorChannelId": "UCpSczBc0HDW2rSXl5Un3aWQ",
                    "authorDisplayName": "@Muu0934",
                    "isCreator": false,
                    "likeCount": 12
                }
            ]
        },
        {
            "id": "UgyD8-Y0kZ0TQauFymt4AaABAg",
            "content": "Chloe Kelly is HER!!!\n-Winning goal in the Euro 2022 Final.\n-Winning penalty in the 2023 Finalissima.\n-Winning penalty in the 2023 World Cup Round of 16.\n-Subs in and immediately sets up two clutch goals, plus scores her penalty to keep England alive in the Euro 2025 Quarterfinal.\n-Winning goal in the Euro 2025 Semifinal.\n-Winning penalty in the Euro 2025 Final.",
            "publishedDate": "2025-07-28T00:00:00.000Z",
            "isPinned": false,
            "isHearted": true,
            "hasDonation": false,
            "level": 0,
            "authorChannelId": "UCA9skl5Iwoi2_RB0muUDB1Q",
            "authorDisplayName": "@nintendolegonbafan5413",
            "isCreator": false,
            "likeCount": 381,
            "replyCount": 0
        }
    ]
}
```

<br><br>

### 🔗 Supported URL Formats

When configuring your scraper, either via the Apify **Input** tab or using [advanced configuration](#advanced-configuration), a variety of valid YouTube URLs may be used to indicate the target content that you wish to scape. The table below shows the supported URL formats and how to use them. A single scraping run may incorporate any mix of URL formats (as well as ID-based content targeting, if you need it).

| URL Type / Examples | How it Works |
| ------------------- | ------------ |
| <strong>Video page URL</strong><br><br>https://www.youtube.com/watch?v=VIDEO\_ID<br><br> | Enter one or more video page URLs to identify videos to be scraped.<br><br>The scraper will output a single scraping result for each URL entered.<br> |
| <strong>Channel home page URL</strong><br><br>https://www.youtube.com/@CHANNEL\_HANDLE<br>https://www.youtube.com/channel/CHANNEL\_ID<br><br><br><br><br> | Enter one or more channel home page URLs to identify channels to be crawled. Note that both ID-based and handle-based URL formats are supported.<br><br>The crawler will extract the IDs of target videos, shorts and livestreams on the designated channel and the scraper will output a single scraping result for each of them (subject to your configured limits).<br> |
| <strong>Channel content page URL</strong><br><br>https://www.youtube.com/@CHANNEL\_HANDLE/videos<br>https://www.youtube.com/channel/CHANNEL\_ID/videos<br><br><br>https://www.youtube.com/@CHANNEL\_HANDLE/shorts<br>https://www.youtube.com/channel/CHANNEL\_ID/shorts<br><br>https://www.youtube.com/@CHANNEL\_HANDLE/streams<br>https://www.youtube.com/channel/CHANNEL\_ID/streams<br><br> | Enter one or more channel content page URLs to identify a specific channel content type to be crawled (for example, videos).<br><br>The crawler will extract target video IDs from the designated content page and the scraper will output a single scraping result for each of them (subject to your configured limits).<br><br><br><br><br><br> |
| <strong>Channel search page URL</strong><br><br>https://www.youtube.com/@CHANNEL\_HANDLE/search?query=football<br><br>https://www.youtube.com/channel/CHANNEL\_ID/search?query=football<br><br> | Enter one or more channel search page URLs to identify a subset of channel content to be crawled.<br><br>The crawler will extract target video IDs from the search results and the scraper will output a single scraping result for each of them (subject to your configured limits).<br><br><br> |
| <strong>Hashtag page URL</strong><br><br>https://www.youtube.com/hashtag/football<br><br><br><br><br> | Enter one or more YouTube hashtag page URLs to identify a themed selection of content to be crawled.<br><br>The crawler will extract target video IDs from the hashtag results and the scraper will output a single scraping result for each of them (subject to your configured limits).<br> |
| <strong>Global search page URL</strong><br><br>https://www.youtube.com/results?search\_query=football<br><br>https://www.youtube.com/results?search\_query=football\&sp=EgIQAQ<br><br><br><br><br> | Enter one or more global YouTube search query URLs to identify a themed selection of content to be crawled. Search URLs may be copy/pasted directly from your browser and may optionally include filter parameters (which are generated automatically when you apply a filter condition via your browser).<br><br>The crawler will extract target video IDs from the search results and the scraper will output a single scraping result for each of them (subject to your configured limits).<br> |

<br><br>
![Cast Your Vote and Make a Difference](https://i.imgur.com/bt3wfon.png)
[![Leave a Review](https://i.imgur.com/gkYNjKK.png)](/actors/6E4kQL6o4PF9O0ApN/reviews) <br><br>

### 📝 JSON Configuration Template

The following JSON data snippet represents *YouTube Ultimate Scraper*'s default settings. You can use this as a template when creating your own advanced configuration. Simply delete the settings that are not relevant to your use case, then edit what remains to reflect your specific scraping requirements.

```json
{
    "discovery": {
        "videoIds": [],
        "channelIds": [],
        "searchQueries": [],
        "hashtags": [],
        "urls": [],
        "ignoreIds": []
    },
    "crawling": {
        "proxyCountry": "US",
        "searchFilters": {
            "sort": null,
            "recency": null,
            "type": null,
            "duration": null,
            "features": []
        },
        "limits": {
            "maxChannelVideos": 0,
            "maxChannelShorts": 0,
            "maxChannelStreams": 0,
            "maxChannelSearchResults": 0,
            "maxGlobalSearchResults": 0,
            "maxHashtagResults": 0,
            "maxVideoComments": 0,
            "maxCommentReplies": 0
        },
        "listSort": "latest"
    },
    "output": {
        "sort": false,
        "dateFilter" : {
            "start": "1970-01-01T00:00:00",
            "end": "2199-01-01T00:00:00",
        },
        "videoMetadata": {
            "channelId": true,
            "author": true,
            "title": true,
            "description": true,
            "keywords": true,
            "length": true,
            "thumbnails": true,
            "metrics": true,
            "allowRatings": true,
            "isPrivate": true,
            "isLiveContent": true,
            "isUnlisted": true,
            "captionTracks": true,
            "category": true,
            "publishDate": true,
            "ownerChannelName": true,
            "viewCount": true,
            "likeCount": true
        },
        "channelMetadata": {
            "enabled": true,
            "handle": true,
            "title": true,
            "description": true,
            "keywords": true,
            "country": true,
            "avatar": true,
            "joinedDateText": false,
            "joinedDate": true,
            "channelAgeDays": true,
            "channelUrl": true,
            "canonicalUrl": true,
            "rssUrl": true,
            "videosUrl": true,
            "shortsUrl": true,
            "liveUrl": true,
            "playlistsUrl": true,
            "aboutUrl": true,
            "searchUrl": true,
            "ownerUrls": true,
            "links": true,
            "hasBusinessEmailAddress": true,
            "isFamilySafe": true,
            "subscriberCountText": false,
            "subscriberCount": true,
            "viewCountText": false,
            "viewCount": true,
            "videoCountText": false,
            "videoCount": true,
            "averageViewCount": true,
            "availableCountryCodes": true
        },
        "transcript": {
            "enabled": false,
            "language": "en",
            "format": "timeline"
        },
        "comments": {
            "enabled": false,
            "totalCount": true,
            "publishedDateText": false,
            "publishedDate": true,
            "isPinned": true,
            "isHearted": true,
            "hasDonation": true,
            "level": true,
            "authorChannelId": true,
            "authorDisplayName": true,
            "isCreator": true,
            "isVerified": true,
            "likeCount": true,
            "replyCount": true
            "replies": {
                "enabled": false,
                "publishedDateText": false,
                "publishedDate": true,
                "isPinned": true,
                "isHearted": true,
                "hasDonation": true,
                "level": true,
                "authorChannelId": true,
                "authorDisplayName": true,
                "isCreator": true,
                "isVerified": true,
                "likeCount": true
            }
        }
    }
}
```

# Actor input Schema

## `urls` (type: `array`):

The URLs of the YouTube video pages that you want to scrape or other YouTube pages that you want to crawl to discover videos.

## `maxChannelVideos` (type: `integer`):

The maximum number of long-form videos to be retrieved while crawling each target channel. Each video will be subsequently scraped to yield a single video metadata result set.

## `maxChannelShorts` (type: `integer`):

The maximum number of shorts to be retrieved while crawling each target channel. Each short will be subsequently scraped to yield a single video metadata result set.

## `maxChannelStreams` (type: `integer`):

The maximum number of livestreams to be retrieved while crawling each target channel. Each livestream will be subsequently scraped to yield a single video metadata result set.

## `maxChannelSearchResults` (type: `integer`):

The maximum number of videos to be retrieved while crawling each target channel search. Each video will be subsequently scraped to yield a single video metadata result set.

## `maxGlobalSearchResults` (type: `integer`):

The maximum number of videos to be retrieved while crawling each target global search. Each video will be subsequently scraped to yield a single video metadata result set.

## `maxHashtagResults` (type: `integer`):

The maximum number of videos to be retrieved while crawling each target hashtag. Each video will be subsequently scraped to yield a single video metadata result set.

## `maxVideoComments` (type: `integer`):

The maximum number of viewwer comments to be retrieved while scraping each target video.

## `includeChannelMetadata` (type: `boolean`):

Enhance each video result by retrieving metadata relating to the channel that owns it.

## `includeVideoTranscript` (type: `boolean`):

Enhance each video result by retrieving a timestamped transcript of its audio track (where available).

## `includeViewerComments` (type: `boolean`):

Enhance each video result by retrieving some or all of its viewer comments.

## `advancedConfiguration` (type: `object`):

Paste a JSON snippet that represents your custom settings, derived from our JSON settings template.

## Actor input object example

```json
{
  "urls": [
    "https://www.youtube.com/@Apify"
  ],
  "maxChannelVideos": 5,
  "maxChannelShorts": 0,
  "maxChannelStreams": 0,
  "maxChannelSearchResults": 0,
  "maxGlobalSearchResults": 0,
  "maxHashtagResults": 0,
  "maxVideoComments": 0,
  "includeChannelMetadata": false,
  "includeVideoTranscript": false,
  "includeViewerComments": false,
  "advancedConfiguration": {}
}
```

# 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 = {
    "urls": [
        "https://www.youtube.com/@Apify"
    ],
    "maxChannelVideos": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("ultimate/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 = {
    "urls": ["https://www.youtube.com/@Apify"],
    "maxChannelVideos": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("ultimate/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 '{
  "urls": [
    "https://www.youtube.com/@Apify"
  ],
  "maxChannelVideos": 5
}' |
apify call ultimate/youtube-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "YouTube Ultimate Scraper",
        "description": "Scrape videos, comments, replies, transcripts, and channel metadata with YouTube Ultimate Scraper. Designed for flexibility, speed, and reliability, it’s perfect for everything from one-off research to large-scale automation.",
        "version": "1.0",
        "x-build-id": "TT9aRSgKcYFppP2Uk"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/ultimate~youtube-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-ultimate-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/ultimate~youtube-scraper/runs": {
            "post": {
                "operationId": "runs-sync-ultimate-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/ultimate~youtube-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-ultimate-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": {
                    "urls": {
                        "title": "YouTube target page URLs",
                        "type": "array",
                        "description": "The URLs of the YouTube video pages that you want to scrape or other YouTube pages that you want to crawl to discover videos.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxChannelVideos": {
                        "title": "Maximum videos crawled per channel",
                        "minimum": 0,
                        "type": "integer",
                        "description": "The maximum number of long-form videos to be retrieved while crawling each target channel. Each video will be subsequently scraped to yield a single video metadata result set.",
                        "default": 0
                    },
                    "maxChannelShorts": {
                        "title": "Maximum shorts crawled per channel",
                        "minimum": 0,
                        "type": "integer",
                        "description": "The maximum number of shorts to be retrieved while crawling each target channel. Each short will be subsequently scraped to yield a single video metadata result set.",
                        "default": 0
                    },
                    "maxChannelStreams": {
                        "title": "Maximum livestreams crawled per channel",
                        "minimum": 0,
                        "type": "integer",
                        "description": "The maximum number of livestreams to be retrieved while crawling each target channel. Each livestream will be subsequently scraped to yield a single video metadata result set.",
                        "default": 0
                    },
                    "maxChannelSearchResults": {
                        "title": "Maximum videos crawled per channel search",
                        "minimum": 0,
                        "type": "integer",
                        "description": "The maximum number of videos to be retrieved while crawling each target channel search. Each video will be subsequently scraped to yield a single video metadata result set.",
                        "default": 0
                    },
                    "maxGlobalSearchResults": {
                        "title": "Maximum videos crawled per global search",
                        "minimum": 0,
                        "type": "integer",
                        "description": "The maximum number of videos to be retrieved while crawling each target global search. Each video will be subsequently scraped to yield a single video metadata result set.",
                        "default": 0
                    },
                    "maxHashtagResults": {
                        "title": "Maximum videos crawled per hashtag",
                        "minimum": 0,
                        "type": "integer",
                        "description": "The maximum number of videos to be retrieved while crawling each target hashtag. Each video will be subsequently scraped to yield a single video metadata result set.",
                        "default": 0
                    },
                    "maxVideoComments": {
                        "title": "Maximum viewer comments retrieved per video result",
                        "minimum": 0,
                        "type": "integer",
                        "description": "The maximum number of viewwer comments to be retrieved while scraping each target video.",
                        "default": 0
                    },
                    "includeChannelMetadata": {
                        "title": "Include channel metadata",
                        "type": "boolean",
                        "description": "Enhance each video result by retrieving metadata relating to the channel that owns it.",
                        "default": false
                    },
                    "includeVideoTranscript": {
                        "title": "Include transcript",
                        "type": "boolean",
                        "description": "Enhance each video result by retrieving a timestamped transcript of its audio track (where available).",
                        "default": false
                    },
                    "includeViewerComments": {
                        "title": "Include viewer comments",
                        "type": "boolean",
                        "description": "Enhance each video result by retrieving some or all of its viewer comments.",
                        "default": false
                    },
                    "advancedConfiguration": {
                        "title": "Advanced configuration",
                        "type": "object",
                        "description": "Paste a JSON snippet that represents your custom settings, derived from our JSON settings template.",
                        "default": {},
                        "additionalProperties": true
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
