# YouTube Channel Scraper — Videos, Shorts & Streams (`meka.im/youtube-channel-scraper`) Actor

Export public videos, Shorts and stream metadata from YouTube channel URLs, with optional channel profiles. No login or YouTube API key.

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

## Pricing

from $0.34 / 1,000 delivered videos

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

Paste YouTube channel URLs, handles or channel IDs to export public videos, Shorts and streams as structured JSON, CSV or Excel—without a YouTube login or YouTube API key. **Pay $0.40 per 1,000 successfully delivered video rows, including platform usage; tier discounts are listed below.** Only valid unique video rows successfully written to the Dataset generate the result event.

- **Choose the content you need:** regular videos, Shorts and streams, with per-channel limits and native latest, popular or oldest ordering when the category supports it.
- **Keep useful context:** video titles, links, duration, original view-count text and available channel identity stay together.
- **Add channel profiles:** available descriptions, public links, images and subscriber metadata are saved separately from video rows.
- **Control extra detail work:** full descriptions are optional; a failed description lookup preserves the valid listing row and reports incomplete detail.
- **Avoid duplicate results:** each video ID is delivered once per run, including overlapping channel aliases.

### Quick start

1. Enter a public channel URL you already know.
2. Keep a small result limit for the first run.
3. Open the Dataset for video rows, `CHANNELS.json` for channel profiles and `OUTPUT` for status.

```json
{
  "channels": ["https://www.youtube.com/@NASA"],
  "tabs": ["videos"],
  "sort": "latest",
  "maxResults": 3,
  "includeChannelInfo": true,
  "includeDescription": false
}
```

Empty API input succeeds with zero output rows and zero result charges. Empty API input does not collect a sample automatically. The Console form prefills NASA for an intentional test run. A new run starts a new Dataset; it is not a continuation of an earlier run.

### What you receive

The Dataset keeps the native v1 video contract. Missing public evidence stays null rather than becoming an invented zero, date or verification flag.

| Output | Useful fields and meaning |
| --- | --- |
| Video identity | `id`, canonical `url`, `title`, `contentType`, `sourceChannel` |
| Channel context | `channelId`, `channelUrl`, `channelTitle` |
| Popularity | `views`, original `viewsText`, and `viewsPrecision`; abbreviations are not exact counts |
| Date evidence | `publishedText`, `displayedDate`, `dateSource`; `publishedAt` is null because exact timestamps are not inferred |
| Duration and image | `durationSeconds`, `durationText`, `thumbnail`, where available |
| Details and ordering | `description`, `descriptionComplete`, `detailsStatus`, `sortRequested`, `sortStatus`, `liveStatus` |
| Channel profile record | `CHANNELS.json`: available public description, links, subscribers, counts, images and status |
| Run summary | `OUTPUT`: delivery, errors, requests, date-filter uncertainty and budget status |

#### Real selected output

The following selected fields come from the NASA input above, captured on **October 13, 2026** from accepted private build **0.1.3**. It is a historical sample, not a forecast of the next run's titles or counts. Descriptions were not requested; approximate listing counts were preserved as text.

```json
{
  "contractVersion": 1,
  "id": "ErAqN6gXqZQ",
  "url": "https://www.youtube.com/watch?v=ErAqN6gXqZQ",
  "title": "NASA's SpaceX Crew-13 Mission (Official NASA Trailer)",
  "contentType": "video",
  "channelTitle": "NASA",
  "description": null,
  "descriptionComplete": false,
  "publishedText": "12d ago",
  "publishedAt": null,
  "views": null,
  "viewsText": "101K",
  "viewsPrecision": "abbreviated_or_unparsed",
  "durationSeconds": 62,
  "durationText": "1:02",
  "detailsStatus": "not_requested",
  "sortRequested": "latest",
  "sortStatus": "confirmed",
  "liveStatus": null
}
```

Thumbnail and profile image links may change or expire; do not treat them as permanent assets. This Actor does not download videos, audio, images or screenshots.

### Input reference

| Input | Default | How to use it |
| --- | --- | --- |
| `channels` | Empty | Public handles, IDs or channel URLs. Exact repeated strings are removed. |
| `tabs` | `["videos"]` | `videos`, `shorts`, `streams`, processed in supplied order under a shared cap. |
| `sort` | `latest` | `latest`, `popular`, `oldest` within each category, where native ordering is exposed. |
| `maxResults` | 30 | Limit per distinct trimmed input reference, 1–1000 in legacy mode. This is a cap, not a promised row count. |
| `includeDescription` | false | Request full public descriptions for selected unique rows. Unavailable detail retains the base row. |
| `includeChannelInfo` | false | Request extended profile fields, separately saved in `CHANNELS.json`. |
| `maxResultsShorts` / `maxResultStreams` | Unset | Supplying either activates independent limits: videos=`maxResults`, Shorts/streams default to 0. Each category accepts 0–1000. |
| `oldestPostDate` | Unset | `YYYY-MM-DD` at UTC midnight, or `N day` / `N days` relative to run start. Forces latest ordering. |
| `outputFormat` | `v1` | `streamers` adds a separate `COMPATIBILITY.json` record; it does not replace or change the Dataset. |
| `startUrls` | Unset | Migration alternative to `channels`; public channel URLs only. Do not supply both. |
| `sortVideosBy` | Unset | Migration alternative to `sort`: `NEWEST`, `POPULAR`, `OLDEST`. Do not supply both. |

For profiles without video rows, use all three independent limits as zero:

```json
{"channels":["https://www.youtube.com/@NASA"],"maxResults":0,"maxResultsShorts":0,"maxResultStreams":0,"includeChannelInfo":true}
```

Different references such as a channel URL and its `@handle` keep separate input quotas. Their shared video IDs are skipped globally; a later distinct video can fill the second quota. Only identical trimmed strings are merged.

`maxResults:0` alone remains invalid. Independent limits override `tabs` and process videos, then Shorts, then streams. Categories are not merged into one chronological feed. The advanced `detailConcurrency` control defaults to 8, accepts 1–32 and preserves listing order.

### Pricing

The `result-delivered` event is charged only after a valid unique video row is successfully written to the Dataset. These prices include platform usage:

| Apify tier | USD per 1,000 successful video rows |
| --- | ---: |
| FREE | $0.40 |
| BRONZE | $0.38 |
| SILVER | $0.36 |
| GOLD | $0.34 |
| PLATINUM | $0.34 |
| DIAMOND | $0.34 |

Channel profiles included with video rows have no additional fee. Regular videos, Shorts and streams use the same `result-delivered` event, only after a valid unique row is successfully committed to the Dataset. Empty input, invalid inputs, unavailable or failed listings and duplicates do not trigger that event. No start fee or minimum charge is part of this decision. At the approved FREE rate, three delivered rows would cost $0.0012; 1,000 would cost $0.40. These are price illustrations, not actual run costs or charged-run evidence.

Channel-only collection writes profile records to `CHANNELS.json` and no video rows, so it generates no `result-delivered` event. Full-description enrichment uses the same delivered-video event and has no separate description fee. A valid listing row is still delivered and charged when its optional description lookup is unavailable; inspect `descriptionComplete`, `detailsStatus` and `OUTPUT` for the outcome.

### Reliability and limitations

On October 14, 2026, build 0.1.8 delivered 1,000 ordinary NASA rows in each of two runs and 100 complete-description rows in each of two smaller runs. Shorts returned 52 and 53 of requested 100 with budget-exhaustion errors despite platform success. Check `OUTPUT.stoppedOnBudget`, errors and delivered counts; a successful platform status alone does not establish complete collection. An abort attempted after 30 observed rows arrived after the run completed 60; interrupted recovery was not verified, and no replacement or resurrection was run. These measured outcomes do not establish universal completeness or stability.

On October 13, 2026, build 0.1.3 delivered three unique NASA video rows with channel profiles, and the separate compatible export attached profile metadata to all three. A prior private run failed a Dataset enum check; the schema was corrected and the second run passed. This small smoke does not establish universal coverage, stability or a speed advantage.

- Public, unavailable, restricted or removed content may return fewer rows or errors. Other valid channels can continue.
- Unknown dates and relative-age intervals crossing a cutoff are retained and reported as incomplete date filtering. Month/year labels do not become exact timestamps; a complete date range is not guaranteed.
- `sortStatus` distinguishes confirmed native selection from requested ordering without returned selection evidence. Unsupported sorts are reported rather than silently replaced.
- `liveStatus` is `live`, `upcoming` or null; live audience and accumulated view counts are different measures.
- Counts may be abbreviated, fields absent and metadata partial. Compatibility field names do not mean every competitor field or value is identical.
- Interrupted or budget-limited collection retains a resumable state when available. The same run can reuse its Dataset and skip delivered IDs, but the October 14 live test did not verify an actual aborted-run resurrection. New runs have independent output and billing.
- Failed Dataset writes or state persistence stop the run. A charge failure is reported and is not retried for an already delivered row.

### Automation and integrations

Use Apify's Actor API to start runs, download Dataset exports and inspect run status. Add schedules for periodic monitoring and webhooks for downstream processing; connect results to spreadsheets, databases or supported Apify integrations. Keep a small limit when testing an automated workflow. This is a batch Actor, not a live web server.

See the [official Actor API documentation](https://docs.apify.com/api/v2/acts) and [Dataset export documentation](https://docs.apify.com/platform/storage/dataset).

### FAQ

**Do I need a YouTube login or API key?** No. This collects available public metadata, not private account content.

**Why is the Dataset empty for profile-only input?** Profiles are in `CHANNELS.json`; they do not become video rows or result events.

**Why is an exact view count or publication timestamp missing?** Listing abbreviations and relative ages are preserved honestly. `publishedAt` stays null; available watch calendar dates are kept separately.

**Can I migrate an existing channel-URL input?** Use `startUrls` instead of `channels`, `sortVideosBy` instead of `sort`, and optionally `outputFormat:"streamers"`. Read the compatibility wrapper's `items` array; the native Dataset remains unchanged.

**Does an empty result mean the whole channel has no videos?** No. Inspect `OUTPUT` for category errors, partial progress, limits and date uncertainty before drawing that conclusion.

**Can I continue a stopped run?** When resurrection is supported, use that same run so its Dataset and saved state remain available. Actual aborted-run recovery was not verified in the October 14 test. Starting a new run does not share prior delivery IDs.

### Responsible use and independence

Use public metadata responsibly and comply with applicable rules and YouTube's terms. This independently developed Actor is not affiliated with, endorsed by or operated by YouTube or Google. Platform names and logos identify the supported public data source.

#### Streamers compatibility format 2

`outputFormat: "streamers"` adds `COMPATIBILITY.json` with `formatVersion: 2` and `datasetContractVersion: 1`. Read migration rows from `items`: regular videos have 31 fields, Shorts 30 (without duration), and scheduled streams 32. Channel profiles and `aboutChannelInfo` have 16 fields. Missing profile booleans default to false in this projection; their original unknown values remain null in diagnostics. Native Dataset 25 fields, OUTPUT and CHANNELS retain source evidence.

For existing format 1 readers, move `items[index].compatibility.*` to `diagnostics.items[index].*`, including count precision, concurrent viewers, date sources and sort status. Video descriptions/completion and live/ended stream states also move to diagnostics; scheduled streamType remains in items. Channel diagnostics move from `channels[index].compatibility.*` to `diagnostics.channels[index].*`. Diagnostic index and channelIndex identify associations; missing or conflicting profiles are never attached by guesswork. Public progressKey and standardizedUrl derive from the source channel about URL, with no copied session identifiers.

# Actor input Schema

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

Public YouTube channel handles, IDs or URLs. Empty input succeeds with no results or result charges.

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

Legacy mode: processed in this order under a shared maxResults cap. Independent limits override tabs when maxResultsShorts or maxResultStreams is supplied.

## `sort` (type: `string`):

Uses YouTube native category ordering; unsupported orders are reported as category errors.

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

Legacy mode: shared maximum per channel (1–1000). Independent mode: videos maximum (0–1000), enabled by maxResultsShorts or maxResultStreams. Duplicates across channels are delivered once.

## `includeDescription` (type: `boolean`):

Additional public watch request only for selected items. Failed enrichment retains the basic row and descriptionComplete=false.

## `maxResultsShorts` (type: `integer`):

Optional: supplying this activates independent category limits. Unspecified Shorts and Streams limits are zero. Set all three limits to zero for channel-only output.

## `maxResultStreams` (type: `integer`):

Optional: supplying this activates independent category limits. Unspecified Shorts and Streams limits are zero. Set all three limits to zero for channel-only output.

## `detailConcurrency` (type: `integer`):

Maximum simultaneous selected-item detail requests. Results retain channel-list order.

## `oldestPostDate` (type: `string`):

Optional YYYY-MM-DD (UTC day boundary) or N day / N days (rolling run-start cutoff). Forces latest order. Unknown and boundary-uncertain dates are retained and reported in OUTPUT.dateFilter.

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

Fetch channel About once per channel. Profile fields appear in OUTPUT.channels and CHANNELS.json; unavailable fields remain null. Adds up to one upstream request per channel.

## `startUrls` (type: `array`):

Alternative to channels. Public YouTube channel URLs only; cannot be combined with channels.

## `sortVideosBy` (type: `string`):

Alternative to sort; cannot be combined with sort.

## `outputFormat` (type: `string`):

streamers writes COMPATIBILITY.json using competitor field names plus explicit precision and semantics. Dataset remains v1.

## Actor input object example

```json
{
  "channels": [
    "https://www.youtube.com/@NASA"
  ],
  "tabs": [
    "videos"
  ],
  "maxResults": 30,
  "includeDescription": false,
  "detailConcurrency": 8,
  "includeChannelInfo": false,
  "outputFormat": "v1"
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

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

No description

## `compatibility` (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("meka.im/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": ["https://www.youtube.com/@NASA"] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,meka.im/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/1HwpISyfoavVvgAXY/builds/GdMCvAVGlEtiCFxl2/openapi.json
