# YouTube Rank Tracker (`aerodynamic_tripod/youtube-rank-tracker`) Actor

Track where public YouTube videos rank for keywords across countries and languages. Monitor current and previous positions, rank changes, history, and video metadata across repeated runs.

- **URL**: https://apify.com/aerodynamic\_tripod/youtube-rank-tracker.md
- **Developed by:** [SearchShark Tools](https://apify.com/aerodynamic_tripod) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 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

## YouTube Rank Tracker

**YouTube Rank Tracker** lets you monitor where **public YouTube videos appear in YouTube search results** for the keywords, countries, and languages you care about.

Track your own videos, compare competitors, monitor SEO movement over time, and build persistent ranking history without manually repeating YouTube searches.

- **Track target videos:** monitor one or many YouTube videos against one or many keywords
- **Measure rank movement:** compare current rank, previous rank, and rank change
- **Build ranking history:** keep best, worst, and average observed rank across repeated runs
- **Localize searches:** track by country and language
- **Inspect YouTube metadata:** capture title, channel, thumbnail, and result details when ranked
- **Run efficiently:** each normalized keyword is searched once, then all target videos are checked against the same result set
- **Automate monitoring:** use Apify Schedules, API, and integrations for recurring rank checks

***

### What data does YouTube Rank Tracker return?

| Field | Meaning |
| --- | --- |
| **keyword** | Search query being tracked |
| **targetVideoId** | Normalized 11-character YouTube video ID |
| **targetUrl** | Canonical YouTube target URL |
| **country** | Country used for the search request |
| **language** | Language used for the search request |
| **currentRank** | Current observed video rank, or `null` when not found |
| **previousRank** | Previous observed numeric rank |
| **rankChange** | `previousRank - currentRank` when both ranks are numeric |
| **status** | Ranking transition status |
| **bestRank** | Best numeric rank observed so far |
| **worstRank** | Worst numeric rank observed so far |
| **averageRank** | Average across ranked observations |
| **checkCount** | Total valid observations recorded |
| **rankedCheckCount** | Number of observations with a numeric rank |
| **searchedResultCount** | Number of normalized video results checked |
| **title** | Video title when the target is found |
| **channelName** | Channel name when available |
| **channelId** | Channel ID when available |
| **thumbnailUrl** | Thumbnail URL when available |
| **resultType** | Result type for a matched target |
| **firstTrackedAt** | Timestamp of the first valid observation |
| **previousCheckedAt** | Timestamp of the previous valid observation |
| **checkedAt** | Timestamp of the current observation |
| **error** | Keyword-level error message when a search fails |

> Missing rank values are returned as `null`. The Actor does not invent a ranking position when the target is not present in the fetched search results.

***

### Features

YouTube Rank Tracker is designed for **YouTube SEO monitoring, competitor tracking, and recurring search-position analysis**.

- **Multiple keywords:** track several search queries in one Actor run
- **Multiple target videos:** check several public YouTube videos for every keyword
- **One search per keyword:** all target videos are matched against the same ordered result set
- **Keyword normalization:** extra whitespace is normalized
- **Keyword deduplication:** duplicate keywords are removed case-insensitively while preserving the first spelling and order
- **Video normalization:** supports raw 11-character YouTube video IDs and supported YouTube video URL forms
- **Video deduplication:** equivalent target URLs and IDs are normalized to the same video
- **Country and language localization:** send locale values with each YouTube search
- **Persistent history:** compare observations across separate Actor runs
- **Rank transitions:** detect improved, dropped, unchanged, new, lost, and still-unranked states
- **Historical statistics:** preserve best, worst, average rank, total checks, and ranked checks
- **Video metadata:** return title, channel, thumbnail, and result type when the target is found
- **Partial failure protection:** one failed keyword does not stop later keywords
- **History protection on failure:** failed keyword searches do not mutate rank history
- **Dataset-friendly output:** one successful row per keyword-target pair
- **HTTP-first search transport:** normal runs use direct logged-out YouTube search responses instead of full browser automation

***

## Input

You can configure YouTube Rank Tracker from the **Apify Console** or start it programmatically through the **Apify API**.

The Actor accepts four required inputs:

```text
keywords
videoTargets
country
language
```

***

### Keywords

Add one or more YouTube search queries that you want to track.

Example:

```text
youtube seo
how to grow on youtube
best video editing software
```

Each normalized keyword is searched independently.

Duplicate keywords are removed **case-insensitively**.

For example:

```text
YouTube SEO
youtube seo
YOUTUBE SEO
```

are treated as one keyword.

Whitespace is also normalized, so accidental repeated spaces do not create separate searches.

***

### YouTube videos

Add one or more **public YouTube video URLs** or raw **11-character video IDs**.

Examples:

```text
https://www.youtube.com/watch?v=dQw4w9WgXcQ
dQw4w9WgXcQ
```

Equivalent forms are normalized to one target video.

Each target is checked against every keyword in the same run.

For example:

```text
3 keywords
x
5 target videos
=
15 keyword-target result rows
```

while still requiring only one YouTube search fetch per normalized keyword.

***

### Country

Enter the country value used to localize the YouTube search request.

Examples:

```text
US
GB
DE
PH
AU
CA
```

Country values are normalized to uppercase.

Different country values can produce different YouTube search results and therefore different observed ranks.

***

### Language

Enter the language value used to localize the YouTube search request.

Examples:

```text
en
es
de
fr
ja
```

Language values are normalized to lowercase.

***

### Example input

```json
{
  "keywords": [
    "Rick Astley Never Gonna Give You Up",
    "80s music"
  ],
  "videoTargets": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "country": "US",
  "language": "en"
}
```

***

## Output

Results are stored in the Actor's default **Apify Dataset**.

You can access them from:

```text
Output
Storage
Apify API
Integrations
Exports
```

Each successful Dataset row represents **one target video checked for one keyword and locale combination**.

If a keyword search itself fails, the Actor writes an error row for that keyword and continues with later keywords.

***

### Example ranked result

The following structure is based on a real successful live Actor run:

```json
{
  "keyword": "Rick Astley Never Gonna Give You Up",
  "targetType": "video",
  "targetVideoId": "dQw4w9WgXcQ",
  "targetUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "country": "US",
  "language": "en",
  "currentRank": 1,
  "previousRank": 1,
  "rankChange": 0,
  "status": "UNCHANGED",
  "bestRank": 1,
  "worstRank": 1,
  "averageRank": 1,
  "checkCount": 3,
  "rankedCheckCount": 3,
  "searchedResultCount": 19,
  "title": "Rick Astley - Never Gonna Give You Up (Official Video) (4K Remaster)",
  "channelName": "Rick Astley",
  "channelId": "UCuAXFkgsw1L7xaCfnd5JJOw",
  "thumbnailUrl": "https://i.ytimg.com/vi/dQw4w9WgXcQ/hq720.jpg",
  "resultType": "video",
  "firstTrackedAt": "2026-09-10T05:31:54.482Z",
  "previousCheckedAt": "2026-09-10T05:33:36.393Z",
  "checkedAt": "2026-09-10T05:48:59.976Z"
}
```

***

### Example unranked result

A video that is not present in the fetched result set is still recorded:

```json
{
  "keyword": "youtube seo",
  "targetVideoId": "dQw4w9WgXcQ",
  "country": "US",
  "language": "en",
  "currentRank": null,
  "previousRank": null,
  "rankChange": null,
  "status": "NOT_RANKED",
  "bestRank": null,
  "worstRank": null,
  "averageRank": null,
  "checkCount": 2,
  "rankedCheckCount": 0,
  "searchedResultCount": 18
}
```

When a target is not ranked, video metadata such as `title`, `channelName`, and `thumbnailUrl` may also be `null` because the target was not present in that fetched search response.

***

## How ranking works

`currentRank` is the **1-based observed video position** among normalized unique YouTube video results returned by the fetched search response.

Example:

```text
Video A -> currentRank 1
Video B -> currentRank 2
Video C -> currentRank 3
```

The tracker does not count duplicate video IDs twice.

Non-video YouTube interface elements do not consume a video rank position.

This means the rank answers:

> **Where did this target video appear among the unique video results returned for this search?**

It should not be interpreted as a permanent or universal YouTube ranking. Search results can change with time, locale, YouTube behavior, and other external factors.

***

### Rank change

`rankChange` is calculated as:

```text
previousRank - currentRank
```

So:

```text
Previous 8 -> Current 5 -> rankChange +3
Previous 3 -> Current 7 -> rankChange -4
Previous 1 -> Current 1 -> rankChange 0
```

A **positive** value means the video improved.

A **negative** value means the video dropped.

***

## Rank statuses

The Actor classifies each valid observation using one of these statuses:

### `FIRST_CHECK`

The first recorded observation for this keyword, target video, country, and language identity.

### `IMPROVED`

The video was ranked before and its numeric position improved.

Example:

```text
Previous rank: 8
Current rank: 5
Status: IMPROVED
```

### `DROPPED`

The video was ranked before and moved to a worse numeric position.

Example:

```text
Previous rank: 4
Current rank: 9
Status: DROPPED
```

### `UNCHANGED`

The video remained at the same numeric rank.

### `NEW_RANKING`

The video was previously unranked and is now present in the search results.

### `LOST_RANKING`

The video was previously ranked but is no longer present in the fetched search results.

### `NOT_RANKED`

The video remained unranked across consecutive checks.

***

## Persistent rank history

Rank history is stored in a **named Apify Key-Value Store** and reused across separate Actor runs.

The history identity includes the tracked search context, so repeated checks of the same:

```text
keyword
target video
country
language
```

can be compared over time.

This powers:

```text
previousRank
rankChange
status
bestRank
worstRank
averageRank
checkCount
rankedCheckCount
firstTrackedAt
previousCheckedAt
checkedAt
```

For meaningful history, keep the same keyword, target, country, and language when comparing repeated runs.

***

### Historical statistics

#### `bestRank`

Best numeric rank observed so far. Lower is better.

#### `worstRank`

Worst numeric rank observed so far.

#### `averageRank`

Average across ranked observations.

Unranked `null` observations do not invent numeric rank values.

#### `checkCount`

Total successful rank observations recorded for the identity.

#### `rankedCheckCount`

Number of those observations where the target video had a numeric rank.

***

## Multiple keywords and multiple videos

The Actor is optimized around the YouTube search result page.

For each normalized keyword:

1. Fetch the YouTube search response once
2. Normalize the ordered video results
3. Compare every target video against that same result set
4. Update persistent history for each valid keyword-target observation
5. Write one Dataset row per keyword-target pair

Example:

```text
100 keywords
x
20 target videos
=
2,000 keyword-target comparisons
```

but approximately:

```text
100 YouTube search fetches
```

rather than 2,000 separate search fetches.

This makes adding more target videos to an existing keyword set much more efficient than independently searching YouTube for every keyword-video pair.

***

## Reliability

YouTube Rank Tracker isolates keyword-level failures.

If you track:

```text
keyword A
keyword B
keyword C
```

and `keyword B` fails to search, the Actor can still preserve successful results for `keyword A` and continue to `keyword C`.

A failed keyword produces an error row containing the keyword, locale, timestamp, and error message.

Most importantly:

> **A failed keyword search does not mutate the persistent rank history for that failed observation.**

This avoids turning transport or parsing failures into fake ranking changes.

***

## Performance

The current Actor uses an **HTTP-first architecture** with Crawlee and direct logged-out YouTube search responses.

Normal rank checks do not launch full browser automation.

This generally reduces:

```text
Browser overhead
Startup overhead
Memory requirements
Unnecessary search duplication
```

The Actor also reuses one fetched search result set for all target videos attached to the same keyword.

Actual runtime depends on the number of keywords, YouTube response times, retries, and Apify infrastructure.

***

## API and integrations

YouTube Rank Tracker can be started programmatically through the **Apify API**.

Because results are stored in the default Dataset, they can be connected to workflows such as:

- Google Sheets
- Make
- Zapier
- CRMs
- Internal dashboards
- Data warehouses
- SEO reporting pipelines
- AI agents
- MCP workflows
- Custom APIs

You can also export Dataset results in formats supported by Apify.

***

## Scheduling

For actual rank tracking, repeated runs are more useful than a single one-time check.

Use **Apify Schedules** to run the Actor automatically.

Example monitoring cadence:

```text
Daily
Every 12 hours
Weekly
```

Each successful repeated observation extends the persistent history for the same keyword-target-locale identity.

A typical workflow is:

```text
1. Add target videos
2. Add target keywords
3. Choose country and language
4. Run once to create FIRST_CHECK observations
5. Schedule recurring runs
6. Monitor IMPROVED, DROPPED, NEW_RANKING, LOST_RANKING, and UNCHANGED results
```

***

## Example use cases

### YouTube SEO tracking

Track an uploaded video for the queries you are targeting.

Example:

```text
Target video:
your YouTube video

Keywords:
how to edit videos
best video editor
video editing tutorial
```

Monitor whether your position improves after title, description, thumbnail, or content changes.

***

### Competitor monitoring

Add competitor videos as additional targets.

For the same keyword, compare which tracked videos appear and where they rank.

This is useful for monitoring:

```text
Competitor visibility
Keyword ownership
Ranking movement
New ranking appearances
Lost ranking positions
```

***

### Content launch monitoring

After publishing a new video, create a keyword set and run recurring checks.

Watch for transitions such as:

```text
NOT_RANKED
-> NEW_RANKING
-> IMPROVED
```

when they occur.

***

### Locale comparison

Run the same target and keyword combinations with different country or language values.

Example:

```text
US / en
GB / en
PH / en
DE / de
```

Each locale is tracked independently.

***

### Ranking-loss alerts

Use scheduled runs and downstream automations to detect:

```text
DROPPED
LOST_RANKING
```

and route those rows into your reporting or alerting workflow.

***

## Current limitations

The current version focuses specifically on **public YouTube video rank tracking from logged-out search responses**.

It does **not currently provide**:

```text
Private-video access
Login-required searches
Cookie-based account personalization
CAPTCHA bypass
Bot-detection bypass
Age-restricted access workarounds
Continuation-page deep scraping
Channel ranking targets
Playlist ranking targets
YouTube Studio analytics
Personalized signed-in rankings
```

The Actor intentionally fails cleanly rather than attempting account or access-control bypasses.

A target outside the fetched video result set is reported as:

```text
currentRank: null
```

rather than being assigned an invented position.

***

## FAQ

### What exactly does this Actor track?

It tracks the observed position of target **YouTube videos** within the unique video results returned for a YouTube keyword search.

***

### Can I track multiple videos?

**Yes.**

Add multiple values to `videoTargets`.

Every target is checked against every normalized keyword.

***

### Can I track multiple keywords?

**Yes.**

Add multiple values to `keywords`.

Each normalized keyword receives its own search context.

***

### Can I use a YouTube URL instead of a video ID?

**Yes.**

Supported YouTube video URLs are normalized to their 11-character video ID.

You can also provide the raw ID directly.

***

### What does `currentRank: null` mean?

It means the target video was not found among the normalized unique video results available in that fetched YouTube search response.

It does **not** mean the Actor invented rank zero or an arbitrary fallback number.

***

### Why is the first status `FIRST_CHECK` even when the video is not ranked?

Because `FIRST_CHECK` describes the history state: this is the first valid observation for that keyword-target-locale identity.

If the target remains unranked on a later successful check, the status becomes `NOT_RANKED`.

***

### What happens if an unranked video later appears?

The status becomes:

```text
NEW_RANKING
```

and `currentRank` contains the newly observed numeric position.

***

### What happens if a ranked video disappears?

The status becomes:

```text
LOST_RANKING
```

and the new `currentRank` becomes `null`.

***

### Does the Actor preserve history between runs?

**Yes.**

Persistent rank history is stored in an Apify Key-Value Store and reused across Actor runs.

***

### Does an error count as a ranking drop?

**No.**

A failed keyword search does not mutate the history for that failed observation.

This prevents request failures from being misclassified as `LOST_RANKING` or other rank changes.

***

### Does the Actor search once for every target video?

**No.**

It searches once per normalized keyword and checks all targets against that shared result set.

***

### Can I export the results?

**Yes.**

Results are written to the default Apify Dataset and can be accessed through Apify's supported exports, API, and integrations.

***

### Can I schedule automatic rank checks?

**Yes.**

Use Apify Schedules to repeat the same input on your preferred cadence.

***

### Does this use the official YouTube Data API?

The current implementation uses direct logged-out YouTube search responses rather than making the YouTube Data API the default search source.

***

### Does this require a browser?

Not for the normal current workflow.

The Actor uses an HTTP-first search transport.

***

## Recommended workflow

For useful ranking intelligence, choose keywords that actually match the search intent of the target video.

Good:

```text
how to edit videos
video editing tutorial
best editing software
```

Less useful:

```text
video
youtube
content
```

Then:

```text
Use stable keyword wording
Use the same country and language for longitudinal comparisons
Schedule repeated checks
Watch status changes instead of relying on one isolated rank
Add competitor videos to the same keyword set when useful
```

***

## Feedback and support

Found a bug or have a feature request?

Use the Actor's **Issues** tab on Apify.

Useful future additions may include:

```text
Deeper result pagination
Channel targets
Additional locale controls
Ranking alerts
Additional output views
Additional YouTube search intelligence
```

***

### Track YouTube rankings without manual searching

Enter your keywords, add the public videos you want to monitor, choose a country and language, and run the Actor.

You receive **structured YouTube ranking data with persistent history** ready for SEO monitoring, competitor research, APIs, scheduled workflows, and automation.

# Actor input Schema

## `keywords` (type: `array`):

YouTube search queries to track. Each normalized keyword is searched once per run.

## `videoTargets` (type: `array`):

Public YouTube video URLs or raw 11-character video IDs to track for every keyword.

## `country` (type: `string`):

Country used to localize the YouTube search request. Examples: US, GB, DE, PH.

## `language` (type: `string`):

Language used to localize the YouTube search request. Examples: en, es, de, fr.

## Actor input object example

```json
{
  "keywords": [
    "Rick Astley Never Gonna Give You Up"
  ],
  "videoTargets": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "country": "US",
  "language": "en"
}
```

# Actor output Schema

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

Default dataset containing one rank result per keyword-target pair, or an error row when a keyword search fails.

# 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 = {
    "keywords": [
        "Rick Astley Never Gonna Give You Up"
    ],
    "videoTargets": [
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("aerodynamic_tripod/youtube-rank-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 = {
    "keywords": ["Rick Astley Never Gonna Give You Up"],
    "videoTargets": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
}

# Run the Actor and wait for it to finish
run = client.actor("aerodynamic_tripod/youtube-rank-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 '{
  "keywords": [
    "Rick Astley Never Gonna Give You Up"
  ],
  "videoTargets": [
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ]
}' |
apify call aerodynamic_tripod/youtube-rank-tracker --silent --output-dataset

```

## MCP server setup

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