# YouTube Shorts Viral Trend Tracker (`fanndev/youtube-shorts-trend-tracker`) Actor

Track what is going viral on YouTube Shorts by hashtag. Returns the ranked Shorts grid with each clip's exact views, likes, like-to-view ratio, duration, sound attribution, hashtags and channel. Schedule it to watch growth. Shorts only. No login.

- **URL**: https://apify.com/fanndev/youtube-shorts-trend-tracker.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/fanndev) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 Viral Trend Tracker

See what is actually going viral on YouTube Shorts, by hashtag, with the numbers
you need to rank it.

Give it hashtags. It returns YouTube's own ranked grid of Shorts for each one,
then opens each clip for the figures the grid does not carry: **exact views,
likes, the like-to-view ratio, duration, sound attribution and hashtags**.

Shorts only — a regular upload that sneaks into a hashtag grid is flagged
(`isShortFormat: false`) rather than quietly mixed in.

No login, no cookies, no API key.

### What you get

```json
{
  "hashtag": "cooking",
  "gridPosition": 1,
  "title": "Frog Eggs Time Challenge! ⏱️🐸🧪",
  "channelName": "Meow Nhi Nhi",
  "viewCount": 3397251,
  "likeCount": 36218,
  "likeToViewPercent": 1.0661,
  "likeCountIsApprox": false,
  "lengthSeconds": 52,
  "soundAttribution": "Original Sound",
  "hashtags": ["Mukbang", "buldak", "buldakchallenge", "cooking", "foodchallenge"],
  "url": "https://www.youtube.com/shorts/FX4RT1cp7Rs"
}
```

`gridPosition` is YouTube's own ranking for that hashtag — it *is* the trend
signal, so it rides along on every record and enrichment never reorders anything.

### Why the per-Short fetch is on by default

The hashtag grid alone cannot rank anything. Measured 2026-09-20:

| | Hashtag grid | Short's own page |
| --- | --- | --- |
| Views | **rounded** — "3.3 million" | exact — `3,397,251` |
| Likes | **none at all** | yes |
| Like-to-view ratio | impossible | yes |
| Sound | no | yes |
| Duration | no | yes |
| Cost | 1 request per hashtag | 1 request per Short |

Set `detail: false` if you only want the ranked list and can live with
3.3M-sized buckets.

### Two kinds of like count

| Surface | Like figure | Sound? |
| --- | --- | --- |
| `/shorts/<id>` (default) | rounded — "36 thousand" → `36000` | yes |
| `/watch?v=<id>` (`exactLikes: true`) | exact — `36,218` | no |

Every record carries `likeCountIsApprox` so a rounded figure is never presented
as an exact one. If you ask for `exactLikes` **and** the Short's page has no
sound attribution, the Actor spends a second request to go get it — that is the
only path that costs two requests per Short.

### Tracking growth over time

Run the same hashtags on a schedule. Each run stamps `_scrapedAt`, so two runs
of `#cooking` give you the delta in `viewCount`, `likeCount` and `gridPosition`
per `videoId` — which is the growth-rate signal. The Actor does not keep state
between runs; comparing datasets is yours to do.

### Known limits, stated plainly

- **36 Shorts per hashtag.** That is one grid page, and it is what YouTube
  serves. The page carries a single continuation token; this Actor does not
  follow it. Ranked top-36 is the useful part of a trend anyway.
- **No historical data.** YouTube exposes the grid as it is right now. Growth
  requires scheduling (above).
- **Sound attribution is often just "Original Sound".** That is what YouTube
  reports for most Shorts; a licensed track shows its title instead.

### Reliability

The hashtag grid measured unusually stable — nine fetches across three TLS
profiles on 2026-09-20 returned 37 lockups and 36 view figures **every single
time**. Individual Shorts pages behave like watch pages and occasionally arrive
without their payload, so the Actor retries up to five times, rotating TLS
profile, before emitting `recordType: "REDUCED"`. A `REDUCED` record still
carries its grid figures — you lose the exact numbers, not the row.

### Input example

```json
{
  "mode": "hashtag",
  "hashtags": ["cooking", "fyp", "asmr"],
  "shortsPerHashtag": 36,
  "detail": true,
  "exactLikes": true,
  "concurrency": 4
}
```

# Actor input Schema

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

hashtag = the ranked Shorts grid for each hashtag. video = figures for Shorts you already have IDs for. reference = probe both surfaces and report what they yielded.

## `hashtags` (type: `array`):

With or without the leading #. Full /hashtag/ URLs also work.

## `videos` (type: `array`):

Video IDs, /shorts/ links or watch URLs.

## `shortsPerHashtag` (type: `integer`):

Capped at 36 because that is what one grid page lists. The grid exposes a single continuation token which this Actor does not follow - see the README.

## `detail` (type: `boolean`):

On: one extra request per Short, giving exact views, likes, the like-to-view ratio, duration and sound. Off: grid only, which means ROUNDED views ("3.3 million") and no likes at all.

## `exactLikes` (type: `boolean`):

The /shorts/ page rounds likes to "36 thousand"; the watch page gives 36,212. Turning this on switches surface. It costs a second request per Short only when you also want the sound attribution, which the watch page does not carry.

## `concurrency` (type: `integer`):

Parallel detail fetches.

## `tlsProfile` (type: `string`):

Optional. The hashtag grid answered identically on all four during recon; this is a tuning knob.

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

Optional. Useful if Shorts pages start coming back as REDUCED.

## Actor input object example

```json
{
  "mode": "hashtag",
  "hashtags": [
    "cooking",
    "fyp"
  ],
  "shortsPerHashtag": 36,
  "detail": true,
  "exactLikes": false,
  "concurrency": 4,
  "tlsProfile": "chrome124"
}
```

# Actor output Schema

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

Every Short, reduced-page and error record produced by this run.

# 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 = {
    "hashtags": [
        "cooking",
        "fyp"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fanndev/youtube-shorts-trend-tracker").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 = { "hashtags": [
        "cooking",
        "fyp",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fanndev/youtube-shorts-trend-tracker").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 '{
  "hashtags": [
    "cooking",
    "fyp"
  ]
}' |
apify call fanndev/youtube-shorts-trend-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fanndev/youtube-shorts-trend-tracker"
        }
    }
}
```

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/u9Lv9vHgnowbf8LdH/builds/1nlINVn4Qb4cd5SnH/openapi.json
