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

Scrape videos, channels, playlists, and search results from YouTube. Extract metadata, subtitles, and channel info.

- **URL**: https://apify.com/beautifulscrape/youtube-scraper.md
- **Developed by:** [Beautiful Scrape](https://apify.com/beautifulscrape) (community)
- **Categories:** Automation, SEO tools, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

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

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

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

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

# README

## YouTube Scraper

Scrape public data from YouTube — videos, channels, playlists, and search results — beyond what the YouTube Data API allows.

### What does YouTube Scraper do?

YouTube Scraper extracts public data from YouTube pages. It can scrape video metadata, channel information, playlist contents, and search results in bulk.

- Extract video titles, descriptions, view counts, likes, comments count, duration, and more
- Scrape channel info: subscriber count, total videos, total views, description, location, join date
- Break down playlists and enumerate all videos
- Search YouTube by keywords with filtering and sorting
- Download subtitles and transcripts (auto-generated or user-uploaded)
- Export data in JSON, CSV, Excel, or HTML via the Apify platform

### What data can you scrape from YouTube?

| Field | Description |
|---|---|
| 📺 Channel name | Name of the video's channel |
| 👍 Likes | Number of likes on the video |
| 📝 Video title | Title of the video |
| 💬 Comments count | Total number of comments |
| 🔗 Video URL | Direct link to the video |
| 📍 Channel location | Geographic location of the channel |
| 🖍 Subtitles | Auto-generated and user-uploaded transcripts |
| 🌐 Channel URL | Link to the channel page |
| 📼 Total videos | Number of videos on the channel |
| 👁️ View count | Number of views on the video |
| 👀 Total views | Total views across all channel videos |
| 📈 Subscribers | Number of channel subscribers |
| ⏱️ Duration | Length of the video |
| 📅 Publish date | When the video was uploaded |
| #️⃣ Hashtags | Hashtags associated with the video |
| 📽️ Thumbnails | Video thumbnail URLs |

### How to scrape YouTube data

1. Create a free [Apify account](https://apify.com/) using your email.
2. Open YouTube Scraper.
3. Add one or more YouTube URLs or search terms.
4. Click the **Start** button and wait for the data to be extracted.
5. Download your data in JSON, CSV, Excel, or HTML.

### Input

You can configure the scraper through the Apify Console UI or by providing a JSON input.

#### Start URLs

Paste YouTube URLs to scrape. Supports:

- **Video URLs**: `https://www.youtube.com/watch?v=...`
- **Channel URLs**: `https://www.youtube.com/@ChannelName`
- **Playlist URLs**: `https://www.youtube.com/playlist?list=...`
- **Search result URLs**: `https://www.youtube.com/results?search_query=...`
- **Shorts**: `https://www.youtube.com/shorts/...`
- **Live streams**: `https://www.youtube.com/live/...`

#### Search keywords

Search YouTube by typing keywords just like you would in the YouTube search bar. Each keyword produces a separate set of results.

#### Result limits

| Parameter | Default | Description |
|---|---|---|
| `maxResults` | 10 | Max regular videos per URL/search |
| `maxResultsShorts` | 0 | Max Shorts (search only) |
| `maxResultStreams` | 0 | Max live streams (search only) |

#### Filtering by date

**When scraping by search term**: Use `searchDateFilter` to filter by `hour`, `day`, `week`, `month`, or `year`.

**When scraping by channel URL**: Use `oldestPostDate` with relative values like `3 days`, `1 week`, `2 months`, or absolute dates like `2024-01-15`.

#### Sorting

**Channel videos**: Use `channelSortBy` — `newest` (default), `popular`, or `oldest`.

**Search results**: Use `searchSortBy` — `relevance`, `date`, `viewCount`, or `rating`.

#### Subtitles

Enable subtitle extraction with `downloadSubtitles: true`. Configure:

| Parameter | Default | Description |
|---|---|---|
| `subtitlesLanguage` | `"en"` | Preferred language code |
| `subtitlesFormat` | `"plaintext"` | Format: `plaintext`, `srt`, or `vtt` |
| `preferAutoGeneratedSubtitles` | `false` | Prefer auto-generated over user-uploaded |
| `saveSubsToKVS` | `false` | Save to Apify key-value store with URL reference |

#### Input example

```json
{
    "startUrls": [
        { "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }
    ],
    "maxResults": 10,
    "downloadSubtitles": true,
    "subtitlesFormat": "plaintext"
}
```

Search example:

```json
{
    "searchKeywords": ["web scraping tutorial"],
    "maxResults": 20,
    "maxResultsShorts": 5,
    "searchSortBy": "date",
    "searchDateFilter": "month"
}
```

### Output

Results are pushed to the Apify dataset. You can download them in JSON, CSV, Excel, or HTML.

#### Single video

```json
{
    "title": "Stromae - Santé (Live)",
    "id": "CW7gfrTlr0Y",
    "url": "https://www.youtube.com/watch?v=CW7gfrTlr0Y",
    "thumbnailUrl": "https://i.ytimg.com/vi/CW7gfrTlr0Y/maxresdefault.jpg",
    "viewCount": 35582192,
    "date": "2021-12-21T00:00:00.000Z",
    "likes": 512238,
    "duration": "00:03:17",
    "type": "video",
    "channelName": "StromaeVEVO",
    "channelUrl": "https://www.youtube.com/@StromaeVEVO",
    "numberOfSubscribers": 6930000,
    "commentsCount": 14,
    "text": "Stromae - Santé (Live From The Tonight Show...)",
    "descriptionLinks": [
        { "url": "https://stromae.lnk.to/la-solassitude", "text": "https://stromae.lnk.to/la-solassitude" }
    ],
    "isMonetized": null,
    "commentsTurnedOff": false,
    "hashtags": ["#Stromae", "#Santé"],
    "isAgeRestricted": false
}
```

#### Channel scrape

When scraping a channel, results include channel-level metadata:

```json
{
    "id": "HV6OlMPn5sI",
    "title": "Raimu - The Spirit Within",
    "duration": "29:54",
    "channelName": "Lofi Girl",
    "channelUrl": "https://www.youtube.com/@LofiGirl",
    "date": "2024-01-15T00:00:00.000Z",
    "viewCount": 410458,
    "fromYTUrl": "https://www.youtube.com/@LofiGirl/videos",
    "numberOfSubscribers": 13100000,
    "channelDescription": "That girl studying by the window non-stop...",
    "channelJoinedDate": "Mar 18, 2015",
    "channelLocation": "France",
    "channelTotalVideos": 409,
    "channelTotalViews": 1710167563,
    "isChannelVerified": true
}
```

#### Playlist scrape

```json
{
    "id": "CdgDLaxe2Q4",
    "title": "Lecture 4 | String Theory and M-Theory",
    "duration": "1:23:37",
    "channelName": "Stanford",
    "channelUrl": "https://www.youtube.com/@stanford",
    "url": "https://www.youtube.com/watch?v=CdgDLaxe2Q4&list=PL6i60qoDQhQG...&index=4",
    "viewCount": 106000,
    "fromYTUrl": "https://www.youtube.com/playlist?list=PL6i60qoDQhQG...",
    "order": 4
}
```

#### Search results

```json
{
    "id": "CwRMBKk8St0",
    "title": "LET'S ARGUE: Beyoncé Fails the Bechdel Test!",
    "duration": "13:48",
    "channelName": "fantano",
    "channelUrl": "https://www.youtube.com/@fantano",
    "viewCount": 635379,
    "fromYTUrl": "https://www.youtube.com/results?search_query=bechdel+test",
    "type": "video",
    "order": 1
}
```

#### Subtitles

When `downloadSubtitles` is enabled, the `subtitles` field contains:

```json
{
    "subtitles": [
        {
            "srtUrl": "https://api.apify.com/v2/key-value-stores/.../records/subtitles_abc_en_auto_generated",
            "type": "auto_generated",
            "language": "en",
            "srt": "1\n00:00:0,320 --> 00:00:4,960\nEver feel like you've been chasing the wrong path?..."
        }
    ]
}
```

### Error items

When the scraper cannot retrieve data for a given input, it pushes an error item to the dataset instead of silently skipping it. You can identify errors by the presence of an `error` field.

```json
{
    "url": "https://www.youtube.com/@somechannel",
    "input": "somechannel",
    "error": "CHANNEL_DOES_NOT_EXIST",
    "note": "Channel does not exist"
}
```

#### Error codes

| Error code | Meaning |
|---|---|
| `CHANNEL_DOES_NOT_EXIST` | Channel URL points to a channel that does not exist |
| `NOT_FOUND` | Page was not found |
| `VIDEO_UNAVAILABLE` | Video is not available (deleted, region-blocked, etc.) |
| `AGE_RESTRICTED` | Video is age-restricted and cannot be accessed without login |
| `CHANNEL_HAS_NO_VIDEOS` | Channel exists but has no uploaded videos |
| `CHANNEL_HAS_NO_LIVE_VIDEOS` | Channel exists but has no live videos |
| `CHANNEL_HAS_NO_SHORTS` | Channel exists but has no Shorts |
| `DATE_FILTER_TOO_STRICT` | Videos exist but none match the active date filter |
| `NO_VIDEOS` | No videos found on the page |
| `NO_RESULTS` | No results collected — check that video-type limits are set above 0 |
| `NO_VALID_START_URLS` | All provided start URLs were invalid or malformed |
| `INVALID_INPUT` | Actor failed due to bad configuration |

### FAQ

**Can I scrape dislikes from YouTube videos?**
No. Dislikes are not public information and cannot be scraped.

**Can I scrape subtitles from YouTube videos?**
Yes. Enable `downloadSubtitles` in the input to extract both auto-generated and user-uploaded subtitles in SRT, WebVTT, or plain text format.

**Can I scrape YouTube Shorts and live streams?**
Yes. When scraping by search term, set `maxResultsShorts` and/or `maxResultStreams` above 0. When scraping by direct URL, Shorts and live stream URLs are automatically detected.

**How to filter videos by date?**
When scraping by search term, use `searchDateFilter`. When scraping by channel URL, use `oldestPostDate`.

**Can I integrate this scraper with other apps?**
Yes. The Apify platform supports integrations with Make, Zapier, Slack, Google Drive, and many more. You can also use webhooks or the Apify API.

# Actor input Schema

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

YouTube URLs to scrape. Supports video, channel, playlist, and search result URLs.

## `searchKeywords` (type: `array`):

Search YouTube by keywords, just like you would in the YouTube search bar. Each keyword will produce a separate set of results.

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

Maximum number of regular videos to return per URL or search term.

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

Maximum number of Shorts to return. Only applies when scraping by search term.

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

Maximum number of live streams to return. Only applies when scraping by search term.

## `oldestPostDate` (type: `string`):

Only return videos published after this date. Accepts relative values like '3 days', '1 week', '2 months', or absolute dates like '2024-01-15'. Applicable only to scraping by channel URL.

## `channelSortBy` (type: `string`):

How to sort videos when scraping a channel.

## `searchSortBy` (type: `string`):

How to sort search results.

## `searchDateFilter` (type: `string`):

Filter search results by upload date.

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

Whether to download subtitles/transcripts for videos.

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

Preferred subtitle language code (e.g. 'en', 'es', 'fr').

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

Output format for downloaded subtitles.

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

If enabled, auto-generated subtitles will be preferred over user-uploaded ones.

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

If enabled, subtitles will be saved to the Apify key-value store as separate files, and a URL reference will be included in the output.

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

Filter: only return videos with closed captions.

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

Filter: only return videos with subtitles.

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

Filter: only return HD videos.

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

Filter: only return 4K videos.

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

Filter: only return HDR videos.

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

Filter: only return live videos.

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

Filter: only return 360° videos.

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

Filter: only return 3D videos.

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

Filter: only return VR180 videos.

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

Filter: only return purchased videos.

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

Filter: only return videos with location data.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    }
  ],
  "maxResults": 10,
  "maxResultsShorts": 0,
  "maxResultStreams": 0,
  "channelSortBy": "newest",
  "downloadSubtitles": false,
  "subtitlesLanguage": "en",
  "subtitlesFormat": "plaintext",
  "preferAutoGeneratedSubtitles": false,
  "saveSubsToKVS": false,
  "hasCC": false,
  "hasSubtitles": false,
  "isHD": false,
  "is4K": false,
  "isHDR": false,
  "isLive": false,
  "is360": false,
  "is3D": false,
  "isVR180": false,
  "isBought": false,
  "hasLocation": false
}
```

# Actor output Schema

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

No description

# API

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

## JavaScript example

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

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

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

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

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

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

```

## Python example

```python
from apify_client import ApifyClient

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

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

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

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    }
  ]
}' |
apify call beautifulscrape/youtube-scraper --silent --output-dataset

```

## MCP server setup

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

```

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

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ErIXZmIeNR1YQ81Pd/builds/Y0B5xbBfFidW383RX/openapi.json
