# YouTube Shorts Scraper - Growth & Audience Insights (`trakk/youtube-shorts-scraper`) Actor

Scrape YouTube Shorts from channels and keyword searches. Get video metrics, available transcripts, comments, replies and optional author avatars. Track growth across runs and discover audience questions, product requests and content ideas backed by real comments.

- **URL**: https://apify.com/trakk/youtube-shorts-scraper.md
- **Developed by:** [Kelopr\_bk](https://apify.com/trakk) (community)
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 shorts

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

<h1 align="center">▶️ YouTube Shorts Scraper</h1>
<p align="center"><strong>Find Shorts. Understand their growth. Hear what viewers are asking for.</strong></p>
<p align="center">📊 Video metrics &nbsp; · &nbsp; 📝 Transcripts &nbsp; · &nbsp; 💬 Comments &nbsp; · &nbsp; 🎯 Audience requests</p>

Collect public Shorts from channels or keyword searches. Export video metrics, creator details, available transcripts and optional comment samples. Track the same Shorts across runs to measure growth, and turn explicit viewer questions into an evidence-backed research list.

**New here?** Keep the starter example, click **Start**, then open **Overview**. It collects a small sample of real Shorts. Increase the result limit when you are ready.

### ⚡ Choose what you need

| Your task | Settings | What you receive |
|---|---|---|
| Collect video statistics quickly | **Fast** | Titles, URLs, views, likes, total comment counts, dates, duration and channel details |
| Read what is said in each Short | **Full** | Everything in Fast, plus available public caption text |
| Read audience reactions | Turn on **Collect comment texts** | A separate Comments table with text, authors, likes and source links |
| Follow conversations | Also turn on **Include replies** | Replies linked to parent comments, within your limits |
| Keep profile pictures | Turn on **Save commenter avatars** | Saved image files, once per author per run |
| Find questions and requests | Keep **Find audience questions and requests** on | Matching comments in Questions, plus grouped evidence in Audience requests |
| Track growth over time | Reuse a **History workspace** | Measured changes between runs and comparisons at similar video ages |

**Fast / Full controls transcripts.** Comments, replies and avatars are separate optional switches. Adding them increases the work even if Fast is selected.

### 🚀 Start in three steps

1. **Choose your sources.** Enter channel handles/URLs, search phrases, or both. One phrase per line.
2. **Choose the depth and limits.** Select Fast or Full, set Shorts per source, and enable comments or avatars if needed.
3. **Run and export.** Open the result view you need, then download JSON, CSV or Excel.

`maxResultsShorts` applies **per channel or search phrase**. `maxTotalResults` is an additional whole-run cap. Duplicates and records excluded by the publication-date filter do not consume the saved-result allowance.

### 🧩 Copy-ready examples

#### 1. Statistics for a channel

```json
{
  "channels": ["MrBeast"],
  "mode": "fast",
  "maxResultsShorts": 50
}
```

#### 2. Search a niche and collect transcripts

```json
{
  "searchQueries": ["space facts"],
  "mode": "full",
  "maxResultsShorts": 30,
  "transcriptLanguage": "auto"
}
```

#### 3. Research audience questions

```json
{
  "searchQueries": ["camera review"],
  "mode": "fast",
  "maxResultsShorts": 10,
  "includeComments": true,
  "maxCommentsPerShort": 50,
  "maxCommentsTotal": 500,
  "commentsSort": "newest",
  "analyzeAudience": true,
  "downloadAvatars": false
}
```

#### 4. Transcripts, conversations and saved avatars

```json
{
  "channels": ["MrBeast"],
  "mode": "full",
  "maxResultsShorts": 10,
  "includeComments": true,
  "maxCommentsPerShort": 20,
  "maxCommentsTotal": 200,
  "includeReplies": true,
  "maxRepliesPerComment": 3,
  "downloadAvatars": true,
  "maxAvatarDownloads": 200
}
```

#### 5. Measure growth on later runs

```json
{
  "channels": ["MrBeast"],
  "mode": "fast",
  "maxResultsShorts": 50,
  "trackHistory": true,
  "historyKey": "my-creator-watchlist",
  "minObservationIntervalSeconds": 900,
  "comparisonAgeHours": 24
}
```

Run the same input again later. The Actor does not schedule itself or wait for another measurement. Use Apify scheduling separately if you want recurring runs.

### 📂 Where to find the results

| View | Contents |
|---|---|
| **Overview** | One row per saved Short, with its main statistics |
| **Analytics** | Engagement rates, duration and lifetime average views/day |
| **Growth** | Observed view changes, growth rate and stage |
| **Comparisons** | Age-matched channel baselines and outlier ratios |
| **Transcripts** | Available caption text, language, status and opening text |
| **Comments** | All saved comment texts and optional author avatars |
| **Questions** | Only matching viewer comments; creator-authored questions are excluded |
| **Audience requests** | Grouped request types, sample sizes and evidence |
| **Shared topics** | Shared phrases/hashtags across different creator channels |
| **Compact** | Alternative core field names for compact exports |

Comments are stored in a separate dataset and linked to Shorts by `videoId`. Questions are a filtered research copy of matching comments. The `OUTPUT` record explains limits, coverage and failures. `AUDIENCE` and `TOPICS` contain aggregate results.

### 💬 Comment counts, texts and replies

**Total comments and collected comments are different.** `commentsCount` is the numeric counter shown by YouTube. `commentsCollected` is how many comment records this run actually saved for that Short. A video can have 12,481 comments while your sample contains 20.

- The total counter is collected even when comment texts are switched off.
- `maxCommentsPerShort` includes replies when replies are enabled.
- `maxCommentsTotal` limits the combined comment output across the run.
- `commentsSort` supports Popular (`top`) and Newest (`newest`).
- Each comment ID is saved once per run. Repeated authors remain separate comments.
- A checked reply sample can show an observed creator response. It cannot prove that no response exists outside that sample.

Comment rows include text, author name/handle/channel link, likes and their precision, reply count, pin/creator-heart flags when available, and a source link. YouTube often supplies a relative date such as “2 days ago”. We preserve it in `publishedTimeText`; an exact `publishedAt` is not invented.

### 🖼️ Optional avatars

Avatar downloads are **off by default**. Off means no commenter-image files are fetched or exposed for image previews. On saves one image per author per run and reuses it across that author's comments. `authorAvatarUrl` links to the saved file; `avatarStatus` explains failures, missing images or a reached limit.

The code supports a separate `avatar_saved` event only after successful file storage, and `comment_saved` only after successful comment storage. Events are used only when already configured on the platform. Monetization is not configured by the Actor itself.

### 🎯 What audience analysis tells you

The Actor finds explicit phrases about purchase links, prices, product models/features, tutorials, follow-ups, alternatives and reported problems. Each signal keeps the original comment and matched phrase. Aggregates count distinct author channel IDs and expose the number of sampled comments.

Phrase rules cover English, Russian, Spanish and Portuguese. This is transparent text matching, not a prediction that someone will buy, and not a general AI sentiment model. Unmatched comments remain in Comments. Generic praise does not become a buying signal.

### 📝 How transcripts work

Full mode attempts to retrieve public YouTube captions. `auto` selects an available track, preferring manual captions and then English. A specified language selects that language when available; the Actor does not silently substitute another language or generate a translation.

| Field | Meaning |
|---|---|
| `transcript` | Caption text returned by YouTube |
| `transcriptLanguage` | Language of the selected track |
| `transcriptIsAutoGenerated` | Whether YouTube marks the track as automatic captions |
| `openingText` | Caption segments starting within the first five seconds |
| `transcriptStatus` | `ok`, `no_captions`, `language_unavailable`, `empty`, `unavailable`, `timeout`, `error` or `not_requested` |

Captions can contain recognition errors or sound labels. Word counts use whitespace-separated tokens and are not linguistic segmentation for every language. Missing captions never become text generated from the title or description.

### 📈 Growth and fairer comparisons

The first observation has no invented history. Two sufficiently spaced observations allow `viewsDelta` and `observedViewsPerHour`. Three allow comparison of recent growth rates. Four can support the defined second-wave heuristic. The default minimum interval is 15 minutes. Decreases in YouTube counters are labeled as corrections.

For age-matched comparisons, the default target is 24 hours after publication, with an explicit ±25% age window. The baseline uses at least five *other* Shorts from the same channel, one actual observation per Short. No observation near the requested age means a null ratio and a clear status. Starting to track an old Short cannot reconstruct its first-day views.

Shared-topic groups use the search phrase, hashtags or adjacent words from titles. They describe the collected sample, not all of YouTube, and do not infer the visual content of a video.

### ⚙️ Important settings and limits

| Setting | Default / meaning |
|---|---|
| `scrapeType` | `auto`: use supplied channels and searches; optionally restrict to `channels` or `search` |
| `outputFormat` | `standard` or `compact`; independent of Fast / Full |
| `sortChannelShortsBy` | `NEWEST`, `POPULAR` or `OLDEST` for channel inputs |
| `oldestPostDate` | Inclusive publication cutoff: ISO date, Unix seconds/milliseconds or a window such as `30 days` |
| `trackHistory`, `historyKey` | Remember observations and keep separate monitoring lists |
| `maxRunSeconds` | 60 seconds by default; maximum 120 |
| Source inputs | Up to 20 channels/search phrases combined |
| Comments | Up to 500 per Short and 10,000 across a run |
| Avatars | Up to 1,000 distinct authors per run |

Separate resource protections bound source requests, response sizes, transfer and estimated cost, and stop prolonged collection without matching results. These protections cannot be increased through input fields. A result cap is a maximum, not a promise to fetch that many regardless of time, source availability or resource limits. `OUTPUT.resourceBudget` explains any resource stop.

### ❓ Common questions

**Why are some fields null?** YouTube may hide or omit them. Disabled comments, hidden likes and unavailable captions have explicit statuses. Zero and false values are preserved.

**What is `dataStatus: complete`?** Core video metadata is present, and likes/comments are available or explicitly hidden/disabled. Transcript, comment-text and avatar coverage are reported separately.

**Why did the date filter return nothing?** The discovered Shorts may all be older than the cutoff. The run reports the cutoff, counts and a correction suggestion. It never relaxes your filter silently.

**Why did a run stop early?** A source, saved-record, page, time, spending or owner resource limit may have been reached. Saved records remain available and the stop reason is reported.

**Are all schema fields implemented?** The preserved fields for translations, `subtitles`, AI summaries, collaborators and monetization can remain null. New transcripts are in `transcript`. Channel age restrictions are not inferred from a family-safety flag.

**How is speed measured?** Record the exact preset. Fifty metadata records and thirty Shorts with hundreds of comments and images are different workloads. Source response times and caption availability vary; see the validation report for measured runs.

**Does it change prices or publish itself?** No. This is currently a private development Actor with no configured monetization.

# Actor input Schema

## `mode` (type: `string`):

Fast collects metrics, history and topic analysis. Full additionally retrieves available public captions.

## `scrapeType` (type: `string`):

Auto processes supplied channels and searchQueries together.

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

YouTube channel handles, IDs or URLs. Up to 20 combined channel and search inputs per run.

## `searchQueries` (type: `array`):

One literal search phrase per entry. Only YouTube Shorts are selected. Limit applies independently to each phrase.

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

Maximum saved Shorts per channel or search phrase. The run time and resource limits can stop collection earlier; OUTPUT explains the stop reason.

## `sortChannelShortsBy` (type: `string`):

Use the channel Shorts tab sorting order.

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

ISO date, Unix seconds/milliseconds or relative time such as 30 days. Inclusive cutoff. Month = 30 days, year = 365 days.

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

Standard returns the full record. Compact returns a smaller core record with alternate field names. Both include analytics and requested transcript fields.

## `deduplicate` (type: `boolean`):

Save each Short ID once across the run.

## `maxConcurrency` (type: `integer`):

Maximum simultaneous source requests.

## `maxPages` (type: `integer`):

Maximum discovery pages per channel.

## `maxRunSeconds` (type: `integer`):

Collection time limit, up to 120 seconds. Saved records are retained. Independent owner resource limits can stop the run sooner.

## `maxRetries` (type: `integer`):

Retries after transient source failures.

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

Apify proxy or custom proxy configuration.

## `trackHistory` (type: `boolean`):

Compare metrics across runs and build age-matched channel baselines.

## `historyKey` (type: `string`):

Reuse this name across runs to compare observations. Use distinct names for separate monitoring lists.

## `minObservationIntervalSeconds` (type: `integer`):

Minimum spacing used to calculate growth. Fifteen minutes by default. The Actor does not wait or schedule another run.

## `comparisonAgeHours` (type: `integer`):

Use actual observations within ±25% of this age. No historical values are invented or extrapolated.

## `baselineMinSamples` (type: `integer`):

Minimum other Shorts from the same channel with observations near the chosen age.

## `historySnapshots` (type: `integer`):

Use up to this many recent run snapshots, capped at 20,000 observations.

## `analyzeTopics` (type: `boolean`):

Group saved Shorts by search phrase, hashtag or adjacent title phrase. Results are in the TOPICS output.

## `topicMinChannels` (type: `integer`):

Require this many different channel IDs for a shared topic.

## `transcriptLanguage` (type: `string`):

Auto selects an available caption language, preferring manual tracks and English. A requested missing language is reported explicitly.

## `maxTotalResults` (type: `integer`):

Hard cap on all saved Shorts across the run, in addition to each source limit.

## `includeComments` (type: `boolean`):

Save comments in a separate table. The total numeric commentsCount is collected even when this is off.

## `maxCommentsPerShort` (type: `integer`):

Maximum saved comment records per Short, including replies when enabled.

## `maxCommentsTotal` (type: `integer`):

Hard limit across all Shorts. Duplicate comment IDs are saved once.

## `commentsSort` (type: `string`):

Use the source comment order.

## `includeReplies` (type: `boolean`):

Replies share the per-Short and total comment limits.

## `maxRepliesPerComment` (type: `integer`):

Maximum replies to one parent. Also constrained by the overall comment limits.

## `analyzeAudience` (type: `boolean`):

Find explicit purchase, price, product, tutorial, follow-up, alternative and problem phrases with original comment evidence. Requires comments.

## `downloadAvatars` (type: `boolean`):

Download and store an avatar once per author per run. Files are not fetched when this is off. A successful file save is eligible for the avatar\_saved event if that event is configured.

## `maxAvatarDownloads` (type: `integer`):

Maximum distinct author avatars to save.

## `maxCommentPages` (type: `integer`):

Maximum total source pages, including reply pages.

## `commentsTimeoutSeconds` (type: `integer`):

Bounded time for fetching each Short comment sample.

## Actor input object example

```json
{
  "mode": "fast",
  "scrapeType": "auto",
  "channels": [
    "MrBeast",
    "NASA"
  ],
  "maxResultsShorts": 3,
  "sortChannelShortsBy": "NEWEST",
  "outputFormat": "standard",
  "deduplicate": true,
  "maxConcurrency": 10,
  "maxPages": 100,
  "maxRunSeconds": 60,
  "maxRetries": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  },
  "trackHistory": true,
  "historyKey": "default",
  "minObservationIntervalSeconds": 900,
  "comparisonAgeHours": 24,
  "baselineMinSamples": 5,
  "historySnapshots": 48,
  "analyzeTopics": true,
  "topicMinChannels": 2,
  "transcriptLanguage": "auto",
  "maxTotalResults": 10000,
  "includeComments": false,
  "maxCommentsPerShort": 20,
  "maxCommentsTotal": 10000,
  "commentsSort": "top",
  "includeReplies": false,
  "maxRepliesPerComment": 5,
  "analyzeAudience": true,
  "downloadAvatars": false,
  "maxAvatarDownloads": 1000,
  "maxCommentPages": 20,
  "commentsTimeoutSeconds": 20
}
```

# Actor output Schema

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

No description

## `analytics` (type: `string`):

No description

## `compact` (type: `string`):

No description

## `growth` (type: `string`):

No description

## `comparisons` (type: `string`):

No description

## `transcripts` (type: `string`):

No description

## `topics` (type: `string`):

No description

## `comments` (type: `string`):

No description

## `questions` (type: `string`):

No description

## `audience` (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 = {
    "mode": "fast",
    "channels": [
        "MrBeast",
        "NASA"
    ],
    "maxResultsShorts": 3,
    "includeComments": false,
    "downloadAvatars": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("trakk/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 = {
    "mode": "fast",
    "channels": [
        "MrBeast",
        "NASA",
    ],
    "maxResultsShorts": 3,
    "includeComments": False,
    "downloadAvatars": False,
}

# Run the Actor and wait for it to finish
run = client.actor("trakk/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 '{
  "mode": "fast",
  "channels": [
    "MrBeast",
    "NASA"
  ],
  "maxResultsShorts": 3,
  "includeComments": false,
  "downloadAvatars": false
}' |
apify call trakk/youtube-shorts-scraper --silent --output-dataset

```

## MCP server setup

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