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

Export public videos, Shorts, and Streams from up to 30 YouTube channels. Get video IDs, titles, watch URLs, thumbnails, positions, and available view counts and live status in structured rows. Choose a per-tab limit or 0 to continue until the listing ends.

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

## Pricing

from $0.75 / 1,000 channel video delivereds

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

Scrape public YouTube channel videos, Shorts, and Streams from channel URLs, `@handles`, or channel IDs into structured Dataset rows. Each row identifies its channel and source tab, with the title, thumbnail, position, URL, and public metrics that YouTube made available during the run.

### What this Actor does

This Actor lists public channel content without downloading video, audio, images, or captions. It accepts bare `@handles`, bare channel IDs, and supported channel URLs. You can collect one tab or all three; each tab is checked separately so a video found in multiple tabs retains its source context. Available thumbnail URLs and live-status labels come from those same listings, without opening each video. The Actor also writes a per-tab run summary with the number of video rows, empty/error status, skipped entries, whether an additional entry was seen beyond your limit, and any count reported by the source.

### Use cases

- Export recent uploads from channels for content research and reporting.
- Build separate inventories of a creator's regular videos, Shorts, and Streams-tab entries.
- Supply discovered video URLs to a transcript workflow when captions are needed.

### How to use

1. Open the Actor in Apify Console.
2. Enter one or more public channel URLs, `@handles`, or channel IDs. The prefilled channel is a small working example.
3. Choose a content tab and how many videos to collect per tab. Enter `0` to collect all available entries, then click **Start**.
4. Open the Dataset for video rows and the run summary for per-tab collection status.

### Input

| Field | Meaning |
|---|---|
| `channelUrls` | Required list of 1–30 public channels. Accept full YouTube URLs, bare `@handles`, bare `UC…` channel IDs, or YouTube URLs without `https://`. URL forms include `@handle`, `/channel/ID`, `/c/name`, and `/user/name`. Duplicate normalized URLs are processed once. |
| `tab` | `videos` by default; choose `shorts`, `streams`, or `all`. `all` checks each of the three tabs separately. |
| `maxItemsPerTab` | Any positive whole number, or `0` for all available videos. Default 50. Applied independently to every requested tab of every channel. There is no fixed video-count ceiling. |

An existing `/videos`, `/shorts`, or `/streams` suffix on a channel URL is normalized away; the `tab` field determines what is collected. This is the exact input from a successful run:

```json
{"channelUrls":["https://www.youtube.com/@GoogleDevelopers"],"tab":"videos","maxItemsPerTab":5}
```

### Output

Each successful Dataset item represents one public video in one selected channel tab. `position` is its observed position in that tab, not a stable global rank. `videoUrl` remains a watch URL even for Shorts; `tab` tells you where the video was listed. `thumbnailUrl` is an image link supplied by the listing, not an image downloaded or stored by the Actor. `liveStatus` can be `is_live`, `is_upcoming`, `was_live`, `post_live`, `not_live`, or `null` when the listing does not identify it. `channelSubscriberCount`, `thumbnailUrl`, `durationSeconds`, `viewCount`, `uploadDate`, and `liveStatus` are nullable because the source does not always supply them. `uploadDate`, when present, uses YouTube's `YYYYMMDD` form; the Actor does not invent a date when it is absent.

This is a complete Dataset item from the successful run above:

```json
{
  "status": "success",
  "channelUrl": "https://www.youtube.com/@GoogleDevelopers",
  "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
  "channelName": "Google for Developers",
  "channelSubscriberCount": 2670000,
  "tab": "videos",
  "position": 1,
  "videoId": "YDCB8Bk1OBE",
  "videoUrl": "https://www.youtube.com/watch?v=YDCB8Bk1OBE",
  "thumbnailUrl": "https://i.ytimg.com/vi/YDCB8Bk1OBE/hq720.jpg?sqp=-oaymwEcCNAFEJQDSFXyq4qpAw4IARUAAIhCGAFwAcABBg==&rs=AOn4CLBFOW0pTiZSeww__p1Y1fYG2__vEg",
  "title": "Gemma 4 12B: The Encoder-Free Model Explained",
  "durationSeconds": 147.0,
  "viewCount": 12000,
  "uploadDate": null,
  "liveStatus": null,
  "scrapedAt": "2026-09-23T10:07:16Z",
  "errorCode": null,
  "errorMessage": null
}
```

An empty tab receives one `status: "empty"` item with no video ID. A tab that cannot be collected receives one `status: "error"` item with a safe `errorCode` and `errorMessage`; its videos are not silently replaced with an empty list. A run with an error tab finishes with a failed run status, even if other tabs yielded usable rows. The `SUMMARY` output records every requested tab, its delivered video count, and `limitReached` status. Dataset rows can be exported in Apify-supported formats such as JSON and CSV.

### Pricing

The Actor charges one `video-delivered` event for each successfully saved video row. The displayed price per 1,000 is an equivalent for comparison; billing is per delivered video, not in blocks of 1,000. The price depends on your Apify discount tier:

| Apify tier | Price per delivered video | Equivalent per 1,000 videos |
|---|---:|---:|
| Free | $0.00100 | $1.00 |
| Bronze | $0.00090 | $0.90 |
| Silver | $0.00080 | $0.80 |
| Gold | $0.00075 | $0.75 |
| Platinum | $0.00075 | $0.75 |
| Diamond | $0.00075 | $0.75 |

There is no separate start charge. `status: "empty"` and `status: "error"` rows, skipped entries, and the run `SUMMARY` are not charged as video results. Platform usage is included in the event price. Check the Actor's **Pricing** tab for the active tariff and set a maximum run charge before collecting a large channel. If that limit is reached, the Actor stops collecting additional tabs; already delivered video rows remain in the Dataset and `SUMMARY.chargeLimitReached` is `true`.

### Related Actors

| Actor | Best for |
|---|---|
| [YouTube Transcript Extractor - Timestamps](https://apify.com/datascraperes/youtube-transcript-scraper) | Turn a discovered video URL into complete available written captions with timestamps. |
| [Social Blade Multi-Platform Analytics Scraper](https://apify.com/datascraperes/socialblade-scraper) | Add creator audience, growth, and ranking data from public Social Blade profiles. |

### Limits and data quality

The Actor reads public channel listings only. Private, removed, region-restricted, or otherwise inaccessible content may not appear. YouTube changes listings over time; the same tab can return a different order or count on a later run. `limitReached: true` means another valid video was observed beyond the effective count limit, which can be your `maxItemsPerTab` or your run-charge budget. With `0`, the Actor continues until the listing ends or the run-charge budget is exhausted; there is no Actor-imposed video-count ceiling. `limitReached: false` does not prove that YouTube exposed every historical upload. A long run can still stop because of a platform timeout, source rate limit, or network error. Before collecting all of a large channel, review the Pricing tab and your run budget.

This is a lightweight listing rather than a full visit to every video. Titles, thumbnails, and public counts may be present while upload dates or durations are null, especially for Shorts. Thumbnail links may change or stop working later; the Actor does not store image files. A successful row confirms a listed video ID and its observed metadata, not that its media or captions can be downloaded. Results are saved as they are collected. If a handled source error occurs after some videos, those rows remain available, an additional error row identifies the incomplete tab, and the run fails. A platform timeout or forced stop may leave partial Dataset rows without a final tab summary. If the same run restarts, it checks saved rows before continuing; if the listing changed ahead of those rows, it fails rather than duplicating results or charges. Check the final run status before treating the list as complete.

### Frequently asked questions

#### Can I collect Shorts and streams together with regular videos?

Yes. Set `tab` to `all`. The item limit applies separately to Videos, Shorts, and Streams. The `tab` field on each row preserves where it was found.

#### Can I collect every available video instead of choosing a count?

Yes. Set `maxItemsPerTab` to `0`. The Actor keeps fetching the selected tab of each channel until YouTube returns no more entries. How much YouTube makes available can vary. A handled source failure produces an error row; a hard platform timeout can stop the run before that row is written, so check the run status as well as the Dataset.

#### Why is an upload date missing?

YouTube's channel listing does not always provide an upload date. The Actor returns `null` rather than estimating one from relative text or fetching every video individually.

#### Can I use a handle or channel ID without a full URL?

Yes. Enter `@GoogleDevelopers` or a YouTube channel ID beginning with `UC` in `channelUrls`. The Actor normalizes these to channel URLs; it does not accept a video URL as a channel input.

#### Does it return transcripts or download media?

No. It returns channel listing data. Use the related transcript Actor for available written captions of specific video URLs.

### Responsible use

Use only content you are entitled to access and process. You are responsible for complying with YouTube's terms, applicable copyright and privacy requirements, and local law. Public visibility does not itself grant permission to republish media or personal information.

### Support

For an unexpected result, open an issue in the Actor's **Issues** tab with a run ID, a small public channel URL, the selected tab, and any error code. Do not include credentials or private content.

For API request examples, CSV export workflows, and sample Dataset output, see the [YouTube channel scraper examples on GitHub](https://github.com/datacrawler-edu/youtube-channel-scraper-python).

# Actor input Schema

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

Enter a public channel URL, bare @handle, or UC channel ID. URLs may use @handle, /channel/ID, /c/name, or /user/name; https:// is optional for youtube.com URLs. Duplicate channels are processed once.

## `tab` (type: `string`):

Choose one tab or all three. Each tab is collected separately; the video count applies to each tab.

## `maxItemsPerTab` (type: `integer`):

Enter any positive count, or 0 to continue until YouTube has no more entries. Applies independently to each channel tab. The run summary flags when more entries existed beyond a positive count.

## Actor input object example

```json
{
  "channelUrls": [
    "https://www.youtube.com/@GoogleDevelopers"
  ],
  "tab": "videos",
  "maxItemsPerTab": 5
}
```

# Actor output Schema

## `results` (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 = {
    "channelUrls": [
        "https://www.youtube.com/@GoogleDevelopers"
    ],
    "tab": "videos",
    "maxItemsPerTab": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("datascraperes/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 = {
    "channelUrls": ["https://www.youtube.com/@GoogleDevelopers"],
    "tab": "videos",
    "maxItemsPerTab": 5,
}

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datascraperes/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/cytbiB7EvZS0jVrKp/builds/0HagdsrWu5nmxP3di/openapi.json
