# YouTube Channel Videos Shorts and Live Stream Scraper (`arjun_code/youtube-channel-content-scraper`) Actor

Export public videos, native Shorts, scheduled live streams, active broadcasts, and replays from YouTube channels. Accept channel URLs, IDs, handles, and usernames; use YouTube's native Latest, Popular, or Oldest ordering; and choose fast inventory or full metadata. No YouTube API key required.

- **URL**: https://apify.com/arjun\_code/youtube-channel-content-scraper.md
- **Developed by:** [Arjun AI](https://apify.com/arjun_code) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 basic content 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/actors/running/actors-in-store.md#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

### Export YouTube channel videos, Shorts, and streams

Export the public content inventory of one or more YouTube channels from a channel URL, channel ID, `@handle`, or username. Select standard videos, native Shorts, streams, or any combination, then use YouTube's native **Latest**, **Popular**, or **Oldest** ordering.

Choose **Basic inventory** for fast channel exports or **Full details** for descriptions, exact dates when available, engagement metrics, tags, categories, chapters, availability, caption-language lists, and other public content metadata.

No YouTube Data API key is required. The Actor extracts metadata only; it does not download video or audio files.

> This is an unofficial Actor and is not affiliated with, endorsed by, or sponsored by YouTube or Google. It collects publicly accessible metadata only.

### Ready-to-run examples

- [Export YouTube channel videos and Shorts](https://apify.com/arjun_code/youtube-channel-content-scraper/examples/export-youtube-channel-videos-and-shorts)
- [Scrape full YouTube channel content](https://apify.com/arjun_code/youtube-channel-content-scraper/examples/scrape-full-youtube-channel-content)

### What you can do

- Export recent, popular, oldest, or complete public channel inventories.
- Keep videos, Shorts, and live content separated by `recordType`.
- Include scheduled streams, active broadcasts, and completed live replays.
- Build content archives, monitoring feeds, creator datasets, and research pipelines.
- Use Basic for high-volume inventory or Full for per-item detail enrichment.
- Receive a visible status row when a channel input or selected tab cannot produce content.

### How it works

1. The Actor resolves each channel input and opens the selected channel tabs.
2. Latest uses the initial tab order. Popular and Oldest follow the sorting command returned by YouTube.
3. Browse continuation tokens are followed until the per-type limit is reached or the tab is exhausted.
4. Results are classified as `video`, `short`, or `stream`, deduplicated by video ID, and kept in YouTube's returned order.
5. Basic writes channel-tab metadata directly. Full additionally opens every selected content item for detail extraction.

Popular and Oldest are server-side YouTube orderings. The Actor does not download a whole channel and sort it locally. The first selected tab also supplies the channel summary, so no separate About-page request is made.

### Input reference

| Field | Type | Default | Behavior |
| --- | --- | --- | --- |
| `channels` | `string[]` | `https://www.youtube.com/@NASA` | 1–10 unique channel URLs, IDs, handles, or usernames. |
| `contentTypes` | `string[]` | `videos`, `shorts`, `streams` | Select one or more content tabs. Only selected types are requested. |
| `maxResultsPerType` | integer | `5` | Limit per selected type and channel. Use `0` for all public items from every selected tab. Maximum positive value: 10,000. |
| `sortBy` | string | `latest` | `latest`, `popular`, or `oldest`, using YouTube's native channel-tab order. |
| `detailLevel` | string | `basic` | `basic` for fast inventory or `full` for per-item detail enrichment. |

#### Supported channel inputs

```text
https://www.youtube.com/@NASA
https://www.youtube.com/@NASA/videos
https://www.youtube.com/channel/UCLA_DiR1FfKNvjuUpBHmylQ
@NASA
UCLA_DiR1FfKNvjuUpBHmylQ
NASA
```

#### Content types

- `videos` — standard uploads from the Videos tab.
- `shorts` — native YouTube Shorts from the Shorts tab.
- `streams` — scheduled streams, broadcasts happening now, and completed streams that remain watchable as replays.

`maxResultsPerType` applies only to selected types. For example, `contentTypes: ["videos", "shorts"]` with `maxResultsPerType: 50` can return up to 50 videos and 50 Shorts per channel. A limit of `0` means all—it does not disable the type. Deselect a type when you do not want it.

#### Basic versus Full

| Capability | Basic | Full |
| --- | --- | --- |
| Channel-tab title, URL, thumbnail, visible views, duration, relative date | Yes, when exposed on the card | Yes |
| Channel ID, name, handle, URL, description, avatar, subscribers, verification | Yes | Yes |
| Per-content description | No | Yes, when exposed |
| Exact publication timestamp | No; an approximate value can be derived from relative text | Yes, when exposed; otherwise preserves the Basic approximation |
| Likes, comment count, tags, categories, chapters, language, availability | No | Yes, when exposed |
| Caption-language availability and media/release metadata | No | Yes, when exposed |
| Additional request per content item | No | Yes |

Basic is recommended for large or complete inventories. `publishedAt` in Basic is an approximate conversion of `publishedTimeText`, calculated relative to `scrapedAt`; it is not an exact timestamp supplied by YouTube. Full prefers an exact timestamp from the detail response and otherwise keeps the Basic approximation.

### Input examples

#### Fast default inventory

```json
{
  "channels": [
    "https://www.youtube.com/@NASA"
  ],
  "contentTypes": [
    "videos",
    "shorts",
    "streams"
  ],
  "maxResultsPerType": 5,
  "sortBy": "latest",
  "detailLevel": "basic"
}
```

#### All public videos and Shorts

```json
{
  "channels": ["@NASA"],
  "contentTypes": ["videos", "shorts"],
  "maxResultsPerType": 0,
  "sortBy": "latest",
  "detailLevel": "basic"
}
```

#### Oldest streams with full details

```json
{
  "channels": ["UCLA_DiR1FfKNvjuUpBHmylQ"],
  "contentTypes": ["streams"],
  "maxResultsPerType": 25,
  "sortBy": "oldest",
  "detailLevel": "full"
}
```

### Pricing

This Actor uses pay-per-event pricing with platform usage included:

- **Basic content result:** `$0.0008` each—`$0.80` per 1,000 results.
- **Full content result:** `$0.003` each—`$3.00` per 1,000 results.
- **Actor start:** `$0.00005` per run.
- **Status rows:** free.

If Full enrichment fails but the Actor preserves the discovered Basic record, that row is charged at the Basic rate only.

Example charges before any configured discounts:

| Run outcome | Charge including one start |
| --- | ---: |
| Default maximum: 5 Basic items × 3 selected types | `$0.01205` |
| 100 Basic results | `$0.08005` |
| 3 Full results | `$0.00905` |
| 100 Full results | `$0.30005` |

These examples assume the requested number of items is available. The Actor respects the user's maximum run charge. The **Pricing** tab is the source of truth for active prices and discounts.

### Dataset output

The default Dataset uses four record types:

- `video` — one standard video.
- `short` — one native Short.
- `stream` — one upcoming, active, processing, or completed live broadcast.
- `channelContentStatus` — a visible invalid-input, not-found, blocked, failed, empty-tab, or charge-limited outcome.

Resolved channel metadata is stored in `OUTPUT.resultsByChannel` and repeated on content rows where useful. It is not emitted as an extra Dataset item, so a request for 50 content results does not unexpectedly return 51 rows.

Fields that do not apply are omitted rather than filled with unrelated `null` values. On successful Full rows, `description`, `publishedAt`, and `commentCount` remain explicit nullable fields so consumers can distinguish a requested-but-unavailable value.

### Real output examples

The shortened records below came from real Actor `0.1.9` cloud runs on September 2, 2026. Counts and live state change over time.

#### Basic video

```json
{
  "recordType": "video",
  "status": "complete",
  "detailLevel": "basic",
  "detailStatus": "notRequested",
  "videoId": "6o3m9Bw67Os",
  "url": "https://www.youtube.com/watch?v=6o3m9Bw67Os",
  "title": "NASA's Nancy Grace Roman Space Telescope Launches (Official NASA Recap)",
  "thumbnailUrl": "https://i.ytimg.com/vi/6o3m9Bw67Os/hq720.jpg",
  "durationSeconds": 127,
  "durationText": "2:07",
  "publishedAt": "2026-09-01T11:23:18.809548Z",
  "publishedTimeText": "1 day ago",
  "viewCount": 92000,
  "sortBy": "latest",
  "sortIndex": 1,
  "channelId": "UCLA_DiR1FfKNvjuUpBHmylQ",
  "channelName": "NASA",
  "channelHandle": "@NASA",
  "channelUrl": "https://www.youtube.com/@NASA",
  "channelSubscriberCount": 15100000,
  "channelIsVerified": true
}
```

#### Full Short

```json
{
  "recordType": "short",
  "status": "complete",
  "detailLevel": "full",
  "detailStatus": "complete",
  "videoId": "myZ9kn9MIWQ",
  "url": "https://www.youtube.com/shorts/myZ9kn9MIWQ",
  "title": "2026 Solar Eclipse @ 50,000 Feet",
  "durationSeconds": 93,
  "durationText": "1:33",
  "uploadDate": "2026-08-14",
  "publishedAt": "2026-08-14T16:46:54Z",
  "viewCount": 232765,
  "likeCount": 12752,
  "commentCount": null,
  "availability": "public",
  "categories": [
    "Science & Technology"
  ],
  "sortBy": "latest",
  "sortIndex": 1,
  "channelName": "NASA",
  "channelHandle": "@NASA"
}
```

#### Full active stream

```json
{
  "recordType": "stream",
  "status": "complete",
  "detailLevel": "full",
  "detailStatus": "complete",
  "videoId": "M3HKLzjvKPc",
  "url": "https://www.youtube.com/watch?v=M3HKLzjvKPc",
  "title": "Live Video from the International Space Station (Official NASA Stream) 2026-09-02 11:23",
  "liveStatus": "is_live",
  "isLive": true,
  "wasLive": false,
  "concurrentViewCount": 100,
  "uploadDate": "2026-07-30",
  "publishedAt": "2026-07-30T13:13:49Z",
  "releasedAt": "2026-07-30T13:14:41Z",
  "viewCount": 1009966,
  "likeCount": 17641,
  "commentCount": null,
  "channelName": "NASA",
  "channelHandle": "@NASA"
}
```

#### Visible no-result status

```json
{
  "recordType": "channelContentStatus",
  "status": "noResults",
  "inputValue": "@example",
  "inputType": "handle",
  "contentType": "streams",
  "errorCode": "NO_CONTENT_FOUND",
  "errorMessage": "No public streams were found for this channel.",
  "suggestion": "Select another content type or verify the channel's public Streams tab."
}
```

Status rows are not billed as content results.

### Output field reference

| Group | Common fields |
| --- | --- |
| Status and source | `recordType`, `status`, `inputValue`, `inputType`, `sourceChannelInput`, `contentType`, `errorCode`, `errorMessage`, `suggestion` |
| Detail state | `detailLevel`, `detailStatus`, `detailErrorCode`, `detailErrorMessage` |
| Ordering | `sortBy`, `sortIndex` |
| Channel | `channelId`, `channelName`, `channelHandle`, `channelUrl`, `channelDescription`, `channelAvatarUrl`, `channelVideoCount`, `channelSubscriberCount`, `channelIsVerified` |
| Content identity | `videoId`, `url`, `title`, `description`, `thumbnailUrl`, `thumbnailWidth`, `thumbnailHeight` |
| Time | `durationSeconds`, `durationText`, `uploadDate`, `publishedAt`, `publishedTimeText`, `releasedAt`, `releaseDate`, `releaseYear`, `modifiedAt`, `modifiedDate` |
| Engagement and live | `viewCount`, `likeCount`, `commentCount`, `concurrentViewCount`, `liveStatus`, `isLive`, `wasLive`, `scheduledStartTime` |
| Full metadata | `mediaType`, `availability`, `ageLimit`, `videoLanguage`, `subtitleLanguages`, `automaticCaptionLanguages`, `license`, `location`, `playableInEmbed`, `creators`, `artists`, `track`, `album`, `genres`, `tags`, `categories`, `chapters` |
| Collection | `scrapedAt` |

`chapters` contains titles plus start and end times in seconds. Caption-language arrays report availability only; this Actor does not download transcripts. `commentCount` is a count, not comment text.

### Run summary

The default Key-Value Store record named `OUTPUT` contains run totals, per-type counts, status counts, Full-enrichment counts, truncation information, and one `resultsByChannel` entry per resolved input. That channel summary includes its ID, handle, URL, description, avatar, subscriber count, video count, verification status, and output counts.

### Run through the Apify API

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/arjun_code~youtube-channel-content-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "channels": ["@NASA"],
    "contentTypes": ["videos", "shorts"],
    "maxResultsPerType": 5,
    "sortBy": "latest",
    "detailLevel": "basic"
  }'
```

For synchronous testing, replace `/runs` with `/run-sync-get-dataset-items`. Use asynchronous runs for complete channels or Full batches.

### Performance guidance

- Basic is the fastest option because it reads channel-tab cards without opening each content page.
- Full performs one additional detail extraction per item; runtime and network cost grow with the number of results.
- Begin with 3–5 results per selected type before requesting all content.
- Select only the content types you need. Three selected tabs require more discovery work than one.
- A limit of `0` can produce a large, long-running Dataset on established channels.

### Troubleshooting

#### No stream rows were returned

The Streams tab includes upcoming, active, and replayable completed broadcasts. If the channel has no public items in that tab, the Actor writes a `channelContentStatus` row with `status: "noResults"`.

#### Full is much slower than Basic

This is expected because Full opens every selected item. Use Basic when you only need channel inventory, then send a smaller chosen subset to [YouTube Video and Shorts Details Scraper](https://apify.com/arjun_code/youtube-video-details-scraper) if needed.

#### A Full field is `null`

The detail request completed, but YouTube did not expose that optional value. Common cases are hidden comment counts, videos without chapters, and content without music or release metadata.

#### Oldest or Popular results do not match a local sort

The Actor preserves YouTube's current server-side tab ranking. Popular is not promised to be a strict `viewCount` sort, and rankings can change.

### Related Actors

| Goal | Actor |
| --- | --- |
| Discover channels, videos, or Shorts by keyword | [YouTube Search Scraper](https://apify.com/arjun_code/youtube-search-scraper) |
| Enrich a known channel with full profile and contact fields | [YouTube Channel Details Scraper](https://apify.com/arjun_code/youtube-channel-details-scraper) |
| Get full metadata for known video or Shorts URLs or IDs | [YouTube Video and Shorts Details Scraper](https://apify.com/arjun_code/youtube-video-details-scraper) |
| Export public comments and replies | [YouTube Comments Scraper](https://apify.com/arjun_code/youtube-comments-scraper) |

### FAQ

#### Does Oldest scan the whole channel before returning results?

No. The Actor selects YouTube's native Oldest order and follows that order's pagination until the requested limit is reached.

#### Is Popular identical to highest view count?

Not necessarily. It is YouTube's server-side ranking, which YouTube does not define as a strict numerical view sort.

#### Does the Actor download videos, comments, or transcripts?

No. It extracts public metadata. Full can return a public comment count and caption-language availability, but not comment text or transcripts.

#### Why is a Full row marked `partial`?

Discovery succeeded but the per-item detail request failed. The Actor preserves the useful Basic metadata, sets `detailStatus: "failed"`, and charges only the Basic result rate.

### Support and responsible use

For unexpected output, open the Actor's **Issues** tab and include the run ID, exact channel input, selected content types, sort order, detail level, and affected Dataset row. Do not post API tokens or private data.

Use the Actor only for lawful processing of publicly accessible information. Follow YouTube's terms, applicable laws, and your own privacy and retention obligations.

# Actor input Schema

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

Add one channel URL, channel ID, @handle, or username per line.

## `contentTypes` (type: `array`):

Select one or more channel tabs. Live includes scheduled streams, broadcasts happening now, and completed streams that can still be watched as replays.

## `maxResultsPerType` (type: `integer`):

Applied separately to every selected content type and channel. For example, selecting Videos and Shorts with 50 returns up to 50 videos and 50 Shorts per channel. Set to 0 to retrieve all public items from each selected type.

## `sortBy` (type: `string`):

Use YouTube's native channel-tab ordering. Popular is YouTube's own ranking, not a guaranteed exact view-count sort.

## `detailLevel` (type: `string`):

Basic reads channel-tab cards only. It includes channel information but not video descriptions, exact publication timestamps, likes, comment counts, tags, or chapters. Full opens every selected item and adds those fields when YouTube exposes them.

## Actor input object example

```json
{
  "channels": [
    "https://www.youtube.com/@NASA"
  ],
  "contentTypes": [
    "videos",
    "shorts",
    "streams"
  ],
  "maxResultsPerType": 5,
  "sortBy": "latest",
  "detailLevel": "basic"
}
```

# 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 = {
    "channels": [
        "https://www.youtube.com/@NASA"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("arjun_code/youtube-channel-content-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": ["https://www.youtube.com/@NASA"] }

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

```

## MCP server setup

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