# YouTube Channel Videos Scraper (`automation-lab/youtube-channel-videos-scraper`) Actor

Collect public video records from YouTube channels with titles, URLs, thumbnails, views, duration, channel identity, continuation pagination, and monitoring checkpoints.

- **URL**: https://apify.com/automation-lab/youtube-channel-videos-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Videos, Social media, Developer tools
- **Stats:** 2 total users, 2 monthly users, 96.2% 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/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 Videos Scraper

Collect public **YouTube channel videos** into a clean dataset for publishing analysis, creator research, competitor monitoring, and scheduled data pipelines.

Give the Actor one or more channel handles, channel IDs, or channel URLs. It resolves each channel, follows YouTube continuation pages, and returns one typed record per video with identity, title, URL, thumbnail, publication text, view text, duration, and channel identity.

### What does YouTube Channel Videos Scraper do?

The Actor reads the public Videos tab of each supplied YouTube channel.

It can:

- accept `@handles`, `UC...` channel IDs, and normal YouTube channel URLs;
- collect several channels in one run;
- continue beyond the first page of videos;
- cap results globally and per channel;
- stop when it reaches an already-seen video ID;
- deduplicate video IDs within each channel;
- export records through Apify datasets as JSON, CSV, Excel, XML, or RSS;
- run manually, through the API, from an Apify Schedule, or through MCP.

It does not download video or audio files. It returns public listing metadata.

### Who is it for?

#### Publishing and content teams

Track uploads from partner, publisher, or competitor channels and send new records to an editorial spreadsheet.

#### Creator economy analysts

Build channel-level video inventories for format, cadence, title, and view-count analysis.

#### Competitive intelligence teams

Schedule recurring runs and use `stopAtVideoId` as a checkpoint so each run returns only newer uploads.

#### Data engineers

Feed stable video and channel IDs into a warehouse, enrichment job, transcript workflow, or dashboard.

#### Developers and AI agents

Call the Actor through the Apify API or MCP instead of maintaining YouTube pagination and normalization code.

### Why use this Actor?

- **Channel-focused input:** supply the channels you already care about rather than a broad search query.
- **Continuation pagination:** collect more than the small recent set exposed by YouTube's Atom feed.
- **Monitoring checkpoint:** stop before a known video instead of downloading older history on every scheduled run.
- **Typed output:** receive consistent fields instead of raw YouTube response objects.
- **Low-overhead route:** the Actor uses logged-out structured responses and does not launch a browser.
- **Integration-ready:** every video is stored in the run's default dataset.

YouTube changes its public interfaces over time. See [Limitations](#limitations) for realistic boundaries.

### What data can I extract?

| Field | Type | Meaning |
| --- | --- | --- |
| `channelInput` | string | The handle, ID, or URL supplied in the input |
| `channelId` | string | Stable YouTube `UC...` channel ID |
| `channelName` | string | Public channel display name |
| `channelUrl` | string | Canonical channel URL |
| `videoId` | string | Stable YouTube video ID |
| `title` | string | Video title shown on the channel Videos tab |
| `url` | string | Canonical watch URL |
| `thumbnailUrl` | string or null | Best available public thumbnail URL |
| `publishedTimeText` | string or null | Relative publication label, such as `2 days ago` |
| `viewCountText` | string or null | Public localized view label |
| `viewCount` | integer or null | Parsed compact view count when available |
| `durationText` | string or null | Displayed video duration |
| `scrapedAt` | ISO timestamp | Time the record was collected |

Nullable fields may be absent from YouTube for scheduled, live, restricted, or specially rendered content.

### How to scrape YouTube channel videos

1. Open the Actor in Apify Console.
2. Add one or more values to **YouTube channels**.
3. Choose the total `maxItems` limit.
4. Choose `maxVideosPerChannel` if channels should receive equal caps.
5. Optionally add `stopAtVideoId` for an incremental monitoring run.
6. Click **Start**.
7. Open **Dataset** to preview or export the records.

A useful first run is:

```json
{
  "channels": ["@GoogleDevelopers", "@Apify"],
  "maxItems": 12,
  "maxVideosPerChannel": 6
}
```

### Input parameters

#### `channels`

Required array with 1–50 public YouTube channels.

Supported forms include:

```text
@GoogleDevelopers
GoogleDevelopers
UC_x5XG1OV2P6uZZ5FSM9Ttw
https://www.youtube.com/@GoogleDevelopers/videos
https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw
```

Playlist, search, watch, and non-YouTube URLs are not channel inputs.

#### `maxItems`

Maximum records saved across all channels.

- default: `100`
- minimum: `1`
- maximum: `10000`

Channels are processed in input order. When the global limit is reached, later channels are not requested.

#### `maxVideosPerChannel`

Maximum records saved for one channel.

- default: `100`
- minimum: `1`
- maximum: `10000`

Use this limit to balance a multi-channel collection.

#### `stopAtVideoId`

Optional checkpoint for recurring runs.

The Actor reads newest videos first. It saves videos until it encounters this ID, then stops that channel before saving the checkpoint or any older items.

Store the newest `videoId` from a successful run and pass it into the next scheduled run.

### Output example

A current record has this shape:

```json
{
  "channelInput": "@GoogleDevelopers",
  "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
  "channelName": "Google for Developers",
  "channelUrl": "https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw",
  "videoId": "-rYFDefcq3k",
  "title": "Introducing Gemini Robotics 2",
  "url": "https://www.youtube.com/watch?v=-rYFDefcq3k",
  "thumbnailUrl": "https://i.ytimg.com/vi/-rYFDefcq3k/hqdefault.jpg",
  "publishedTimeText": "1 day ago",
  "viewCountText": "7.4K views",
  "viewCount": 7400,
  "durationText": "39:14",
  "scrapedAt": "2026-08-02T04:55:00.000Z"
}
```

Titles, counts, and relative publication labels naturally change as YouTube updates them.

### How much does it cost to scrape YouTube channel videos?

The Actor uses pay-per-event pricing:

- a **$0.00005** one-time start event per run;
- a tiered **video** event for every record saved;
- current BRONZE video price: **$0.00048 per video**.

At the current BRONZE tier, example Actor charges are approximately:

| Saved videos | BRONZE charge calculation |
| ---: | --- |
| 10 | 10 × $0.00048 video event + $0.00005 start event |
| 100 | 100 × $0.00048 video event + $0.00005 start event |
| 1,000 | 1,000 × $0.00048 video event + $0.00005 start event |

Higher-volume pricing tiers reduce the per-video price. Your Apify plan also governs platform usage and spending limits. The Actor never charges a video event for a duplicate, rejected, or unsaved record.

### Monitor new channel uploads on a schedule

A practical incremental workflow is:

1. Run without `stopAtVideoId` and store the first returned `videoId` per channel.
2. Create an Apify Schedule for the desired interval.
3. On the next run, pass the previous newest ID as `stopAtVideoId`.
4. Send the resulting dataset to your webhook, spreadsheet, or database.
5. Replace the checkpoint with the new first record.

Example:

```json
{
  "channels": ["@GoogleDevelopers"],
  "maxItems": 20,
  "maxVideosPerChannel": 20,
  "stopAtVideoId": "iOK1-b_9Dlg"
}
```

The Actor returns only records newer than the checkpoint when that ID is still present in the traversed listing.

### Export videos to a spreadsheet or pipeline

After a run, use the Dataset **Export** menu to download JSON, CSV, Excel, XML, or RSS.

For an automated pipeline, read the dataset through the API:

```text
https://api.apify.com/v2/datasets/DATASET_ID/items?clean=true&format=json
```

Good stable keys are:

- `videoId` for video upserts;
- `channelId` for channel joins;
- `scrapedAt` for collection history.

Relative fields such as `publishedTimeText` should not be treated as exact publication timestamps.

### API usage

Use the API patterns below to run the Actor from cURL, JavaScript, or Python and then read its default dataset.

#### Use the Actor with cURL

Start a run and wait for it to finish:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~youtube-channel-videos-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "channels": ["@GoogleDevelopers"],
    "maxItems": 10,
    "maxVideosPerChannel": 10
  }'
```

Keep API tokens in environment variables or a secret manager.

#### Use the Actor with JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('automation-lab/youtube-channel-videos-scraper').call({
  channels: ['@GoogleDevelopers', '@Apify'],
  maxItems: 20,
  maxVideosPerChannel: 10,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map(({ videoId, title, channelName }) => ({ videoId, title, channelName })));
```

#### Use the Actor with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/youtube-channel-videos-scraper').call(run_input={
    'channels': ['@GoogleDevelopers'],
    'maxItems': 25,
    'maxVideosPerChannel': 25,
})

items = client.dataset(run['defaultDatasetId']).list_items().items
for item in items:
    print(item['channelName'], item['title'], item['url'])
```

### Use the Actor through MCP

Add the Apify MCP server to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/youtube-channel-videos-scraper"
```

#### Claude Desktop, Cursor, and VS Code setup

Use this equivalent JSON configuration in Claude Desktop, Cursor, or VS Code:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/youtube-channel-videos-scraper"
    }
  }
}
```

Example prompts:

- “Collect the 20 newest videos from `@GoogleDevelopers` and summarize the recurring topics.”
- “Run the YouTube Channel Videos Scraper for these five channel URLs and save at most 10 records per channel.”
- “Return videos newer than checkpoint `iOK1-b_9Dlg` from `@GoogleDevelopers`.”

### Tips for reliable runs

- Prefer stable `UC...` channel IDs when a channel may rename its handle.
- Start with small limits while testing a new list of channels.
- Use both global and per-channel limits for predictable multi-channel runs.
- Keep the newest ID from each run if you are building incremental monitoring.
- Inspect logs when a channel resolves but returns no public Videos tab.
- Schedule at a cadence appropriate for the channels; polling every minute is rarely useful.
- Deduplicate downstream by `videoId` if you intentionally collect overlapping runs.

### Failure behavior

Malformed input fails the run with a clear error.

If one channel fails but another succeeds, the Actor logs the failed channel and preserves useful records from successful channels.

If every supplied channel fails to resolve or load, the run fails rather than reporting a misleading empty success.

A valid channel with no public video records can complete with zero records for that channel.

Temporary network errors, HTTP 429 responses, and upstream server errors are retried with bounded backoff.

### Limitations

- Only public channel video listings are supported.
- Private, members-only, deleted, age-restricted, or region-limited data may be absent.
- The Actor does not log in and cannot access YouTube Studio or private analytics.
- It does not return likes, comments, transcripts, tags, descriptions, exact publish timestamps, or downloaded media.
- `viewCount` is parsed from YouTube's compact public label and can be rounded.
- `publishedTimeText` is relative text, not an exact ISO date.
- A handle can change; a channel ID is more stable.
- YouTube may change its logged-out response structure or rate-limit requests.
- The monitoring checkpoint must occur within the traversed range; use a sufficient limit.
- Channel order matters when `maxItems` is lower than the sum of per-channel limits.

### Responsible and legal use

This Actor collects public listing metadata.

You are responsible for:

- complying with YouTube's terms and applicable laws;
- choosing a reasonable run frequency;
- respecting privacy, copyright, and database rights;
- avoiding profiling or harmful decisions based on scraped data;
- securing exported datasets and API credentials;
- honoring deletion or access obligations that apply to your use case.

Do not use the Actor to bypass access controls or collect private account data.

### Troubleshooting

#### My channel does not resolve

Use a full public channel URL or its `UC...` ID. Verify that you supplied a channel page rather than a playlist or video URL.

#### I received fewer videos than requested

The channel may have fewer public videos, the checkpoint may have been reached, the global limit may have been consumed by earlier channels, or YouTube may not expose some content in the Videos tab.

#### My monitoring run returned zero records

Zero is expected when the checkpoint is currently the newest video. Confirm the checkpoint ID belongs to the supplied channel and raise the per-channel limit if it is older than the traversed range.

#### Why is `viewCount` null?

Some rendered items do not expose a public count, and scheduled or special content can use labels that are not numeric. Inspect `viewCountText` for the source label.

#### Can I scrape Shorts?

This Actor targets the channel Videos tab. Shorts shown there may appear, but separate Shorts-tab coverage is not promised. Use the related YouTube Shorts Actor for a Shorts-specific workflow.

#### Does the Actor need a proxy?

No proxy input is required. The Actor uses a public logged-out structured route and bounded retries.

### Related Automation Lab Actors

- [YouTube Channel Scraper](https://apify.com/automation-lab/youtube-channel-scraper) — collect broader channel metadata together with videos.
- [YouTube Playlist Scraper](https://apify.com/automation-lab/youtube-playlist-scraper) — extract videos organized in a specific playlist.
- [YouTube Transcript](https://apify.com/automation-lab/youtube-transcript) — retrieve transcript text after discovering video IDs.
- [YouTube Shorts Scraper](https://apify.com/automation-lab/youtube-shorts-scraper) — use a Shorts-focused input and output workflow.

### FAQ

#### Does this use the official YouTube Data API?

No. It reads public logged-out YouTube channel responses and does not require a Google API key or consume a user's Data API quota.

#### Can I collect all videos from a large channel?

Set both limits high enough. The Actor follows continuation pages until it reaches the channel end or a configured limit. Begin with a smaller run to confirm expected cost and output.

#### Can I sort by popular or oldest?

No. The current product reads the normal newest-first Videos tab so it can support incremental monitoring.

#### Can I get exact publication dates?

Not from this Actor's channel-listing route. It preserves YouTube's displayed relative publication text. Use a separate detail-enrichment step when exact dates are required.

#### Are duplicate videos charged twice?

The Actor deduplicates video IDs within each processed channel before charging and saving them. Downstream deduplication is still recommended across separate runs.

#### Can I run it every day?

Yes. Use an Apify Schedule and a checkpoint. Choose a cadence and limits that match the upload frequency of the channels you monitor.

#### Where are results stored?

Every video is written to the run's default Apify dataset. Dataset retention follows your Apify account plan and storage settings.

# Actor input Schema

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

Channel handles, IDs, or URLs. Examples: @GoogleDevelopers, UC\_x5XG1OV2P6uZZ5FSM9Ttw, or https://www.youtube.com/@GoogleDevelopers/videos.

## `maxItems` (type: `integer`):

Total number of video records to save across all supplied channels.

## `maxVideosPerChannel` (type: `integer`):

Per-channel limit. Continuation pages are fetched until this limit, the total limit, or the end of the channel is reached.

## `stopAtVideoId` (type: `string`):

For scheduled monitoring, stop before this video ID. Newer videos are saved; the known video and older videos are skipped.

## Actor input object example

```json
{
  "channels": [
    "@GoogleDevelopers"
  ],
  "maxItems": 12,
  "maxVideosPerChannel": 6
}
```

# Actor output Schema

## `overview` (type: `string`):

Open the overview table with video identity, channel identity, title, views, publication label, duration, thumbnail, and collection time.

# 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": [
        "@GoogleDevelopers"
    ],
    "maxItems": 12,
    "maxVideosPerChannel": 6
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/youtube-channel-videos-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": ["@GoogleDevelopers"],
    "maxItems": 12,
    "maxVideosPerChannel": 6,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/youtube-channel-videos-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 '{
  "channels": [
    "@GoogleDevelopers"
  ],
  "maxItems": 12,
  "maxVideosPerChannel": 6
}' |
apify call automation-lab/youtube-channel-videos-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/youtube-channel-videos-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/0EqHKAgysYAn0FlvD/builds/fYZ5rsC6eJHfXle8I/openapi.json
