# YouTube Shorts Scraper (`scraper_creator/youtube-shorts-scraper`) Actor

Scrape public YouTube Shorts from channel URLs. Collect video titles, descriptions, publish dates, views, likes, comments, and channel information. Supports pagination and configurable result limits. Unavailable metrics are returned as null.

- **URL**: https://apify.com/scraper_creator/youtube-shorts-scraper.md
- **Developed by:** [Scraper Creator](https://apify.com/scraper_creator) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 youtube shorts

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

## YouTube Shorts Scraper

Collect public YouTube Shorts and engagement statistics from channel URLs. Get video titles, descriptions, URLs, publication dates, views, likes, comment counts, and channel subscriber counts in a structured dataset for reporting and analysis.

The Actor reads the channel's Shorts tab, newest first, and follows pagination to older Shorts. It does not require a YouTube API key or login cookies, and it does not download videos.

### How to use

1. Add one to five public YouTube channel URLs.
2. Set the maximum number of Shorts to return **per channel**. The default is 100; the allowed range is 1–10,000.
3. Optionally configure a proxy under **Advanced settings**. Direct connections are used by default.
4. Start the Actor, inspect the output and run summary, then export the dataset or retrieve it through the Apify API.

The maximum is a limit, not a guaranteed result count. A channel may have fewer accessible Shorts, and individual videos or pages may fail to load. Allow enough run time when requesting large result sets.

### Input

```json
{
  "channels": ["https://www.youtube.com/@YouTube"],
  "maxResultsShorts": 100
}
```

| Field | Required | Description |
| --- | --- | --- |
| `channels` | Yes, unless using `channelUrls` | Array of 1–5 HTTPS YouTube channel URLs. |
| `maxResultsShorts` | No | Maximum returned Shorts per channel, from 1 to 10,000. Defaults to 100. |
| `proxyConfiguration` | No | Optional Apify proxy configuration. Omit to connect directly. |

Accepted channel paths include `/@handle`, `/channel/UC...`, `/c/name`, and `/user/name`. Channel URLs ending in `/shorts` are also accepted. Use `youtube.com` or `www.youtube.com` without query parameters or URL fragments. Individual video URLs are not supported as input.

#### API input aliases

For integrations that use alternative field names, `channelUrls` is an alias for `channels`, and `maxShortsPerChannel` is an alias for `maxResultsShorts`:

```json
{
  "channelUrls": ["https://www.youtube.com/@YouTube"],
  "maxShortsPerChannel": 100
}
```

Use either naming convention. If both are supplied, their values must agree. The optional API field `sortChannelShortsBy` accepts only `"NEWEST"`; newest-first ordering is already the default.

#### Optional proxy

If direct requests are blocked, you can configure a proxy in the input form or JSON:

```json
{
  "channels": ["https://www.youtube.com/@YouTube"],
  "maxResultsShorts": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

Proxy availability depends on your account and the selected service. Proxies may add cost and do not guarantee access to YouTube. Check the Actor's pricing and your proxy rates before running.

### Output

Each dataset row represents one Short. The following is a saved example, not live statistics:

```json
{
  "id": "AOVf1JmEeS8",
  "type": "shorts",
  "url": "https://www.youtube.com/shorts/AOVf1JmEeS8",
  "title": "the ICONIC Victoria's Secret angel wings... but make it rug version",
  "text": "tune in this sunday and watch the angels take the runway #YouTubePartner",
  "date": "2026-10-16T22:00:58.000Z",
  "channelId": "UCBR8-60-B28hp2BmDPdntcQ",
  "channelUrl": "https://www.youtube.com/channel/UCBR8-60-B28hp2BmDPdntcQ",
  "channelUsername": "YouTube",
  "inputChannelUrl": "https://www.youtube.com/@YouTube",
  "viewCount": 8210,
  "likes": 228,
  "commentsCount": 126,
  "numberOfSubscribers": 46500000,
  "subscriberCountText": "46.5M subscribers",
  "subscriberCountIsApproximate": true,
  "hashtags": ["#YouTubePartner"],
  "scrapedAt": "2026-10-17T07:40:09.563Z",
  "warnings": ["subscriber_count_approximate"]
}
```

| Field | Description |
| --- | --- |
| `id`, `type`, `url` | Video ID, the value `shorts`, and the Shorts URL. |
| `title`, `text` | Video title and description. The description may be `null`. |
| `date` | Publication timestamp in UTC ISO 8601 format. |
| `channelId`, `channelUrl`, `channelUsername` | Publishing channel ID, canonical channel URL, and handle. The handle may be `null`. |
| `inputChannelUrl` | Normalized channel URL associated with the input. |
| `viewCount` | Public view count as an integer. |
| `likes`, `commentsCount` | Public like and comment counts as integers, or `null` when unavailable. |
| `numberOfSubscribers` | Channel subscriber count. Compact labels are converted to approximate integers; unavailable counts are `null`. |
| `subscriberCountText` | Original subscriber label, such as `41.5K subscribers`, or `null`. |
| `subscriberCountIsApproximate` | Whether the subscriber count was converted from a compact label. |
| `hashtags` | Hashtags displayed by YouTube above the video title, including `#` and display order. Empty when none are available. |
| `scrapedAt` | Time this row was assembled, in UTC ISO 8601 format. |
| `warnings` | Notices about unavailable counts or approximate subscriber counts. |

#### Data accuracy

- **Subscriber counts can be approximate.** For example, `41.5K` becomes `41500`, with `subscriberCountIsApproximate: true`. This is not an exact count from the channel owner's analytics. Use `subscriberCountText` and the approximation flag when displaying the value.
- **Unknown counts stay `null`.** Unavailable or rounded like and comment counts are not converted into exact numbers. A confirmed zero is returned as `0`.
- **Hashtags reflect YouTube's displayed selection.** They are not every hashtag mentioned in the title or description. The selection and order may change between runs.
- **Counts are snapshots.** Statistics can change during or after a run. Channel subscriber information is read at the start of processing that channel and repeated on its video rows.

### Partial results and errors

Inspect `RUN-SUMMARY` in the run's default key-value store when checking completeness. It contains per-channel status, result counts, and errors.

- A failed video is skipped so other videos can still be processed.
- A failed channel or pagination request preserves results already collected and allows the next channel to proceed.
- A run with some valid results may finish successfully while `RUN-SUMMARY.partial` is `true`. Always check the summary if complete coverage matters.
- An exhausted pay-per-event budget or an abort signal stops collection and sets `RUN-SUMMARY.stoppedEarly` to `true`. With no recorded errors, the run status is `stopped` even when `partial` is `false`; channels not yet attempted may be absent from the summary. Check the run status, `stoppedEarly`, per-channel statuses, and coverage of the requested channels rather than treating `partial: false` as proof of completion. If errors also occurred, the run status may instead be `partial` or `failed`.
- If errors occur and no valid results are available after all channels have been attempted, the run fails.
- Storage or charging failures stop the run. Error records are not added to the video dataset.

Per-channel status `limit_reached` means the requested maximum was reached; it does not mean the channel has no more Shorts. `no_shorts` means the channel did not expose a Shorts tab. A public channel with no accessible Shorts produces no video rows, including no standalone subscriber-count row.

Missing video identity, owner identity, an exact view count, or a valid publication timestamp causes the video to be skipped. Videos owned by another channel are also skipped.

### Refreshing statistics

Start a new run with a fresh default dataset to refresh counts. Each new run begins with the newest Shorts and continues until it reaches the per-channel limit or the end of the available feed. With a limit of 100, older videos outside those results will not be refreshed.

Within the same run, duplicate video IDs are removed. If a run restarts with its existing dataset, already written videos are skipped rather than refreshed.

### Scope and limitations

- Collects publicly accessible channel Shorts only. It does not collect regular long-form videos, private videos, or owner-only analytics.
- Returns comment counts, not comment text, subtitles, or transcripts.
- Does not download video or audio files.
- Public availability, network restrictions, and changes to YouTube may affect coverage, speed, and data availability. The 10,000-result input limit is not a guarantee that all requested results can be collected.
- Available subscriber counts are public display values, not authenticated YouTube Studio figures.

# Changelog

This Actor's version history is a separate document: https://apify.com/scraper_creator/youtube-shorts-scraper/changelog.md

# Actor input Schema

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

HTTPS YouTube channel URLs such as https://www.youtube.com/@YouTube. Video URLs are not accepted.

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

Maximum returned Shorts for each channel, including older posts. Defaults to 100.

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

Optional. Omit for direct connections. An Apify or custom proxy can help when the hosting IP is blocked; proxy usage has a separate cost.

## Actor input object example

```json
{
  "channels": [
    "https://www.youtube.com/@YouTube"
  ],
  "maxResultsShorts": 100
}
```

# Actor output Schema

## `shorts` (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/@YouTube"
    ],
    "maxResultsShorts": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraper_creator/youtube-shorts-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/@YouTube"],
    "maxResultsShorts": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("scraper_creator/youtube-shorts-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/@YouTube"
  ],
  "maxResultsShorts": 100
}' |
apify call scraper_creator/youtube-shorts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scraper_creator/youtube-shorts-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/nJM0YkUPPMdTGbFzv/builds/TJa0qbcMRJMKfbCKO/openapi.json
