# YouTube Channel Scraper (`apihq/youtube-channel-scraper`) Actor

Export a YouTube channel's long-form videos to JSON by URL, @handle, or channel ID. No YouTube Data API key or quota. One record per video with views, date, duration, and thumbnail. Pay-per-video: a channel that can't be resolved returns a success:false row and is not charged.

- **URL**: https://apify.com/apihq/youtube-channel-scraper.md
- **Developed by:** [apihq](https://apify.com/apihq) (community)
- **Categories:** Videos, Social media, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.50 / 1,000 videos

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

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

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

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

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

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

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

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

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

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

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

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

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


# README

## YouTube Channel Scraper

Export a public YouTube channel's long-form videos as clean JSON, from a channel URL, @handle, or channel ID. No YouTube Data API key, no quota, no browser.

The contract is simple: **a bad channel never fails your run, and you only pay for videos delivered.** Misspell a handle, paste a video URL by mistake, or hit a channel with no uploads, and it comes back as a `success: false` row while the rest of the batch keeps going. Pay-per-result at $0.50 per 1,000 videos. Failed channels cost $0.

### See one run

Input:

```json
{ "channelUrls": ["@MrBeast", "@totally-wrong-handle"], "maxResults": 5 }
````

What comes back:

- 5 `success: true` video rows from `@MrBeast`, billed
- 1 `success: false` row, `code: CHANNEL_NOT_FOUND`, for the bad handle, not billed
- Run status: **SUCCEEDED**
- Charged: 5 videos = $0.0025

That is the whole contract. Good input returns billed rows, bad input returns free error rows in the same dataset, and the run still succeeds so one typo never costs you a batch.

### Why this Actor

- **A bad channel never breaks the batch.** Every channel that cannot be resolved or listed returns a `success: false` record with a machine-readable `code` (`CHANNEL_NOT_FOUND`, `NO_VIDEOS`, `VALIDATION_FAILED`, `RESOLVE_TIMEOUT`, `CHANNEL_VIDEOS_TIMEOUT`, `DEADLINE_EXCEEDED`). Branch on `code` without parsing English.
- **You pay only for videos.** Billing fires on an explicit per-video event, not on dataset writes, so failure rows sit in your dataset for free.
- **No YouTube Data API key, no quota.** The official YouTube Data API needs a Google key and rations a daily quota per call. This reads public data directly, so there is no Google key to provision and no daily Data API quota to ration. (You still run it with your normal Apify account, like any Actor.)

### Best for

Data and AI workflows that turn channels into video datasets: creator databases, competitor monitoring, content-enrichment pipelines, and collecting video IDs to feed transcript or comment jobs. The failure-free billing and machine-readable error rows matter most when the extraction runs unattended inside a larger pipeline, where one bad channel should never take down the batch. It works fine for one-off manual pulls too.

### Input example

A single channel:

```json
{
  "channelUrl": "https://www.youtube.com/@MrBeast",
  "maxResults": 50
}
```

A batch, mixing URL, @handle, and channel ID forms:

```json
{
  "channelUrls": [
    "https://www.youtube.com/@MrBeast",
    "@mkbhd",
    "UCX6OQ3DkcsbYNE6H8uQQuVA"
  ],
  "maxResults": 100
}
```

`channelUrl` and `channelUrls` are merged and de-duplicated. Up to 50 unique channels run per job. Each channel is walked newest-first up to `maxResults` videos (default 50).

### Output example

One record per video. The channel's id and name are copied onto every row so each row stands alone:

```json
{
  "success": true,
  "channel_id": "UCX6OQ3DkcsbYNE6H8uQQuVA",
  "channel_title": "MrBeast",
  "video_id": "iYlODtkyw_I",
  "title": "Spend 30 Days Handcuffed To A Stranger",
  "url": "https://www.youtube.com/watch?v=iYlODtkyw_I",
  "published": "2 weeks ago",
  "view_count": "55M views",
  "duration": 2105,
  "thumbnail_url": "https://i.ytimg.com/vi/iYlODtkyw_I/hqdefault.jpg",
  "author": "MrBeast"
}
```

A channel that cannot be resolved lands in the same dataset and is not charged:

```json
{
  "success": false,
  "channel_url": "@totally-wrong-handle",
  "code": "CHANNEL_NOT_FOUND",
  "error": "Could not resolve YouTube channel: @totally-wrong-handle",
  "request_id": "req_911f37d2e55644ff9d9e4a3f",
  "status_code": 404
}
```

Split hits from misses on the `success` field. Quote `request_id` in any support issue and we can trace the exact request.

### What you get

Every video is one record with `success: true`:

| Field | Type | What it is |
|---|---|---|
| `success` | boolean | `true` for a video (billed), `false` for a channel that could not be listed (not billed). |
| `channel_id` | string | The `UC...` channel ID the video belongs to. |
| `channel_title` | string | The channel's display name. |
| `video_id` | string | The 11-character YouTube video ID. |
| `title` | string | Video title. |
| `url` | string | Canonical watch URL. |
| `published` | string | Relative publish string YouTube shows (for example `2 weeks ago`). |
| `view_count` | string | View count as a display string. |
| `duration` | integer | Video length in seconds. Absent for live streams and unparseable lengths. |
| `thumbnail_url` | string | URL of the largest available thumbnail. |
| `author` | string | Channel author name. |

Channels that could not be listed carry `success: false`, `channel_url`, a machine-readable `code`, a human-readable `error`, the service `request_id`, and the HTTP `status_code`. They are not charged.

### Pricing

Pay-per-result. One charge per video delivered: `$0.0005` each, which is `$0.50 per 1,000 videos`. The charge fires only after a video row lands in your dataset.

- 1,000 delivered videos cost $0.50.
- A run that hits ten dead handles and returns zero videos costs $0.

Apify subscriber discounts apply automatically: roughly `$0.40 per 1,000` on the Scale plan and `$0.30 per 1,000` on Business. Platform compute is included in the per-video price. Cap the maximum spend of a single run from Apify's Run Limits panel; the Actor honors the cap and stops cleanly mid-walk when the budget runs out.

### What this Actor does not do

Honest scope, so you know before you run it:

- **It reads the channel's Videos tab (long-form uploads), not Shorts.** That keeps output focused on regular videos and avoids mixing formats. For Shorts, use a Shorts-specific Actor.
- **It returns videos newest first.** There is no sort by popularity or oldest.
- **It returns channel identity (id and name), not channel statistics.** Subscriber totals, lifetime views, and channel-level counts are out of scope.

### How to use this Actor

1. Open the Actor in the Apify Console.
2. Set `channelUrl` (single), `channelUrls` (a list), or both. Each accepts a full channel URL, an `@handle`, or a `UC...` channel ID. Up to 50 unique channels run per job.
3. Set `maxResults` to cap how many videos to return per channel, newest first. Default is 50.
4. Click Start. Each video is one `success: true` record. Channels that cannot be listed produce one `success: false` record and do not stop the run. Only videos are charged.

The Actor is also callable from the Apify API and every official integration (Make, Zapier, n8n, Slack, webhooks). The API tab in the Console has ready-to-paste JavaScript, Python, and curl snippets.

### Reliability

**A bad channel never fails the batch.** A misspelled handle, a video URL pasted by mistake, or a channel with no uploads becomes a `success: false` record with a specific `code`. The run keeps going and finishes successfully.

**You never pay for a failure.** Billing fires on an explicit per-video charge event, not on dataset writes, so `success: false` records are free.

**Hard 30-second deadline per page request.** Each page of a channel is fetched under a 30-second deadline. If YouTube or the proxy network stalls, that channel returns a `504` with `code: DEADLINE_EXCEEDED` as a `success: false` record instead of hanging your run.

### FAQ

**Do I need a YouTube Data API key?**

No. The Actor reads YouTube's public data directly and does not consume Google API quota.

**What channel formats are accepted?**

A full channel URL (`https://www.youtube.com/@MrBeast` or `.../channel/UC...`), an `@handle`, or a bare `UC...` channel ID. A video URL or unrecognizable input comes back as a `success: false` record with `code: VALIDATION_FAILED`, not a rejected run.

**How many videos do I get per channel?**

Up to `maxResults`, newest first. The Actor walks the channel's Videos tab page by page until it reaches `maxResults` or the channel runs out. Set `maxResults` higher to go deeper.

**Does this include Shorts?**

No. This Actor lists a channel's long-form videos. For Shorts, use a Shorts-specific Actor.

**Can I get transcripts too?**

Not from this Actor. Use it to collect a channel's video IDs, then run the [YouTube Transcript Scraper](https://apify.com/apihq/youtube-transcript-scraper) on those IDs to pull captions.

**Can I use this Actor from my own code?**

Yes. Use the Apify API or one of the official SDKs (Node.js: `apify-client`, Python: `apify-client`). The Console shows ready-to-paste code samples on the API tab.

**How does billing know a channel failed?**

Billing fires on an explicit per-video charge event, not on dataset writes. The Actor only fires it when a video is delivered, so `success: false` records sit in your dataset for free. You get every result in one place and still branch on `success` and `code`, with a `request_id` for support correlation.

### Found a bug or want a feature?

Open an issue on this Actor's Issues tab and include the `request_id` from any error record you saw. We respond within one business day.

# Actor input Schema

## `channelUrl` (type: `string`):

A single YouTube channel. Accepts a full channel URL (https://www.youtube.com/@MrBeast or /channel/UC...), an @handle, or a UC... channel ID. A channel that can't be resolved comes back as a success:false record (code CHANNEL\_NOT\_FOUND), not a rejected run.

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

List of channel URLs, @handles, or channel IDs. Merged with channelUrl and de-duplicated; up to 50 unique channels are processed per run. A channel that can't be resolved comes back as a success:false record, so one bad channel never blocks the batch.

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

Maximum number of videos to return per channel (newest first). The Actor walks the channel's Videos tab in pages until it reaches this many videos or the channel is exhausted.

## Actor input object example

```json
{
  "channelUrl": "https://www.youtube.com/@MrBeast",
  "maxResults": 50
}
```

# Actor output Schema

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

One record per video. success:true carries the video and channel fields; success:false carries the error code and message for a channel that failed.

# 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 = {
    "channelUrl": "https://www.youtube.com/@MrBeast",
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("apihq/youtube-channel-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 = {
    "channelUrl": "https://www.youtube.com/@MrBeast",
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("apihq/youtube-channel-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 '{
  "channelUrl": "https://www.youtube.com/@MrBeast",
  "maxResults": 50
}' |
apify call apihq/youtube-channel-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "YouTube Channel Scraper",
        "description": "Export a YouTube channel's long-form videos to JSON by URL, @handle, or channel ID. No YouTube Data API key or quota. One record per video with views, date, duration, and thumbnail. Pay-per-video: a channel that can't be resolved returns a success:false row and is not charged.",
        "version": "0.1",
        "x-build-id": "P8LHG5agr651rOA1b"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/apihq~youtube-channel-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-apihq-youtube-channel-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/apihq~youtube-channel-scraper/runs": {
            "post": {
                "operationId": "runs-sync-apihq-youtube-channel-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/apihq~youtube-channel-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-apihq-youtube-channel-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": {
                    "channelUrl": {
                        "title": "Channel URL, @handle, or ID",
                        "type": "string",
                        "description": "A single YouTube channel. Accepts a full channel URL (https://www.youtube.com/@MrBeast or /channel/UC...), an @handle, or a UC... channel ID. A channel that can't be resolved comes back as a success:false record (code CHANNEL_NOT_FOUND), not a rejected run."
                    },
                    "channelUrls": {
                        "title": "Multiple channels",
                        "type": "array",
                        "description": "List of channel URLs, @handles, or channel IDs. Merged with channelUrl and de-duplicated; up to 50 unique channels are processed per run. A channel that can't be resolved comes back as a success:false record, so one bad channel never blocks the batch.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxResults": {
                        "title": "Max videos per channel",
                        "type": "integer",
                        "description": "Maximum number of videos to return per channel (newest first). The Actor walks the channel's Videos tab in pages until it reaches this many videos or the channel is exhausted."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
