# YouTube Channel Scraper - Videos, Shorts, Views & Likes (`tidytools/youtube-channel-scraper`) Actor

Scrape YouTube channels, playlists and videos: subscribers, total views, join date, country, links, plus each video's views, likes, publish date, duration, tags and description. Videos, Shorts and live tabs. No login, no proxy needed. From $1 per 1,000 videos; failed items are free.

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

## Pricing

Pay per event

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

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does YouTube Channel Scraper do?

**Paste YouTube channels (@handle or URL), playlists or videos, get one row per channel and per video (views, likes, dates, duration, tags) for $1 per 1,000 videos and $2 per 1,000 channels, with no start fee.** Failed, removed, filtered and duplicate items are free.

It turns **YouTube channels, playlists and video links into clean rows**: channel statistics and the newest videos, Shorts and live streams of each channel, with views, likes, publish dates, durations, tags and descriptions.

- 📺 **Channel info**: subscribers, total views, video count, join date, country, description, external links (Instagram, X, website ...), keywords, verified badge, avatar and banner.
- 🎬 **Videos, Shorts and live streams**: the newest up to 100 per tab, each with title, URL, views, duration and age, from one page per tab, so even 300 videos take a few seconds.
- 🔎 **Full video details** (optional): exact views, likes, publish date and time, category, tags, hashtags, chapters, full description, caption languages and live status.
- 🗓️ **Date filter and monitoring**: only videos after a date, or only videos your earlier scheduled runs have not seen.
- 💸 **From $1 per 1,000 videos, no start fee.** Failed, removed, filtered and duplicate videos are free.
- 🤝 **Honest by design**: no login, no cookies, no browser, our own user agent, and youtube.com/robots.txt is followed. No proxy needed.

#### Real results (3 October 2026)

9 inputs (5 channels with all three tabs, a playlist, 2 videos and a Vimeo link), 20 videos per tab: **264 rows in 4 seconds (263 charged: 5 channels, 258 videos), $0.27**; the Vimeo line was a free `invalid_input` row.

| Channel | Subscribers | Total views | Videos | Joined | Country | Links |
|---|---|---|---|---|---|---|
| MrBeast | 519,000,000 | 141,443,077,746 | 1,004 | 2012-02-19 | United States | 4 |
| Marques Brownlee | 21,300,000 | 5,730,204,755 | 1,856 | 2008-03-21 | United States | 5 |
| Veritasium | 21,300,000 | 4,628,964,886 | 538 | 2010-07-21 | United States | 7 |
| Linus Tech Tips | 16,900,000 | 9,876,645,641 | 7,941 | 2008-11-24 | Canada | 7 |
| hololive ホロライブ - VTuber Group | 2,970,000 | 2,674,827,645 | 2,109 | 2016-03-03 | Japan | 6 |

Full details on (2 channels x 10 videos + 4 video links, one of them removed): 23 videos with full details, 2 channels, the removed video a free `not_found` row, 6 seconds, $0.05.

### Use cases

- **Influencer and creator research**: compare channels by subscribers, total views, upload frequency and views per video before a sponsorship.
- **Competitor monitoring**: schedule a run with monitoring on and get only the new uploads of the channels you follow, with their first-day views.
- **Content and SEO research**: titles, tags, hashtags, chapters and descriptions of the best performing videos in a niche.
- **Shorts analysis**: views of every recent Short of a channel next to its long videos.
- **Data for AI agents and dashboards**: one clean JSON row per video, ready for Sheets, BigQuery or an LLM.

Need the spoken words too? The **YouTube Transcript Scraper** by TidyTools returns captions with timestamps for the same videos.

### How much does it cost?

| Event | Price | When |
|---|---|---|
| Video | **$1.00 / 1,000 videos** ($0.001 each) | a video from a channel tab or playlist (title, URL, views as YouTube shows them, duration, age) |
| Video with full details | **$2.00 / 1,000 videos** ($0.002 each) | charged instead of "Video" when the video's page was read with full details |
| Channel info | **$2.00 / 1,000 channels** ($0.002 each) | one channel row |

**Free:** channels and videos that do not exist, private, removed or age-restricted videos, videos older than your date filter, videos returned by an earlier run in monitoring mode, duplicates and invalid inputs. **No start fee.** Larger Apify plans get the usual volume discount (Silver 10%, Gold and above 20%).

**Example:** 50 channels, newest 30 videos each: 50 x $0.002 + 1,500 x $0.001 = **$1.60**.

For comparison (Apify Store, checked 3 October 2026, users in the last 30 days): streamers/youtube-scraper (12,352 users) $0.004 per result; streamers/youtube-channel-scraper (2,949 users) $0.0013 per video; streamers/youtube-shorts-scraper (2,666 users) $0.004 per Short; apidojo/youtube-channel-information-scraper (433 users) $0.005 per channel URL; grow_media/youtube-channel-scraper (142 users) $0.001 per row. Those cover more (search results, comments, complete channel histories); this Actor reads only the public pages robots.txt allows (see Limitations).

#### Control your cost

- `maxVideos` (per channel tab or playlist) and `maxResults` (per run) cap the number of videos; channel rows are one per channel.
- Before reading, the run logs its plan (worst case) and compares it with your **maximum charge per run**. When the next video could pass it, the run stops: `SUMMARY.status` is `LIMIT_REACHED` and `SUMMARY.notProcessed` lists the inputs not read.
- Every row has `charged: true` or `false`. If Apify restarts the run, rows already delivered are skipped and not charged again.

### How to use it

1. **Channels, playlists or videos**: one per line (spaces, commas and semicolons also separate; pasted quotes and brackets are removed). Channels as `https://www.youtube.com/@mkbhd`, `@mkbhd`, a `/channel/UC...` URL or the channel ID; playlists as their URL; videos as watch, youtu.be or Shorts links or 11-character IDs.
2. **Channel tabs**: Videos, Shorts and/or Live streams.
3. **Videos per channel tab or playlist**: up to 100 (0 = channel info only).
4. Optional: **Full video details**, **Only videos published after** (`2026-09-01` or `30 days`), **monitoring** for scheduled runs.
5. Click **Start**. The **Videos** view shows the key columns, **Channels** the channel rows, **All fields** everything (CSV, Excel, JSON).

#### Input example

```json
{
    "urls": ["https://www.youtube.com/@mkbhd", "@veritasium", "https://www.youtube.com/playlist?list=PLBCF2DAC6FFB574DE"],
    "tabs": ["videos", "shorts"],
    "maxVideos": 30,
    "videoDetails": false,
    "publishedAfter": "90 days"
}
```

#### Output example

Real rows (3 October 2026), shortened. A channel:

```json
{
    "type": "channel",
    "channelId": "UCBJycsmduvYEL83R_U4JriQ",
    "channelName": "Marques Brownlee",
    "handle": "@mkbhd",
    "handleUrl": "https://www.youtube.com/@mkbhd",
    "subscriberCount": 21300000,
    "subscriberCountText": "21.3M subscribers",
    "videoCount": 1856,
    "viewCount": 5730204755,
    "joinedDate": "2008-03-21",
    "country": "United States",
    "links": [{ "title": "Twitter", "url": "http://twitter.com/MKBHD" }, { "title": "Instagram", "url": "http://instagram.com/MKBHD" }],
    "isVerified": true,
    "charged": true
}
```

A video from a channel tab (list level):

```json
{
    "type": "video",
    "detailLevel": "list",
    "videoId": "3iRUwVzRDZQ",
    "url": "https://www.youtube.com/watch?v=3iRUwVzRDZQ",
    "title": "Xiaomi 18 Fold: How Does This Happen?",
    "contentType": "video",
    "viewCount": 4200000,
    "viewCountText": "4.2 million views",
    "viewCountIsApproximate": true,
    "durationSeconds": 647,
    "publishedText": "17 hours ago",
    "publishedAtApprox": "2026-10-02T21:34:47.583Z",
    "channelHandle": "@mkbhd",
    "position": 1,
    "source": "channel:videos",
    "charged": true
}
```

A video with full details:

```json
{
    "type": "video",
    "detailLevel": "full",
    "videoId": "QW_jlUn4gA8",
    "title": "This Is What a Godlike Civilization Would Look Like",
    "viewCount": 7212170,
    "likeCount": 146119,
    "durationSeconds": 852,
    "publishedAt": "2026-09-22T07:00:01-07:00",
    "category": "Education",
    "tags": ["kurzgezagt", "kurzgesatg", "kurzgsagt", "kurzgessagt"],
    "hasCaptions": true,
    "captionLanguages": [{ "language": "en", "name": "English", "autoGenerated": false }],
    "channelName": "Kurzgesagt – In a Nutshell",
    "channelSubscriberCount": 25600000,
    "via": "direct",
    "charged": true
}
```

#### What the fields mean

- **detailLevel**: `list` = from the channel tab or playlist page (views rounded as YouTube shows them, e.g. 4.2M, and an age such as "17 hours ago" with `publishedAtApprox`); `full` = the video's own page with player data (exact numbers and dates); `page` = the video's page without player data (see Limitations), charged at the list price.
- **contentType**: `video`, `short` or `live` (a live stream or its recording).
- **viewCountIsApproximate**: `true` when the number comes from a rounded label like "4.2M".
- **chapters**: from the description's timestamp lines (at least two, starting at 0:00).
- **SUMMARY** (key-value store): counts, `perChannelTabs` (videos per tab or "no videos"), `videoPages` (full vs page-only details), `pagesFrom` (which network read the pages) and the cost plan.

### Use it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/tidytools~youtube-channel-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls":["@mkbhd","@veritasium"],"tabs":["videos"],"maxVideos":10,"videoDetails":true}'
```

**With AI agents (MCP):** connect Apify's MCP server (`https://mcp.apify.com?tools=tidytools/youtube-channel-scraper`) to Claude, Cursor or any MCP client and ask, for example, "Compare the last 10 videos of @mkbhd and @veritasium by views and likes". Minimal input: `{"urls": ["@mkbhd"]}`. Failed items are not charged and carry an `errorType`.

### Limitations

- **Newest 100 videos per tab or playlist.** A channel's complete history and the "Popular" sort need YouTube's internal API, which youtube.com/robots.txt disallows, so we do not use it.
- **No search, no comments, no hashtag pages.** Search result pages (`/results`) and comments are disallowed or only reachable through that internal API. Enter channels, playlists or videos.
- **Full details depend on the network.** YouTube often answers data-center networks with "Sign in to confirm you're not a bot" instead of a video's player data. The Actor then tries our own servers; if they get the same answer, it returns the page data YouTube still shows (exact views, likes, date, description, channel) as `detailLevel: "page"`, without duration (unless the video came from a list), tags, category or captions, and charges it at the list price. In our tests on 3 October 2026: from a residential connection 23 of 23 videos had full details; from our data-center servers 7 of 20 (13 page-level). Adding an Apify residential proxy in Advanced settings (billed to your Apify account) usually gives full details for every video.
- **List rows show what YouTube shows**: rounded views (4.2M) and ages ("2 weeks ago"), so the date filter is approximate in list mode. Shorts lists show no age at all: with a date filter the Actor reads each Short's own page for its exact publish date (the row stays a list row at the list price; a page that cannot be read keeps the Short). Live streams and premieres may have no view count.
- Members-only, private and age-restricted videos are not read (no login).

### Responsible use

The Actor reads only public pages, with an honest user agent (`TidyToolsYouTube`), following youtube.com/robots.txt. It does not log in, use cookies, solve CAPTCHAs or bypass bot checks: a page YouTube refuses is reported, not forced. It returns channel and video data that creators publish, not data about viewers. YouTube content belongs to its creators; use the data for analysis and follow YouTube's Terms of Service and the laws that apply to you.

### FAQ

**Does the Actor collect usage data?** The Actor sends one anonymous usage counter per run (input type, item count range, outcome) to improve the tool; no URLs, content or account data.

**Why do some videos have `detailLevel: "page"`?** YouTube withheld the player data from the network that read the page (see Limitations). Views, likes, date and description are still exact; those rows cost the list price.

**Why does a tab say "no videos"?** The channel has no videos of that kind (for example no live streams), so nothing is charged.

**Can I get only new videos every day?** Yes: turn on **Only videos not returned before**, give the monitor a name and schedule the Actor. The first run returns everything and saves a baseline. Later runs look only at the newest "videos per channel tab" uploads, so set that number higher than the uploads you expect between two runs.

**What happens with a mistake in the input?** A line that is not a YouTube channel, playlist or video (a bare name without `@`, a YouTube page such as /trending, a malformed link, a number or object in the list), an unknown channel, an unknown tab name, or a date filter such as "yesterday" gives a free row with an `errorType` (`invalid_input` or `not_found`) and the run ends normally, never as a failed run. Turning both "Videos per channel tab = 0" and "Channel info row" off for channels only also ends as a free `invalid_input` row, because nothing would be returned.

**Which separators and spellings work?** Line breaks, spaces, tabs, commas and semicolons separate entries, so `@mkbhd @veritasium` is two channels. Quotes, brackets and a trailing slash around an entry are removed (`"@mkbhd"`, `(https://www.youtube.com/@mkbhd/)`). `@MKBHD` and `@mkbhd` are the same channel, and so are `@handle`, its `/channel/UC...` URL and a `/c/` link: the channel is read and charged once (the repeat counts under `duplicatesSkipped`). A video or Shorts link in the list is returned as a video (full details, $2 per 1,000), not as its channel; a `watch?v=...&list=...` link is the video.

**What if an option has the wrong type?** `"false"`, `"no"`, `"0"` (text) count as off and `"true"`, `"yes"`, `"1"` as on. A number given as text works; a value that is not a number falls back to the default, and out-of-range numbers are brought into range (`maxVideos` 0-100, `maxResults` 1-100,000). Every such correction is listed in `SUMMARY.inputNotes` and logged as a warning.

**Does it work with old /c/ and /user/ links?** Yes, as well as @handles, channel IDs, m.youtube.com and music.youtube.com links.

### Support

Open an issue in the **Issues** tab with your input and the run link. Issues are checked regularly.

# Actor input Schema

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

One per line: a channel (https://www.youtube.com/@mkbhd, @mkbhd, a /channel/UC... URL or channel ID), a playlist URL, or a video (watch, youtu.be or Shorts URL, or an 11-character video ID). Spaces, commas and semicolons also separate entries; pasted quotes and brackets are removed. Up to 1,000 per run. Entries that are not YouTube channels, playlists or videos (for example a name without @) become a free row with errorType "invalid_input".

## `tabs` (type: `array`):

Which lists to read for each channel (newest first). Ignored for playlists and single videos.

## `maxVideos` (type: `integer`):

The newest N videos of each channel tab or playlist (0 = channel info only). YouTube's public pages show at most 100; more would need YouTube's internal API, which robots.txt disallows, so we do not use it.

## `videoDetails` (type: `boolean`):

Off: each video comes from the channel or playlist list (title, views rounded as YouTube shows them, e.g. 4.1M, duration, age such as "3 days ago"; $1 per 1,000). On: each video's page is read too, adding exact views, likes, publish date and time, category, tags, hashtags, chapters, full description, caption languages and live status ($2 per 1,000, charged instead). Video links in the input always get full details.

## `includeChannelInfo` (type: `boolean`):

One row per channel: subscribers, total views, video count, join date, country, description, external links, keywords, avatar and banner ($2 per 1,000 channels).

## `publishedAfter` (type: `string`):

A date (2026-09-01) or a period (7 days, 2 weeks, 3 months). In list mode YouTube shows only an age such as "2 weeks ago", so the cut-off is approximate; with full details (and for Shorts, whose lists show no age) it uses the exact publish date. Older videos are skipped and free.

## `onlyNewVideos` (type: `boolean`):

For scheduled runs: return (and charge) only videos that earlier runs with the same monitor name did not see, and each channel info row only once. The first run returns everything and saves the baseline.

## `monitorName` (type: `string`):

Separate monitors keep separate memories (letters, digits and dashes). Only used with monitoring on.

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

The run stops after this many video rows (channel rows are not counted). A cost cap on top of Apify's maximum charge per run.

## `httpVia` (type: `string`):

Every request uses our own user agent and follows youtube.com/robots.txt, with no cookies, login or browser. If YouTube refuses one network (consent page, bot check, HTTP 429), Auto retries the page from our servers.

## `proxyConfiguration` (type: `object`):

Only used for requests sent from Apify's network. Apify proxy usage is billed to your Apify account.

## `maxConcurrency` (type: `integer`):

How many YouTube pages are read at the same time.

## Actor input object example

```json
{
  "urls": [
    "https://www.youtube.com/@mkbhd"
  ],
  "tabs": [
    "videos"
  ],
  "maxVideos": 10,
  "videoDetails": false,
  "includeChannelInfo": true,
  "onlyNewVideos": false,
  "monitorName": "default",
  "maxResults": 1000,
  "httpVia": "auto",
  "maxConcurrency": 5
}
```

# Actor output Schema

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

No description

## `channels` (type: `string`):

No description

## `full` (type: `string`):

No description

## `summary` (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 = {
    "urls": [
        "https://www.youtube.com/@mkbhd"
    ],
    "maxVideos": 10
};

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

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tidytools/youtube-channel-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/tYsrX7KkSKgUHIemE/builds/iCaqswx5drynJcdvK/openapi.json
