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

Collect public YouTube channel profiles from handles or URLs — subscribers, description, avatar, country, and channel stats. Optionally add videos and Shorts with views, likes, duration, and thumbnails. Output as separate dataset rows (channel, video, short) or one nested record per channel.

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

## Pricing

from $0.10 / 1,000 channel profile collecteds

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

## 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

Collect structured data from public [YouTube](https://www.youtube.com) **channel** pages using handles or channel URLs. Add one or more channels, start a run, and receive clean JSON in your Apify dataset — no YouTube login required.

Use it for **creator research**, **competitive intelligence**, **influencer outreach**, **content monitoring**, **market research**, **lead enrichment**, and **automation workflows** — without copying channel profiles, video lists, or Shorts manually.

---

### What you get

Every run always collects **channel profile data** (subscribers, description, avatar, country, and more). You can optionally add **videos** from the channel’s Videos tab and **Shorts** from the Shorts tab.

| Section                   | What it contains                                                                                                 |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **Channel profile**       | Name, handle, URL, subscriber count, video count, total views, avatar, country, description, verification status |
| **`videos`** _(optional)_ | Regular uploads with title, URL, publish date, duration, views, likes, comments, thumbnails                      |
| **`shorts`** _(optional)_ | Short-form uploads with the same enriched fields                                                                 |
| **`summary`**             | How many videos and Shorts were requested vs collected                                                           |
| **`warnings`**            | User-friendly notes when part of a channel could not be loaded                                                   |

Results are saved to the dataset **as each channel is processed**, so you can preview progress before the run finishes.

---

### Quick start on Apify

1. Open the Actor in the Apify Console.
2. Under **Channel handles and links**, add one or more YouTube channels (one per line).
3. Choose your **output format** — separate dataset rows per channel / video / Short (default), or one row per channel with nested arrays.
4. Enable **Include channel videos** and/or **Include channel Shorts** if you need uploads, and set the per-channel limits.
5. Click **Start** and open the **Dataset** tab as results are saved.

**Supported input formats:**

- Handle: `@apify`
- Channel URL: `https://www.youtube.com/@apify`
- Legacy URLs: `https://www.youtube.com/channel/UC…`, `/c/…`, `/user/…`

**Example input:**

```json
{
  "channelInputs": ["@apify", "https://www.youtube.com/@apify"],
  "separateChannelRecords": true,
  "includeChannelVideos": true,
  "includeChannelShorts": true,
  "maxChannelVideos": 20,
  "maxChannelShorts": 20,
  "channelDateRangeSortBy": "latest",
  "channelDateRangeDate": ""
}
````

***

### Input parameters

#### Channel handles and links

|              |                                                                              |
| ------------ | ---------------------------------------------------------------------------- |
| **Field**    | `channelInputs`                                                              |
| **Type**     | List of text entries (one channel per line)                                  |
| **Required** | Yes — at least one entry                                                     |
| **Formats**  | `@handle`, `youtube.com/@handle`, `youtube.com/channel/…`, `/c/…`, `/user/…` |

Duplicate channels in the same run are processed once.

Unsupported entries are skipped with a log message.

#### Output format

| Field                    | Default | Description                                                                                                                                                                                                                                          |
| ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `separateChannelRecords` | `true`  | When enabled, the dataset uses **separate rows** for each channel (`type: channel`), video (`type: video`), and Short (`type: short`). When disabled, you get **one row per channel** with optional `videos` and `shorts` arrays on the same object. |

#### Videos and Shorts (optional)

| Field                  | Default | Description                                                                          |
| ---------------------- | ------- | ------------------------------------------------------------------------------------ |
| `includeChannelVideos` | `false` | Collect items from the channel’s **Videos** tab                                      |
| `includeChannelShorts` | `false` | Collect items from the channel’s **Shorts** tab                                      |
| `maxChannelVideos`     | `10`    | Maximum videos per channel (1–2,000). Applies only when video collection is enabled  |
| `maxChannelShorts`     | `10`    | Maximum Shorts per channel (1–2,000). Applies only when Shorts collection is enabled |

The video and Short limits apply **independently per channel**. For example, 5 channels with `maxChannelVideos: 20` and `maxChannelShorts: 20` can return up to **100 videos** and **100 Shorts** in total (plus 5 channel profile rows when using separate records).

#### Sorting and date filter (videos only)

| Field                    | Default   | Description                                                                                                                                                                                                      |
| ------------------------ | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `channelDateRangeSortBy` | `latest`  | Order for tab results: `latest`, `popular`, or `oldest`                                                                                                                                                          |
| `channelDateRangeDate`   | *(empty)* | Optional publish-time filter for **videos only**. Use `YYYY-MM-DD` or relative values such as `2 weeks`, `3 months`, `1 year`. When set, sorting is automatically forced to **Latest**. Does not apply to Shorts |

***

### What you will see during a run

Messages describe collection progress and outcomes.

Typical messages:

- `Starting collection for N channel(s).`
- `Prepared 41 dataset item(s) for channel 1 of 2 (Apify).` when **Separate dataset records** is enabled
- `Prepared channel result 1 of 2 (Apify).` when results are nested on one row per channel
- `Collection finished with N dataset item(s).`
- `N unsupported channel input(s) will be skipped.`

If one channel cannot be fully loaded, other channels in the same run can still succeed. Check the **`status`** and **`warnings`** fields on each channel result.

On the Apify **free plan**, you may also see notices when free-tier limits apply (see [Free plan limits](#free-plan-limits)).

***

### Output overview

#### Dataset structure

Results are saved to a **single Apify dataset**.

**Separate records (default)** — filter by `type`:

| `type`    | One row represents                                    |
| --------- | ----------------------------------------------------- |
| `channel` | Channel profile + `summary` + optional `warnings`     |
| `video`   | One regular video, with parent channel context fields |
| `short`   | One Short, with parent channel context fields         |

**Nested records** (`separateChannelRecords: false`) — one row per input channel:

- Channel profile fields at the top level
- Optional `videos` and `shorts` arrays on the same object
- `summary` counts on the channel row

#### Status values

| `status`        | Meaning                                                      |
| --------------- | ------------------------------------------------------------ |
| `ok`            | Channel profile (and requested media) collected successfully |
| `partial`       | Channel or media collected with warnings — see `warnings`    |
| `failed`        | Channel could not be processed — see `error` or `warnings`   |
| `invalid_input` | Input was not a supported channel handle or URL              |

Field presence varies by channel. Not every channel publishes country, full descriptions, or complete stats on the public page. Missing optional fields are omitted from the output.

***

### Output fields

#### Channel record (`type: channel`, or nested mode)

| Field              | Description                                                                |
| ------------------ | -------------------------------------------------------------------------- |
| `type`             | `channel` (separate records mode only)                                     |
| `inputValue`       | Original input string for this channel                                     |
| `channelUrl`       | Normalized channel URL                                                     |
| `status`           | `ok`, `partial`, `failed`, or `invalid_input`                              |
| `error`            | Short explanation when collection failed or input was invalid              |
| `id`               | YouTube channel ID (`UC…`)                                                 |
| `name`             | Channel display name                                                       |
| `handle`           | Public handle (for example `@apify`)                                       |
| `url`              | Canonical channel URL                                                      |
| `isVerified`       | Whether the channel shows a verification badge                             |
| `subscriberCount`  | Subscriber count as a number when available                                |
| `videoCountText`   | Public video count label from YouTube                                      |
| `totalViewsText`   | Total channel views label when shown                                       |
| `avatarUrl`        | Channel avatar image URL                                                   |
| `country`          | Country code when published                                                |
| `description`      | Full channel description                                                   |
| `shortDescription` | Short description when available                                           |
| `sortBy`           | Sort applied when collecting videos or Shorts                              |
| `dateRange`        | Date filter applied to videos, if any                                      |
| `videos`           | Array of video objects *(nested mode only, when enabled)*                  |
| `shorts`           | Array of Short objects *(nested mode only, when enabled)*                  |
| `summary`          | `videosRequested`, `shortsRequested`, `videosCollected`, `shortsCollected` |
| `warnings`         | List of user-friendly warning messages                                     |
| `collectedAt`      | ISO timestamp when the record was saved                                    |

#### Video / Short record (`type: video` or `type: short`)

| Field             | Description                                         |
| ----------------- | --------------------------------------------------- |
| `type`            | `video` or `short`                                  |
| `inputValue`      | Original channel input                              |
| `channelUrl`      | Parent channel URL                                  |
| `channelId`       | Parent channel ID                                   |
| `channelName`     | Parent channel name                                 |
| `channelHandle`   | Parent channel handle                               |
| `id`              | Video or Short ID                                   |
| `url`             | Watch or Shorts URL                                 |
| `title`           | Title                                               |
| `description`     | Description when available                          |
| `publishedDate`   | ISO publish timestamp                               |
| `durationSeconds` | Duration in seconds                                 |
| `viewCount`       | View count                                          |
| `likeCount`       | Like count when available                           |
| `commentCount`    | Comment count when available                        |
| `thumbnailUrl`    | Primary thumbnail URL                               |
| `thumbnails`      | Array of thumbnail sizes (`url`, `width`, `height`) |
| `isLive`          | Whether the item is live content                    |
| `isUpcoming`      | Whether the item is an upcoming premiere            |
| `collectedAt`     | ISO timestamp when the record was saved             |

#### Nested `videos` / `shorts` array items

Same fields as the video / Short rows above, **without** the `type` and parent channel context fields (those live on the parent channel object).

***

### Example output

The excerpts below are from real runs against public YouTube channels. Your run dataset will contain the full records.

#### Example input

```json
{
  "channelInputs": ["https://www.youtube.com/@apify"],
  "separateChannelRecords": true,
  "includeChannelVideos": true,
  "includeChannelShorts": true,
  "maxChannelVideos": 20,
  "maxChannelShorts": 20
}
```

#### Excerpt — separate records: channel row

When **Separate dataset records** is enabled (`separateChannelRecords: true`):

```json
{
  "inputValue": "https://www.youtube.com/@apify",
  "channelUrl": "https://www.youtube.com/@apify",
  "status": "ok",
  "sortBy": "latest",
  "summary": {
    "videosRequested": 20,
    "shortsRequested": 20,
    "videosCollected": 20,
    "shortsCollected": 20
  },
  "collectedAt": "2026-06-29T17:59:37+00:00",
  "id": "UCTgwcoeGGKmZ3zzCXN2qo_A",
  "name": "Apify",
  "handle": "@apify",
  "url": "https://www.youtube.com/@apify",
  "isVerified": true,
  "subscriberCount": 14400,
  "videoCountText": "255",
  "totalViewsText": "9989847",
  "avatarUrl": "https://yt3.ggpht.com/taqvhsquq1iG09A82lJy_qSjXUmvQB0Tm-kAPIxgg0pv1fqSwvZ7ZNWhkWZ1Ias1_mZrllnNsQ4=s800-c-k-c0x00ffffff-no-rj",
  "country": "CZ",
  "description": "Welcome to Apify’s official YouTube channel! Apify is a web scraping and automation platform...",
  "shortDescription": "Welcome to Apify’s official YouTube channel! Apify is a web scraping and automation platform...",
  "type": "channel"
}
```

#### Excerpt — separate records: video row

```json
{
  "type": "video",
  "collectedAt": "2026-06-29T17:59:37+00:00",
  "inputValue": "https://www.youtube.com/@apify",
  "channelUrl": "https://www.youtube.com/@apify",
  "channelId": "UCTgwcoeGGKmZ3zzCXN2qo_A",
  "channelName": "Apify",
  "channelHandle": "@apify",
  "id": "faf4ouwGykc",
  "url": "https://www.youtube.com/watch?v=faf4ouwGykc",
  "title": "I Scraped 90 YouTube Videos to See What's Actually Winning",
  "publishedDate": "2026-06-17T17:00:22Z",
  "durationSeconds": 230,
  "viewCount": 332,
  "likeCount": 15,
  "commentCount": 1,
  "thumbnailUrl": "https://i.ytimg.com/vi/faf4ouwGykc/maxresdefault.jpg",
  "isLive": false,
  "isUpcoming": false
}
```

#### Excerpt — separate records: Short row

```json
{
  "type": "short",
  "collectedAt": "2026-06-29T17:59:37+00:00",
  "inputValue": "https://www.youtube.com/@apify",
  "channelUrl": "https://www.youtube.com/@apify",
  "channelId": "UCTgwcoeGGKmZ3zzCXN2qo_A",
  "channelName": "Apify",
  "channelHandle": "@apify",
  "id": "LUTaRsyFzno",
  "url": "https://www.youtube.com/shorts/LUTaRsyFzno",
  "title": "Watch Klára’s full presentation on our channel! 🏠📈 #apify #praguecrawl #dev",
  "publishedDate": "2026-06-24T11:44:01Z",
  "durationSeconds": 53,
  "viewCount": 877,
  "likeCount": 7,
  "commentCount": 0,
  "thumbnailUrl": "https://i.ytimg.com/vi/LUTaRsyFzno/maxresdefault.jpg",
  "isLive": false,
  "isUpcoming": false
}
```

#### Excerpt — nested single record per channel

When **Separate dataset records** is disabled (`separateChannelRecords: false`), each channel is one dataset row with optional `videos` and `shorts` arrays:

```json
{
  "inputValue": "https://www.youtube.com/@apify",
  "channelUrl": "https://www.youtube.com/@apify",
  "status": "ok",
  "sortBy": "latest",
  "videos": [
    {
      "id": "faf4ouwGykc",
      "url": "https://www.youtube.com/watch?v=faf4ouwGykc",
      "title": "I Scraped 90 YouTube Videos to See What's Actually Winning",
      "publishedDate": "2026-06-17T17:00:22Z",
      "durationSeconds": 230,
      "viewCount": 332,
      "likeCount": 15,
      "commentCount": 1,
      "thumbnailUrl": "https://i.ytimg.com/vi/faf4ouwGykc/maxresdefault.jpg",
      "isLive": false,
      "isUpcoming": false
    }
  ],
  "shorts": [
    {
      "id": "LUTaRsyFzno",
      "url": "https://www.youtube.com/shorts/LUTaRsyFzno",
      "title": "Watch Klára’s full presentation on our channel! 🏠📈 #apify #praguecrawl #dev",
      "publishedDate": "2026-06-24T11:44:01Z",
      "durationSeconds": 53,
      "viewCount": 877,
      "likeCount": 7,
      "commentCount": 0,
      "thumbnailUrl": "https://i.ytimg.com/vi/LUTaRsyFzno/maxresdefault.jpg",
      "isLive": false,
      "isUpcoming": false
    }
  ],
  "summary": {
    "videosRequested": 20,
    "shortsRequested": 20,
    "videosCollected": 20,
    "shortsCollected": 20
  },
  "collectedAt": "2026-06-29T17:52:34+00:00",
  "id": "UCTgwcoeGGKmZ3zzCXN2qo_A",
  "name": "Apify",
  "handle": "@apify",
  "url": "https://www.youtube.com/@apify",
  "isVerified": true,
  "subscriberCount": 14400,
  "videoCountText": "255",
  "totalViewsText": "9989847",
  "country": "CZ"
}
```

#### Excerpt — invalid input

```json
{
  "inputValue": "not-a-channel",
  "status": "invalid_input",
  "error": "This input is not a supported YouTube channel handle or URL.",
  "type": "channel"
}
```

When `status` is `invalid_input` or `failed`, rely on **`error`** and **`warnings`** for context. Partial channel data may still be present when `status` is `partial`.

***

### Pricing

This Actor uses **pay-per-event** pricing. You are charged only for **successful** collection — failed or invalid channels are not billed for channel events, and only successfully collected videos and Shorts count toward media events.

| Event                       | When it is charged                                                                                  |
| --------------------------- | --------------------------------------------------------------------------------------------------- |
| **`channel_record`**        | Once per channel **successfully saved** (`status` is `ok` or `partial`)                             |
| **`channel_videos_shorts`** | Once per **video or Short successfully collected** when the corresponding tab collection is enabled |

**Examples** (see the **Pricing** tab on the Store listing for current rates):

| Run                                             | What you pay for                                           |
| ----------------------------------------------- | ---------------------------------------------------------- |
| 10 channels, videos and Shorts disabled         | 10 `channel_record` events                                 |
| 1 channel + 20 videos + 20 Shorts, all succeed  | 1 `channel_record` + 40 `channel_videos_shorts` events     |
| 5 channels + 100 videos each, all succeed       | 5 `channel_record` + 500 `channel_videos_shorts` events    |
| 10 channels requested, 2 invalid inputs skipped | 8 `channel_record` events (invalid inputs are not charged) |

Disable **Include channel videos** and **Include channel Shorts** if you only need profile data — you will not be charged for `channel_videos_shorts` events.

When **Separate dataset records** is enabled, the dataset lists each channel, video, and Short as its own row. Billing still uses the two events above: one charge per channel saved, and one charge per video or Short collected.

***

### Free plan limits

On the Apify **free plan**, the Actor may automatically apply:

| Limit                      | Value                                        |
| -------------------------- | -------------------------------------------- |
| Channels processed per run | **10** (only the first entries in your list) |
| Maximum videos per channel | **5** (when video collection is enabled)     |
| Maximum Shorts per channel | **5** (when Shorts collection is enabled)    |

Additional channels in the same run are not processed. Paid Apify plans can use the full input list and higher per-channel limits without these caps. If limits apply, the run log will include a short notice.

***

### Public data and coverage

**No YouTube login required**\
The Actor reads publicly visible channel pages. It does not sign in to YouTube and does not use your Google account.

**Guest view vs signed-in view**\
Results reflect what YouTube shows to visitors who are not logged in. Compared with a signed-in session, output may differ slightly in counts, ordering, or available metadata.

**Videos and Shorts**\
Collection reads the channel’s public Videos and Shorts tabs up to your limits. The number returned depends on what YouTube exposes and on your sort / date filter settings. The date filter applies to **videos only**, not Shorts.

**Unavailable or restricted channels**\
Some channels may return `partial` or `failed` with a message in `warnings` or `error`. Retrying later or processing a smaller batch can help in some cases.

**Compliance**\
You are responsible for using collected data in line with applicable laws and [YouTube's Terms of Service](https://www.youtube.com/t/terms).

***

### Tips for best results

1. **Use handles or full URLs** — Both `@apify` and `https://www.youtube.com/@apify` work.
2. **Start with a small batch** — Test with 2–5 channels before large exports.
3. **Pick the right output format** — Use **separate records** (default) for spreadsheets, warehouses, and filtering by `type`. Use **nested records** when you want one JSON object per channel.
4. **Enable only what you need** — Profile-only runs are faster and cost less than full video + Shorts collection.
5. **Set sensible limits** — Use lower `maxChannelVideos` / `maxChannelShorts` for quick checks; raise them for catalog builds.
6. **Filter on `status`** — Use `ok` and `partial` for usable data; review `warnings` on partial rows.
7. **Deduplicate on channel `id`** — The `UC…` channel ID is a stable key across runs.
8. **Schedule recurring runs** — Use Apify schedules to refresh channel stats and latest uploads for your target list.
9. **Export flexibly** — Download as JSON, CSV, Excel, or connect via API to your BI tools, CRM, or automation stack.

***

### Frequently asked questions

**Can I scrape multiple channels in one run?**\
Yes. Add as many handles or URLs as you need (subject to free-plan caps on the Apify free tier).

**What is the difference between separate and nested output?**\
**Separate records** (default) writes one dataset row per channel, video, and Short, each with a `type` field. **Nested records** writes one row per channel with `videos` and `shorts` arrays on the same object.

**Do I always get channel profile data?**\
Yes. Every supported channel input produces channel profile fields. Videos and Shorts are optional.

**Why are there fewer videos than my `maxChannelVideos` setting?**\
YouTube may expose fewer items than your limit, or a tab may not load fully. Check `summary.videosCollected` and `warnings` on the channel row.

**Why is `status` `partial`?**\
Some part of the channel run had an issue — for example the Videos tab could not be loaded but the profile was retrieved. Read `warnings` for details.

**Does the date filter apply to Shorts?**\
No. `channelDateRangeDate` filters **videos only**.

**Can I sort videos by most popular?**\
Yes. Set `channelDateRangeSortBy` to `popular` or `oldest`. If a date range is set, sorting is forced to **Latest**.

**Will failed channels be charged?**\
No. `channel_record` is charged only for successfully saved channels (`ok` or `partial`). Media events are charged only for videos and Shorts that were actually collected.

**Can I get live stream or premiere metadata?**\
Video and Short items include `isLive` and `isUpcoming` when YouTube provides that information.

**Does this Actor download video files?**\
No. It returns metadata and URLs only — not MP4 files or audio.

***

### Support

For Actor-specific issues, use the **Issues** tab on the Apify Store listing or contact the publisher through Apify.

For platform questions (runs, billing, API, schedules), see [Apify documentation](https://docs.apify.com) and Apify support.

# Actor input Schema

## `channelInputs` (type: `array`):

Add one channel per row. Supported values: handles such as `@apify` and full YouTube channel URLs. Channel profile data is always collected for every row.

## `separateChannelRecords` (type: `boolean`):

When enabled (default), the dataset contains separate items for each channel (`type: channel`), each video (`type: video`), and each Short (`type: short`). When disabled, one item per channel is returned with optional `videos` and `shorts` arrays on the same record.

## `includeChannelVideos` (type: `boolean`):

Collect items from the channel's Videos tab. With separate records enabled, each video is a dataset item with `type: video`. Otherwise, videos are returned in the `videos` array on the channel record.

## `includeChannelShorts` (type: `boolean`):

Collect items from the channel's Shorts tab. With separate records enabled, each Short is a dataset item with `type: short`. Otherwise, Shorts are returned in the `shorts` array on the channel record.

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

Maximum number of regular videos to collect from each channel when `Include channel videos` is enabled.

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

Maximum number of Shorts to collect from each channel when `Include channel Shorts` is enabled.

## `channelDateRangeSortBy` (type: `string`):

Choose how channel tab results should be ordered when collecting videos or Shorts. If a channel date range is set, sorting is automatically forced to Latest.

## `channelDateRangeDate` (type: `string`):

Optional publish-time filter for channel videos when video collection is enabled. Use either an absolute date (`YYYY-MM-DD`) or a relative value such as `2 weeks`, `3 months`, or `1 year`. If set, channel sorting is automatically changed to Latest. This filter does not apply to Shorts. Leave empty to skip this filter.

## Actor input object example

```json
{
  "channelInputs": [
    "@MrBeast",
    "https://www.youtube.com/@apify"
  ],
  "separateChannelRecords": true,
  "includeChannelVideos": false,
  "includeChannelShorts": false,
  "maxChannelVideos": 10,
  "maxChannelShorts": 10,
  "channelDateRangeSortBy": "latest",
  "channelDateRangeDate": ""
}
```

# Actor output Schema

## `channels` (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 = {
    "channelInputs": [
        "@MrBeast",
        "https://www.youtube.com/@apify"
    ]
};

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

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

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "YouTube Channel Scraper",
        "description": "Collect public YouTube channel profiles from handles or URLs — subscribers, description, avatar, country, and channel stats. Optionally add videos and Shorts with views, likes, duration, and thumbnails. Output as separate dataset rows (channel, video, short) or one nested record per channel.",
        "version": "0.0",
        "x-build-id": "84qXUPC7C4wWxsxMb"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/calm_builder~youtube-channel-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-calm_builder-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/calm_builder~youtube-channel-scraper/runs": {
            "post": {
                "operationId": "runs-sync-calm_builder-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/calm_builder~youtube-channel-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-calm_builder-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",
                "required": [
                    "channelInputs"
                ],
                "properties": {
                    "channelInputs": {
                        "title": "Channel handles and links",
                        "type": "array",
                        "description": "Add one channel per row. Supported values: handles such as `@apify` and full YouTube channel URLs. Channel profile data is always collected for every row.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "separateChannelRecords": {
                        "title": "Separate dataset records",
                        "type": "boolean",
                        "description": "When enabled (default), the dataset contains separate items for each channel (`type: channel`), each video (`type: video`), and each Short (`type: short`). When disabled, one item per channel is returned with optional `videos` and `shorts` arrays on the same record.",
                        "default": true
                    },
                    "includeChannelVideos": {
                        "title": "Include channel videos",
                        "type": "boolean",
                        "description": "Collect items from the channel's Videos tab. With separate records enabled, each video is a dataset item with `type: video`. Otherwise, videos are returned in the `videos` array on the channel record.",
                        "default": false
                    },
                    "includeChannelShorts": {
                        "title": "Include channel Shorts",
                        "type": "boolean",
                        "description": "Collect items from the channel's Shorts tab. With separate records enabled, each Short is a dataset item with `type: short`. Otherwise, Shorts are returned in the `shorts` array on the channel record.",
                        "default": false
                    },
                    "maxChannelVideos": {
                        "title": "Maximum videos per channel",
                        "minimum": 1,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "Maximum number of regular videos to collect from each channel when `Include channel videos` is enabled.",
                        "default": 10
                    },
                    "maxChannelShorts": {
                        "title": "Maximum Shorts per channel",
                        "minimum": 1,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "Maximum number of Shorts to collect from each channel when `Include channel Shorts` is enabled.",
                        "default": 10
                    },
                    "channelDateRangeSortBy": {
                        "title": "Channel sort",
                        "enum": [
                            "latest",
                            "popular",
                            "oldest"
                        ],
                        "type": "string",
                        "description": "Choose how channel tab results should be ordered when collecting videos or Shorts. If a channel date range is set, sorting is automatically forced to Latest.",
                        "default": "latest"
                    },
                    "channelDateRangeDate": {
                        "title": "Channel date range",
                        "pattern": "^$|^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$|^(\\d+)\\s*(day|week|month|year)s?$",
                        "type": "string",
                        "description": "Optional publish-time filter for channel videos when video collection is enabled. Use either an absolute date (`YYYY-MM-DD`) or a relative value such as `2 weeks`, `3 months`, or `1 year`. If set, channel sorting is automatically changed to Latest. This filter does not apply to Shorts. Leave empty to skip this filter.",
                        "default": ""
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
