# App Store + Google Play Rank Tracker (`constructive_calm/app-store-rank-tracker`) Actor

Daily top-chart snapshots across 150+ countries for Apple App Store and Google Play — Free, Paid, Grossing. Built-in rank deltas (1d/7d/30d), top movers, new entries, dropoffs, and statistical forecasts. Per-app enrichment (ratings, reviews, dev, category).

- **URL**: https://apify.com/constructive\_calm/app-store-rank-tracker.md
- **Developed by:** [Omar Eldeeb](https://apify.com/constructive_calm) (community)
- **Categories:** Social media, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 2 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $3.00 / 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## App Store + Google Play Rank Tracker

Daily top-chart snapshots across **150+ countries** for both Apple App Store and Google Play — with built-in **rank deltas**, **top-mover detection**, **new-entry / dropoff alerts**, and **statistical rank forecasts**.

Built for mobile growth teams, ASO agencies, and investors who need Sensor Tower-grade rank tracking at a fraction of the cost.

---

### 1. What you get

For every country × chart × ranked app per run:

| Field | Description |
|---|---|
| `rank` | Current position on the chart (1 = top) |
| `app_id` | Numeric iTunes track ID (Apple) or package name like `com.openai.chatgpt` (Play) |
| `app_name`, `developer`, `url`, `icon_url` | Basic identity |
| `app_genre` | App's own Apple/Play genre (e.g. "Productivity") |
| `rating`, `rating_count`, `size_bytes`, `release_date`, `short_description`, `screenshot_urls` | When `perAppEnrichment` is on |
| `price`, `currency` | In LOCAL currency for paid apps |
| **`rank_change_1d`** | +ve = moved up, -ve = moved down vs. yesterday's snapshot (null on first run) |
| **`rank_change_7d`** | vs. ~7 days ago (null until ≥ 7 days of history) |
| **`rank_change_30d`** | vs. ~30 days ago (null until ≥ 30 days of history) |
| **`days_on_chart`** | Consecutive days in chart through current snapshot |
| **`peak_rank`** | Best rank in the rolling history window |
| **`forecast_rank_1d`, `forecast_rank_7d`** | Exponential-smoothing forecast (null until ≥ 5 snapshots) |

Plus auxiliary **mover events** (when `emitMovers` is on):
- `top-riser` (top 10 biggest positive deltas vs. prior snapshot)
- `top-faller` (top 10 biggest negative deltas)
- `new-entry` (apps that entered the chart)
- `dropoff` (apps that fell off the chart)

---

### 2. Coverage

- **Apple App Store** — all 175+ official storefronts, Top Free / Top Paid / Top Grossing, all-apps and category-filtered charts, via the official iTunes RSS feed (zero anti-bot, no auth).
- **Google Play** — all 130+ publishing regions, Top Free / Top Paid / Grossing, scraped via the `google-play-scraper` library. Residential proxy enabled by default.
- Up to **200 apps per chart**.
- Cross-platform **category filter** supports: games, social-networking, photo-video, business, productivity, finance, health-fitness, education, entertainment, lifestyle, music, news, shopping, sports, travel, utilities, weather, books, food-drink, navigation, medical, reference.

---

### 3. Use cases & copy-paste input recipes

#### 3.1 Indie dev — daily rank of my app's market
```json
{
    "platforms": ["apple", "googleplay"],
    "countries": ["us"],
    "chartTypes": ["top-free"],
    "resultsPerChart": 100,
    "perAppEnrichment": false,
    "emitMovers": false,
    "enableForecast": true
}
````

Cheap (~$9/mo on daily schedule), gives you a daily picture of who's ahead of you in Top Free US.

#### 3.2 Mobile growth team — G8 markets, all three charts

```json
{
    "platforms": ["apple", "googleplay"],
    "countries": ["us", "gb", "de", "fr", "jp", "kr", "ca", "au"],
    "chartTypes": ["top-free", "top-paid", "top-grossing"],
    "resultsPerChart": 100,
    "perAppEnrichment": true,
    "emitMovers": true,
    "enableForecast": true
}
```

Full Sensor Tower replacement for the big eight markets. ~$150/mo on daily schedule.

#### 3.3 Game studio — Games category in 20 mobile-first markets

```json
{
    "platforms": ["apple", "googleplay"],
    "countries": ["us", "cn", "jp", "kr", "tw", "hk", "br", "mx", "in", "id", "th", "vn", "ph", "my", "sg", "tr", "ru", "ae", "sa", "eg"],
    "chartTypes": ["top-free", "top-grossing"],
    "categories": ["games"],
    "resultsPerChart": 100,
    "perAppEnrichment": true,
    "emitMovers": true
}
```

Track the competitive landscape in mobile gaming across emerging + established markets.

#### 3.4 ASO agency — 150+ country sweep, metadata only

```json
{
    "platforms": ["apple"],
    "countries": [],
    "chartTypes": ["top-free"],
    "resultsPerChart": 50,
    "perAppEnrichment": true,
    "emitMovers": false,
    "enableForecast": false
}
```

Apple-only (lower cost, no proxy), all 175 Apple storefronts, 50 apps each. Output ready to feed client dashboards.

#### 3.5 Investor watch — tracking public mobile companies

```json
{
    "platforms": ["apple", "googleplay"],
    "countries": ["us", "gb", "de", "fr", "jp"],
    "chartTypes": ["top-free", "top-grossing"],
    "resultsPerChart": 200,
    "perAppEnrichment": true,
    "emitMovers": true,
    "enableForecast": true
}
```

Wider result depth (200 apps) means you catch apps like Duolingo, Roblox, Uber, Lyft, Airbnb ranking movements as early signals.

#### 3.6 Trend hunter — anomaly digest mode

```json
{
    "platforms": ["apple", "googleplay"],
    "countries": ["us", "gb", "de", "fr", "jp", "kr", "br", "in", "id", "mx"],
    "chartTypes": ["top-free"],
    "resultsPerChart": 200,
    "perAppEnrichment": false,
    "emitMovers": true,
    "enableForecast": false
}
```

Just the movers — find tomorrow's breakout apps. Filter dataset for `mover_type=new-entry` + `rank ≤ 20` to spot rapid-rise new apps.

***

### 4. How time-series works

The actor persists per-chart snapshot history in an Apify key-value store (one key per `platform/country/category/chart`). Each scheduled run:

1. Fetches the current chart.
2. Loads prior snapshots from KV (default 30 days rolling).
3. **Idempotency**: if a prior snapshot exists from the same hour, it's replaced (re-runs don't inflate history).
4. Computes deltas, movers, and forecasts against the merged history.
5. Writes the new snapshot back to KV.

To build time-series for analysis, set up a **scheduled run in Apify** (e.g. daily at 09:00 UTC) with the same input. The dataset for each run is timestamped, so you can query across runs or roll them up to a BigQuery / Looker / Metabase table via Apify's dataset API.

***

### 5. Cost & pricing (pay-per-event)

| Event | Price | When it fires |
|---|---|---|
| Actor run start | $0.01 | Once per run |
| Dataset item | $0.003 | Per ranked app pushed to the dataset |
| Per-app enrichment | $0.002 | Per app, only when `perAppEnrichment: true` |
| Mover event | $0.001 | Per mover/new-entry/dropoff row, only when `emitMovers: true` |

**Free trial**: first 100 chargeable events per run are free. This lets new users run a single-country preview at $0.

**Typical monthly costs** (daily scheduled run):

- Indie dev, 1 country × 100 apps × 1 chart: **~$9/mo**
- Mobile growth team, 8 countries × 100 × 3 charts + enrichment + movers: **~$150/mo**
- ASO agency, 150 countries × 50 apps × 1 chart, Apple only: **~$270/mo**

Compare to Sensor Tower ($500–2000/mo), data.ai (same), Appfigures (from $10 but single-country).

***

### 6. Data-freshness notes

- **Apple** refreshes its top charts every few minutes. Our RSS fetch reflects whatever Apple published at query time.
- **Google Play** charts update hourly. Google Play regional charts can lag US by 1-2 hours in some countries.
- **Scheduling**: for daily deltas, pick a time and stick with it. Running at the same UTC hour every day produces the cleanest rank-change signals.

***

### 7. Google Play reliability notes

Google Play has no official charts API — the data is scraped from public store pages. To keep scraping stable at scale:

- **Use residential proxies** (enabled by default in the proxy config). Datacenter proxies trigger CAPTCHAs quickly.
- **Unsupported countries** (some very small territories): the actor logs a skip warning and moves on rather than erroring out the whole run.
- **Partial failures** (a country returns 503/CAPTCHA after retries): that chart is skipped with a warning. Other countries in the same run are unaffected.
- **Apple side** is always reliable — it's the official iTunes RSS feed, no proxy needed.

***

### 8. Input reference

See the Input tab in the Apify Console. All fields have inline docs, including empty-value behavior, cross-field dependencies, and cost hints.

***

### 9. Dataset schema

Every row is one ranked-app snapshot or one mover event. Both shapes share the common fields `snapshot_ts`, `platform`, `country`, `chart_type`, `category`, `app_id`, `app_name`, `rank`. Mover rows additionally carry `mover_type` and `prior_rank`; regular rows carry the delta, days-on-chart, peak, and forecast fields.

For visualizations, the Console's built-in dataset views expose three preset filters: **overview** (all ranked-app snapshots), **enriched** (with ratings + details), and **movers** (anomaly events only). You can also export CSV / JSON / Excel directly from the Console, or hit the dataset REST API to feed BI tools.

# Actor input Schema

## `platforms` (type: `array`):

Which app stores to scrape. Select one or both. Apple uses the official iTunes RSS feed (zero anti-bot, no proxy needed). Google Play uses the public store (residential proxy recommended — enable the proxy section below). To scrape both Apple and Google Play, add 'googleplay' after 'apple'.

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

Two-letter country codes (lower-case) to scrape. Examples: us, gb, de, fr, jp, kr, cn, br, in, ae. LEAVE EMPTY to scrape all 159 supported countries (curated intersection of Apple 184 App Store storefronts and Google Play 130+ regions). Countries supported by only one platform are skipped on the other with a debug log, not an error. Start with 1-2 countries to preview before expanding.

## `chartTypes` (type: `array`):

Which top charts to pull per country. Free = free apps ranked by downloads, Paid = paid apps ranked by revenue from purchases, Grossing = apps ranked by total revenue including IAP + subscriptions (usually dominated by games).

## `categories` (type: `array`):

Optional category filter. LEAVE EMPTY to scrape the all-apps chart for each country (most common). When set, the actor pulls one chart per (country × chart type × category). Supported names: games, social-networking, photo-video, business, productivity, finance, health-fitness, education, entertainment, lifestyle, music, news, shopping, sports, travel, utilities, weather, books, food-drink, navigation, medical, reference. Unknown names are ignored with a warning. Each added category multiplies runtime and cost.

## `resultsPerChart` (type: `integer`):

How many ranked apps to pull per chart. IMPORTANT: Apple's RSS feed caps at 100 rows per chart regardless of this setting (Apple-side limit — requesting 200 still returns 100). Google Play supports up to 200 per chart. Each ranked app = $0.003 dataset charge, so 100 countries × 3 charts × 100 results = 30,000 rows ≈ $90. Start small (25-50) to preview.

## `perAppEnrichment` (type: `boolean`):

If enabled, each ranked app also gets enriched with rating (stars), rating count, developer name, genre, app size, screenshot URLs, short description, and release date. Apple uses the iTunes Lookup API (batched, fast — adds only a few seconds). Google Play requires a per-app fetch (slower: roughly 1-2 seconds per app with residential proxy). Adds $0.002 per enriched app. RECOMMENDED for mobile-growth / agency use cases. First 100 enrichment calls per run are free (trial). Off by default so you can gauge base-run cost before opting in.

## `emitMovers` (type: `boolean`):

If enabled, after each snapshot the actor emits mover events vs. the prior snapshot: top 10 risers, top 10 fallers, new entries to the chart, and dropoffs from the chart. Mover rows are pushed to the same dataset as snapshots ($0.003 per row) plus a supplementary $0.001 mover-event charge for the analytical signal. Never fires on the first run (needs prior snapshot history). REQUIRES scheduled runs to build history.

## `enableForecast` (type: `boolean`):

If enabled, each result includes `forecast_rank_1d` and `forecast_rank_7d` computed via exponential smoothing over the last 30 snapshots. Forecasts are only populated once at least 5 snapshots of history exist (otherwise fields are null). FREE — no per-event charge.

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

How many prior snapshots to persist in the key-value store per (platform, country, category, chart) for delta and forecast computation. Default 30 = ~one month of daily history. Higher values give smoother forecasts but use more KV storage.

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

Proxy used for Google Play requests. Apple RSS is called directly without proxy. Residential proxies STRONGLY recommended for Google Play — datacenter proxies trigger CAPTCHAs quickly. Leave default to use Apify residential proxies automatically.

## Actor input object example

```json
{
  "platforms": [
    "apple"
  ],
  "countries": [
    "us"
  ],
  "chartTypes": [
    "top-free"
  ],
  "categories": [],
  "resultsPerChart": 25,
  "perAppEnrichment": false,
  "emitMovers": true,
  "enableForecast": true,
  "historySnapshots": 30,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Snapshot rows (one per ranked app per chart) plus mover events (risers, fallers, new entries, dropoffs) when enabled.

# 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 = {
    "platforms": [
        "apple"
    ],
    "countries": [
        "us"
    ],
    "chartTypes": [
        "top-free"
    ],
    "categories": [],
    "resultsPerChart": 25,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("constructive_calm/app-store-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 = {
    "platforms": ["apple"],
    "countries": ["us"],
    "chartTypes": ["top-free"],
    "categories": [],
    "resultsPerChart": 25,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("constructive_calm/app-store-rank-tracker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "platforms": [
    "apple"
  ],
  "countries": [
    "us"
  ],
  "chartTypes": [
    "top-free"
  ],
  "categories": [],
  "resultsPerChart": 25,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call constructive_calm/app-store-rank-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=constructive_calm/app-store-rank-tracker",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "App Store + Google Play Rank Tracker",
        "description": "Daily top-chart snapshots across 150+ countries for Apple App Store and Google Play — Free, Paid, Grossing. Built-in rank deltas (1d/7d/30d), top movers, new entries, dropoffs, and statistical forecasts. Per-app enrichment (ratings, reviews, dev, category).",
        "version": "1.0",
        "x-build-id": "Cx4UgJQiaz1mrXRcU"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/constructive_calm~app-store-rank-tracker/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-constructive_calm-app-store-rank-tracker",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/constructive_calm~app-store-rank-tracker/runs": {
            "post": {
                "operationId": "runs-sync-constructive_calm-app-store-rank-tracker",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/constructive_calm~app-store-rank-tracker/run-sync": {
            "post": {
                "operationId": "run-sync-constructive_calm-app-store-rank-tracker",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "platforms"
                ],
                "properties": {
                    "platforms": {
                        "title": "Platforms",
                        "type": "array",
                        "description": "Which app stores to scrape. Select one or both. Apple uses the official iTunes RSS feed (zero anti-bot, no proxy needed). Google Play uses the public store (residential proxy recommended — enable the proxy section below). To scrape both Apple and Google Play, add 'googleplay' after 'apple'.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "apple",
                                "googleplay"
                            ],
                            "enumTitles": [
                                "Apple App Store",
                                "Google Play"
                            ]
                        },
                        "default": [
                            "apple"
                        ]
                    },
                    "countries": {
                        "title": "Countries (ISO-3166 alpha-2)",
                        "type": "array",
                        "description": "Two-letter country codes (lower-case) to scrape. Examples: us, gb, de, fr, jp, kr, cn, br, in, ae. LEAVE EMPTY to scrape all 159 supported countries (curated intersection of Apple 184 App Store storefronts and Google Play 130+ regions). Countries supported by only one platform are skipped on the other with a debug log, not an error. Start with 1-2 countries to preview before expanding.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "chartTypes": {
                        "title": "Chart types",
                        "type": "array",
                        "description": "Which top charts to pull per country. Free = free apps ranked by downloads, Paid = paid apps ranked by revenue from purchases, Grossing = apps ranked by total revenue including IAP + subscriptions (usually dominated by games).",
                        "items": {
                            "type": "string",
                            "enum": [
                                "top-free",
                                "top-paid",
                                "top-grossing"
                            ],
                            "enumTitles": [
                                "Top Free",
                                "Top Paid",
                                "Top Grossing"
                            ]
                        },
                        "default": [
                            "top-free",
                            "top-paid",
                            "top-grossing"
                        ]
                    },
                    "categories": {
                        "title": "Categories filter",
                        "type": "array",
                        "description": "Optional category filter. LEAVE EMPTY to scrape the all-apps chart for each country (most common). When set, the actor pulls one chart per (country × chart type × category). Supported names: games, social-networking, photo-video, business, productivity, finance, health-fitness, education, entertainment, lifestyle, music, news, shopping, sports, travel, utilities, weather, books, food-drink, navigation, medical, reference. Unknown names are ignored with a warning. Each added category multiplies runtime and cost.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "resultsPerChart": {
                        "title": "Results per chart",
                        "minimum": 10,
                        "maximum": 200,
                        "type": "integer",
                        "description": "How many ranked apps to pull per chart. IMPORTANT: Apple's RSS feed caps at 100 rows per chart regardless of this setting (Apple-side limit — requesting 200 still returns 100). Google Play supports up to 200 per chart. Each ranked app = $0.003 dataset charge, so 100 countries × 3 charts × 100 results = 30,000 rows ≈ $90. Start small (25-50) to preview.",
                        "default": 100
                    },
                    "perAppEnrichment": {
                        "title": "Per-app enrichment (ratings, reviews, developer)",
                        "type": "boolean",
                        "description": "If enabled, each ranked app also gets enriched with rating (stars), rating count, developer name, genre, app size, screenshot URLs, short description, and release date. Apple uses the iTunes Lookup API (batched, fast — adds only a few seconds). Google Play requires a per-app fetch (slower: roughly 1-2 seconds per app with residential proxy). Adds $0.002 per enriched app. RECOMMENDED for mobile-growth / agency use cases. First 100 enrichment calls per run are free (trial). Off by default so you can gauge base-run cost before opting in.",
                        "default": false
                    },
                    "emitMovers": {
                        "title": "Emit mover / anomaly events",
                        "type": "boolean",
                        "description": "If enabled, after each snapshot the actor emits mover events vs. the prior snapshot: top 10 risers, top 10 fallers, new entries to the chart, and dropoffs from the chart. Mover rows are pushed to the same dataset as snapshots ($0.003 per row) plus a supplementary $0.001 mover-event charge for the analytical signal. Never fires on the first run (needs prior snapshot history). REQUIRES scheduled runs to build history.",
                        "default": true
                    },
                    "enableForecast": {
                        "title": "Enable statistical rank forecast",
                        "type": "boolean",
                        "description": "If enabled, each result includes `forecast_rank_1d` and `forecast_rank_7d` computed via exponential smoothing over the last 30 snapshots. Forecasts are only populated once at least 5 snapshots of history exist (otherwise fields are null). FREE — no per-event charge.",
                        "default": true
                    },
                    "historySnapshots": {
                        "title": "History window (snapshots to keep)",
                        "minimum": 5,
                        "maximum": 180,
                        "type": "integer",
                        "description": "How many prior snapshots to persist in the key-value store per (platform, country, category, chart) for delta and forecast computation. Default 30 = ~one month of daily history. Higher values give smoother forecasts but use more KV storage.",
                        "default": 30
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration (Google Play only)",
                        "type": "object",
                        "description": "Proxy used for Google Play requests. Apple RSS is called directly without proxy. Residential proxies STRONGLY recommended for Google Play — datacenter proxies trigger CAPTCHAs quickly. Leave default to use Apify residential proxies automatically.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
