# YouTube Channel Scraper - Videos & Shorts (`tubelens/youtube-channel-scraper`) Actor

Scrape any YouTube channel: videos, Shorts, live streams, playlists, community posts and channel metadata, with exact publish dates and view counts. Need transcripts or comments? Use the Video Scraper. Need keyword rankings? Use the Search Scraper.

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

## Pricing

from $1.00 / 1,000 results

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

## How to integrate an Actor?

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

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

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

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

# README

### YouTube channel scraper - videos, Shorts, live streams, playlists & posts

One actor for a whole YouTube channel. Give it a handle, a URL, or a channel ID and get every video, Short, live stream, playlist and community post, plus the channel's own metadata.

**$1.00 per 1,000 results. $0.005 per run. No browser, no proxy setup.**

Works on any public channel. Metadata comes back in English so counts and dates parse reliably; titles and descriptions are the creator's own text.

### Why this scraper?

- 📅 **Exact publish timestamps**: most channel scrapers hand you "3 days ago" and let you guess. Turn on enrichment and every video carries the real upload time.
- 🔢 **Exact view counts**: not "2.3M views" rounded to two digits, the real integer.
- 🎬 **Shorts get the same treatment**: YouTube's Shorts listings carry a title and a rounded view count and nothing else. We fill in duration, exact date, category, description and tags anyway.
- 📚 **The whole catalog, not the first page**: thousands of videos from a single channel, paged to the end. There is no page cap on an unfiltered run.
- 🧾 **Honest nulls**: when a view count is hidden or a field genuinely isn't published, you get `null`, never a fabricated number. Failed enrichment is labelled in `enrichmentError` rather than silently blank.
- 💸 **Bad input doesn't bill you**: a channel that fails to resolve is skipped with a warning, and you're charged only for rows that land in your dataset.

### What you can pull

| Content | Input | Notes |
|---|---|---|
| Long-form videos | `maxVideos` | Newest first, no depth limit |
| Shorts | `maxShorts` | Same enrichment as regular videos |
| Live streams | `maxLiveStreams` | Past, in progress and scheduled, flagged with `wasLiveStream`, `isLive` and `isUpcoming` |
| Playlists | `maxPlaylists` | Title, video count, first video, thumbnail |
| Community posts | `maxCommunityPosts` | Text, attached images, poll questions and options |
| Channel profile | always | Subscribers, total views, country, join date, links, monetization signals |

Set any limit to `0` to skip that content type and keep the run cheap.

### Use cases

- **Creator analytics**: track upload cadence, median views and engagement across a roster of channels on a schedule.
- **Competitive intelligence**: watch what competitors publish, how often, and which formats they lean into.
- **AI and LLM pipelines**: pull titles, descriptions, tags and categories as structured training or retrieval data.
- **Sponsorship research**: size a channel properly before you pay for placement, using real view distributions instead of a headline subscriber count.
- **Trend monitoring**: sweep a keyword for channels, then track what the whole cohort ships.

### Input

Paste channels one per line. Handles, full URLs and `UC…` IDs all work, and you can mix them.

```json
{
  "channels": ["@MrBeast", "https://www.youtube.com/@mkbhd", "UCXuqSBlHAE6Xw-yeJA0Tunw"],
  "maxVideos": 50,
  "maxShorts": 20,
  "enrichVideos": true,
  "includeDerivedAnalytics": true
}
```

No channel list? Set `searchKeyword` instead and the actor finds channels for you.

### Output

One row per item. Every row carries a `type` field so you can filter, and video rows also carry `videoKind` (`regular`, `short` or `live`).

A video row with enrichment on. Note `viewCount: 52` beside `viewCountText: "51 views"`: that isn't a bug. The text is what YouTube rendered on the channel page, which is rounded and cached; the number is the exact live count from enrichment.

```json
{
  "type": "video",
  "videoKind": "regular",
  "videoId": "fUymQq5llCo",
  "title": "Build a Delivery Competitor Monitor",
  "url": "https://www.youtube.com/watch?v=fUymQq5llCo",
  "viewCount": 52,
  "viewCountText": "51 views",
  "publishedAt": "2026-07-24T17:00:12.000Z",
  "publishedText": "15 hours ago",
  "publishedAtIsApproximate": false,
  "durationSeconds": 219,
  "isLive": false,
  "wasLiveStream": false,
  "isMembersOnly": false,
  "description": "See how you can automatically track every location...",
  "tags": ["web scraping platform", "web automation", "scrapers"],
  "category": "Science & Technology",
  "exactPublishedAt": "2026-07-24T17:00:12.000Z",
  "exactViewCount": 52,
  "channelId": "UCTgwcoeGGKmZ3zzCXN2qo_A",
  "channelHandle": "@Apify"
}
```

A channel row:

```json
{
  "type": "channel",
  "channelId": "UCXuqSBlHAE6Xw-yeJA0Tunw",
  "handle": "@LinusTechTips",
  "name": "Linus Tech Tips",
  "country": "Canada",
  "joinedAt": "2008-11-24T00:00:00.000Z",
  "subscriberCount": 16900000,
  "totalViews": 9686730358,
  "totalVideos": 7800,
  "totalVideosIsApproximate": true,
  "verified": true,
  "socialLinks": { "twitter": "https://twitter.com/LinusTech" },
  "monetization": { "hasMembership": true, "hasMerchShelf": false }
}
```

Playlist and community-post rows follow the same pattern. Filter on `type` to split them out.

### How much does it cost?

Two charges, that's it:

- **$1.00 per 1,000 results.** Every row costs the same, whether it's a plain video row or a fully enriched one.
- **$0.005 per run.**

On the Apify **free plan** ($5 of credit) that's about **5,000 results a month**. On **Starter** ($29), about **29,000**.

Enrichment and like counts add requests, not charges. A 50-video channel costs about $0.055 either way.

### Limitations

Worth knowing before you run it:

- **Date filters always use exact dates.** Channel listings only say "2 months ago", which is too coarse to filter on, so setting `publishedAfter` or `publishedBefore` switches enrichment on automatically and every returned row is checked against its real publish timestamp.
- **Very narrow windows on very busy channels are slow.** Channel listings date a video only to the nearest week, month or year depending on its age, so the actor checks individual videos whenever that granularity is coarser than your window. A one-day window on a channel that posts dozens of times a day is the worst case and can take a few hundred requests. Widening the window, or raising the videos limit, returns far more rows for the same work. Depth is not the problem: a window several years back is often quicker than one a few weeks back, because older videos sit in wide year buckets that are fast to rule out wholesale.
- **Historical windows on Shorts are limited.** Shorts listings carry no date at all, so nothing can be ruled out without checking it. The run does as much as its search budget allows and then reports a partial result. For older Shorts, narrow the range and run one channel at a time.
- **A window deep in a large catalog may not be fully reached.** The run works backwards from the newest upload within a search budget; if it runs out before covering the whole range it says so in the status rather than pretending it found everything. Narrow the range or run one channel at a time.
- **`totalVideos` is rounded on big channels.** YouTube reports "7.8K videos" rather than an exact figure, so `totalVideosIsApproximate` tells you when the number came from a rounded label.
- **A small share of videos fail enrichment.** YouTube rate-limits some requests. Those rows come back with `enrichmentError` set and their listing fields still populated. The one exception is a date-filtered run: any video whose enrichment fails has no trustworthy date to filter on, so it is retried once and then skipped rather than guessed at, and the run status tells you how many were skipped.
- **Like counts are opt-in and slow.** YouTube exposes likes only on a payload roughly 70 times larger than the one carrying everything else, so `includeLikeCount` is a separate switch.
- **Members-only and private videos** appear in listings but can't be enriched. They're marked, not dropped.
- **Scheduled premieres have no publish date.** They come back with `isUpcoming: true` and a null `publishedAt`, and they're excluded from date filters, because they haven't aired yet.
- **Derived analytics describe the videos you collected**, not the channel's whole history. Ask for more videos and the median moves.
- **Poll vote counts aren't available.** YouTube doesn't publish them, so poll options come back without tallies.
- **Comment text and transcripts aren't here.** This actor covers the channel and its catalog. Those belong to a video scraper.

### FAQ

**Do I need a YouTube API key?**
No. There's no key, no login and no quota to manage. Paste channels and run.

**Do I need to configure a proxy?**
No. Datacenter proxy is used by default and is enough for YouTube. If an address does get blocked, the actor retries on a residential one automatically.

**Can I run this on a schedule?**
Yes. Apify Schedules can run it hourly, daily or weekly, and each run appends to a dataset you can pull over the API.

**How do I get only recent videos?**
Set `publishedAfter` to a date like `2026-01-01` or a relative value like `30 days`. Both bounds include the named day, and enrichment turns on automatically so the cutoff is exact.

**What happens if a channel doesn't exist?**
It's skipped with a warning, the rest of your list still runs, and you aren't charged for it. The run status message tells you how many channels failed.

**Your feedback**
Found a bug or need a field that isn't here? Open an issue at [console.apify.com/actors/SERgpqPKFdbZrAOmq/issues](https://console.apify.com/actors/SERgpqPKFdbZrAOmq/issues) and it goes straight to a human.

# Actor input Schema

## `channels` (type: `array`):

YouTube channels to scrape. Accepts @handles, channel URLs, or UC channel IDs. Paste one per line.

## `searchKeyword` (type: `string`):

Search YouTube for channels matching this keyword instead of listing them above. Ignored when Channels is set.

## `maxChannelsFromSearch` (type: `integer`):

How many channels to take from the keyword search.

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

Long-form videos to RETURN per channel, newest first. With a date filter set, the actor pages back looking for matches until it has this many or reaches its search budget, then reports a partial result. Set 0 to skip videos.

## `maxShorts` (type: `integer`):

Shorts to RETURN per channel, newest first. With a date filter set, the actor pages back looking for matches until it has this many or reaches its search budget, then reports a partial result. Set 0 to skip Shorts.

## `maxLiveStreams` (type: `integer`):

Past and current live streams to collect per channel. Set 0 to skip.

## `maxPlaylists` (type: `integer`):

Public playlists to collect per channel. Set 0 to skip.

## `maxCommunityPosts` (type: `integer`):

Community tab posts to collect per channel, including polls and images. Set 0 to skip.

## `enrichVideos` (type: `boolean`):

Adds description, tags, category, exact view count and the exact publish timestamp to every video. Channel listings only carry rounded view counts and a relative date such as '3 days ago', so this is the only way to get precise numbers. Costs one small extra request per video, with no extra charge per row.

## `includeLikeCount` (type: `boolean`):

Adds the like count to every video. YouTube only exposes likes on a payload about 70 times larger than the one used for the other enrichment fields, so this makes runs noticeably slower. Requires the enrichment option above.

## `includeDerivedAnalytics` (type: `boolean`):

Adds upload cadence, median views and engagement rates to the channel row. Needs at least 10 videos collected from that channel.

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

Keep only videos published after this date. Accepts YYYY-MM-DD or a relative value such as '30 days'. Both bounds include the named day, and enrichment is enabled automatically so the cutoff is exact.

## `publishedBefore` (type: `string`):

Keep only videos published before this date. Accepts YYYY-MM-DD or a relative value such as '30 days'. Both bounds include the named day, and enrichment is enabled automatically so the cutoff is exact.

## `country` (type: `string`):

Country used for YouTube's regional catalogue. Metadata text is always returned in English so numbers and dates parse reliably; video titles and descriptions are the creator's own text either way.

## `concurrency` (type: `integer`):

How many channels to process at the same time. Raise it for large channel lists.

## `maxRunSeconds` (type: `integer`):

The run stops cleanly and keeps everything collected so far once this is reached, rather than being killed mid-write.

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

Datacenter proxy is used by default and is enough for YouTube. Residential is used automatically only if a datacenter address gets blocked.

## Actor input object example

```json
{
  "channels": [
    "@MrBeast",
    "https://www.youtube.com/@mkbhd",
    "UCXuqSBlHAE6Xw-yeJA0Tunw"
  ],
  "searchKeyword": "tech reviews",
  "maxChannelsFromSearch": 10,
  "maxVideos": 50,
  "maxShorts": 0,
  "maxLiveStreams": 0,
  "maxPlaylists": 0,
  "maxCommunityPosts": 0,
  "enrichVideos": false,
  "includeLikeCount": false,
  "includeDerivedAnalytics": false,
  "publishedAfter": "2026-01-01",
  "publishedBefore": "2026-06-30",
  "country": "US",
  "concurrency": 5,
  "maxRunSeconds": 3300,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Channel metadata, videos, Shorts, live streams, playlists and community posts.

# 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 = {
    "channels": [
        "@MrBeast"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tubelens/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 = { "channels": ["@MrBeast"] }

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

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/SERgpqPKFdbZrAOmq/builds/JhVlYQUU5xoZu5bRW/openapi.json
