# App Store Rank Monitor — iOS Top Charts as JSON (`darknezz/app-store-rank-monitor`) Actor

Track any iOS app's position in Apple's App Store charts day by day. Diffs each chart against the previous run and emits only the rows that moved, with rank, previous rank and the delta. Top Free, Top Paid and Top Grossing, 150+ storefronts, optional category filter, no key or proxy.

- **URL**: https://apify.com/darknezz/app-store-rank-monitor.md
- **Developed by:** [Oaida Adrian](https://apify.com/darknezz) (community)
- **Categories:** Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 chart row emitteds

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?

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

## App Store Rank Monitor — iOS Top Charts as JSON

Track **where an iOS app sits in Apple's App Store charts** and get a row each time it moves. Apple publishes every storefront chart as a public RSS/JSON feed; this Actor reads that feed, remembers the last ranking, and emits **only the apps whose position changed** — with the old position folded into a single `rank_delta` number.

No API key, no login, no proxies, no scraping iOS itself. Top Free, Top Paid and Top Grossing charts, 150+ storefronts, optional category filter.

### Why a rank tracker and not a scraper

Apple already publishes the chart. What nobody gets for free is the **history**: where the app was yesterday, and by how much it moved. That delta is the product — `rank` alone is a number you can read on your phone, `rank_delta` is what tells you a release, a price change or a competitor's ad buy actually worked.

Because the Actor keeps its own cursor between runs, a daily schedule costs one row per app that actually moved. On a quiet day that is zero rows.

### What you get per row

```json
{
  "country": "us",
  "chart": "topfreeapplications",
  "category": null,
  "rank": 3,
  "rank_delta": -2,
  "app_id": "6741796873",
  "name": "TikTok Pro - Events",
  "artist": "TikTok Ltd.",
  "url": "https://apps.apple.com/us/app/tiktok-pro-events/id6741796873?uo=2",
  "price": "Get",
  "currency": "USD",
  "is_new": false,
  "captured_at": "2026-10-28T20:02:25+00:00"
}
```

Read `rank_delta` the way you read a share price: **positive = climbed** (was 5, now 3 → `+2`), **negative = fell** (was 3, now 5 → `-2`), `null` = the app was not in the previous run's chart (`is_new: true`). `rank_delta: 0` only appears with `emit: "all"`, which emits the whole chart every run instead of just the movers.

| Field | Meaning |
|-------|---------|
| `country` | Storefront the chart was read from (`us`, `gb`, `de`, `ro`…) |
| `chart` | `topfreeapplications`, `toppaidapplications` or `topgrossingapplications` |
| `category` | Apple genre id the chart was filtered by, `null` for the overall chart |
| `rank` | Position now, 1 = top |
| `rank_delta` | Places gained since the previous run — negative means it fell |
| `app_id` / `name` / `artist` / `url` | Identity of the app, straight from Apple |
| `price` / `currency` | Price label as Apple shows it (`Get`, `$1.99`) |
| `is_new` | App was absent from the last run's chart (new entry, or it re-entered) |
| `captured_at` | When this run read the chart (ISO 8601, UTC) |

### Input

```json
{
  "countries": ["us", "ro"],
  "chart": "topfreeapplications",
  "category": "6007",
  "limit": 200,
  "emit": "changes"
}
```

| Field | Description |
|-------|-------------|
| `countries` | Storefront codes to track (default `["us"]`). Each is an independent chart with its own cursor. |
| `chart` | `topfreeapplications` (default), `toppaidapplications` or `topgrossingapplications`. |
| `category` | Optional Apple genre id — `6007` Productivity, `6014` Games, `6016` Entertainment, `6015` Finance, `6012` Lifestyle. Empty = overall chart. |
| `limit` | Chart depth, 1–200 (default 100). Apple's feed refuses anything deeper than 200. |
| `emit` | `changes` (default) = only rows that moved. `all` = the entire chart every run, for building a full snapshot history. |

### Run it daily

1. Set **Input** once (e.g. `countries: ["us"]`, `chart: "topfreeapplications"`).
2. Add a **Schedule** in the Apify console — daily is Apple's own refresh cadence for these feeds, and hourly gains nothing.
3. Point a **webhook** or a Zapier/Make/n8n step at the dataset to alert on a drop: filter `rank_delta < -5` and you have a "something broke or a competitor launched" alarm for free.

The first run is a baseline: every app in the chart is emitted with `is_new: true` and `rank_delta: null`. Deltas start on the second run.

### Use it from the API

```bash
curl -X POST "https://api.apify.com/v2/acts/darknezz~app-store-rank-monitor/run-sync-get-dataset-items?token=YOUR_TOKEN" -H "Content-Type: application/json" -d '{"countries":["us"],"chart":"topfreeapplications","limit":200}'
```

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("darknezz~app-store-rank-monitor").call(
    run_input={"countries": ["us"], "chart": "topfreeapplications", "limit": 200})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["rank"], row["name"], row["rank_delta"])
```

Works with Zapier, Make, n8n and MCP-enabled AI agents like any other Actor.

### Limitations

- **Apple's chart feed is undocumented.** It is Apple's own marketing feed, published for years and used by everything from blogs to App Store link widgets, but it is not a contract: Apple has never published a schema for it and can change or lag it without notice. When a storefront returns nothing, or the request fails, the run **logs a warning, emits no rows and keeps the previous ranking**, so the next run still knows what to diff against — a lagging feed delays your delta, it never wipes your history. Nothing is charged for a run that emits no rows.
- **It cannot recover the history you never collected.** There is no back-catalogue of past chart positions on Apple's side; the cursor starts building the day you schedule it.
- **It cannot see the app that fell out of the tracked depth.** Keep `limit` above the app's worst plausible position — an app below position 200 is simply absent from the chart, not ranked 201st.
- It does not fetch reviews or app details — see **Related data** below.

### Related data

- [App Store Reviews Scraper](https://apify.com/darknezz/app-store-reviews-scraper) — iOS reviews for the same apps, one row per review, sorted newest or most helpful.
- [Google Play Reviews Scraper](https://apify.com/darknezz/google-play-reviews-scraper) — the Android side, if you track both stores.

### Pricing

**$0.01 per row emitted**, plus a **$0.01 start fee** per run (one event per GB of memory — this Actor runs on 1 GB). Rows are only charged when they are actually written: a daily run with nothing moving costs the start fee and nothing else, and the first baseline run of a 200-deep chart costs $2.01 once. Apify's standard platform compute costs still apply.

### FAQ

**Where does the data come from?** Apple's public marketing RSS feeds (`itunes.apple.com/{country}/rss/...`) — the same feeds Apple has published for years for exactly this purpose. No reverse engineering, no private API, nothing to break when the web app changes.

**Do I need the App Store Connect API?** No. That API only covers apps you own; this tracks any app, including competitors'.

**How fresh is it?** Apple refreshes these charts a few times a day. Daily is the useful cadence; more frequent runs mostly return zero changes (and cost only the start fee).

**Why is my app missing?** Either it is beyond `limit`, or it is not charting in that storefront/category at all. Widen the depth, then check the country.

**Can I diff a whole quarter of positions?** Yes — run with `emit: "all"` and keep the dataset, or use Apify's dataset exports. `emit: "changes"` is for cheap continuous monitoring; `all` is for building your own history table.

# Actor input Schema

## `countries` (type: `array`):

Apple storefront country codes to track (us, gb, de, ro...).

## `chart` (type: `string`):

Which Apple chart to track.

## `category` (type: `string`):

Apple genre id to track one category instead of the overall chart, e.g. 6007 Productivity, 6014 Games, 6016 Entertainment, 6015 Finance, 6012 Lifestyle. Leave empty for the overall chart.

## `limit` (type: `integer`):

How many positions to track (1-200, Apple's maximum).

## `emit` (type: `string`):

changes = only rows whose rank moved since the last run (cheapest per-row billing); all = the whole chart every run.

## Actor input object example

```json
{
  "countries": [
    "us"
  ],
  "chart": "topfreeapplications",
  "limit": 100,
  "emit": "changes"
}
```

# Actor output Schema

## `results` (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 = {
    "countries": [
        "us"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("darknezz/app-store-rank-monitor").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 = { "countries": ["us"] }

# Run the Actor and wait for it to finish
run = client.actor("darknezz/app-store-rank-monitor").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 '{
  "countries": [
    "us"
  ]
}' |
apify call darknezz/app-store-rank-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,darknezz/app-store-rank-monitor"
        }
    }
}
```

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/V4KmJZgfwcnD9ofWN/builds/0LFGJofu4vvHzWHrK/openapi.json
