# App Store & Google Play Tracker: Version, Price & Rank Changes (`datasmithlab/app-store-play-tracker`) Actor

Monitor iOS/Android version, price and rating changes by country. Charts cover Apple Top Free/Top Paid top 100; reviews are App Store only. Google Play charts/reviews and keyword/ASO ranks are not included.

- **URL**: https://apify.com/datasmithlab/app-store-play-tracker.md
- **Developed by:** [Datasmithlab](https://apify.com/datasmithlab) (community)
- **Categories:** Developer tools, SEO tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 app rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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

## App Store & Google Play Tracker: Version, Price & Rank Changes

Track selected iOS and Android apps by country for version, price and rating changes. Charts cover only Apple's Top Free/Top Paid top 100; review tracking is App Store only. Google Play charts/reviews, keyword rankings and ASO analysis are not included.

With monitoring enabled, the first run establishes a baseline. Unchanged apps have no app-row charge, but start and applicable run costs still apply. Review rows have their own event charge. Data comes from Apple's public lookup/chart feeds and public Google Play app pages. Reviewer names and profiles are not collected.

### What it tracks

| Event (`changes`) | Meaning | `diff` fields |
|---|---|---|
| `VERSION_CHANGE` | New app version (Google Play apps that show "varies with device" are detected by their update date) | `version`, `lastUpdated` |
| `PRICE_CHANGE` | Price or currency changed in that country's store | `price` (with `changePct`), `currency` |
| `RATING_CHANGE` | Average rating moved by at least your threshold (default 0.05 stars) since the last *reported* value | `ratingAverage` (with `change`), `ratingCount` |
| `RANK_CHANGE` | Position in Apple's official top-100 chart (Top Free / Top Paid, per country) moved by at least your threshold, or the app entered or left the top 100 | `rank:top-free`, `rank:top-paid` |
| `NEW_REVIEWS` | At least *N* new App Store reviews since the last run (optional) | `newReviews` (`count`, `averageRating`) |
| `REMOVED` | The store no longer has the app in that country (reported when it is missing in two runs in a row, so one empty store answer is not a false alarm) | - |

`changeType` is `NEW` (first time seen), `CHANGED`, `REMOVED`, or `SNAPSHOT` when monitoring is off. One row per **app, store and country**; several events can sit in one row (`"changes": ["VERSION_CHANGE", "RATING_CHANGE"]`) and the old value is always in `diff`.

### Quick start

1. Put apps in **App Store apps** (`389801252` or an `apps.apple.com` link) and/or **Google Play apps** (`com.instagram.android` or a `play.google.com` link).
2. Pick **Countries** (default United States).
3. Run once: every app comes back as `NEW`, that is your baseline.
4. Schedule the Actor daily (or hourly). From then on you get rows only when something changed.

| You want | Set |
|---|---|
| A competitor release alert | their apps, **Only new or changed apps** on, schedule daily |
| Price changes of paid apps in 5 countries | the apps, 5 **Countries** |
| Chart position of your apps | **Top charts to watch** `Top Free` |
| Every new app that enters the top 20 | **Top charts to watch** + **Also track the top N apps** `20` |
| New reviews to read or forward | **Customer reviews** `Summary + each review as a row` |
| A full snapshot every time | turn **Only new or changed apps** off |

### Output example

```json
{
  "recordType": "app",
  "id": "ios:389801252:us",
  "store": "ios",
  "appId": "389801252",
  "bundleId": "com.burbn.instagram",
  "country": "us",
  "name": "Instagram",
  "developer": "Instagram, Inc.",
  "category": "Photo & Video",
  "version": "450.1.0",
  "lastUpdated": "2026-10-06T12:29:07Z",
  "price": 0,
  "currency": "USD",
  "isFree": true,
  "ratingAverage": 4.69,
  "ratingCount": 29575931,
  "ranks": { "top-free": 20 },
  "url": "https://apps.apple.com/us/app/instagram/id389801252",
  "changeType": "CHANGED",
  "changes": ["VERSION_CHANGE", "RANK_CHANGE"],
  "diff": {
    "version": { "from": "449.0.0", "to": "450.1.0" },
    "lastUpdated": { "from": "2026-09-29T10:02:11Z", "to": "2026-10-06T12:29:07Z" },
    "rank:top-free": { "from": 31, "to": 20, "change": -11 }
  },
  "firstSeenAt": "2026-09-01T06:00:12Z"
}
```

Fields per app: `name`, `developer`, `category`, `version`, `releaseNotes`, `lastUpdated`, `releasedAt`, `price`, `currency`, `isFree`, `ratingAverage`, `ratingCount`, `contentRating`, `minOsVersion`, `sizeBytes` (App Store), `installs` (Google Play band such as `500,000,000+`), `ranks`, `url`.

A review row (`recordType: "review"`): `appName`, `appId`, `country`, `reviewId`, `rating`, `title`, `text`, `appVersion`, `updatedAt`. No author.

The run's key-value store also holds `APPS` (one line per app and country: found / not found / blocked / failed) and `HEALTH` (requests, blocked responses, empty-field ratios, format alerts).

### How each store is read

- **App Store:** Apple's official **iTunes Lookup API** (up to 50 apps per request and country), Apple's official **Top Charts feed** (`rss.marketingtools.apple.com`, top 100 Free and Paid) and, if you turn reviews on, Apple's public customer-review feed (the 50 most recent reviews per country, rating, title, text, version and date only).
- **Google Play:** the public app page (`play.google.com/store/apps/details`) in English, one request per app and country. Version, rating, rating count, price, install band, category, release notes and update date.
- Requests go out one at a time with a pause between them (App Store lookups stay under Apple's documented ~20 calls per minute), with an honest `DatasmithLab-Scraper` user agent. The Actor only requests URLs allowed by the stores' `robots.txt`.
- No proxy is used by default. If a store ever blocks the request, the run stops reading that store, reports it in `APPS` / `HEALTH` and keeps the other store going. You can add a proxy in the input; it is used only after a block.

### Limits (read this first)

- **No keyword search or ASO keyword ranks.** Both stores' search URLs are excluded by their `robots.txt`, so you give the apps (ids or links) yourself.
- **No Google Play reviews and no Google Play charts.** Google's `robots.txt` forbids both. Play apps are tracked by version, rating, price, install band and update date.
- **Charts are Apple's top 100 Top Free and Top Paid per country.** Apple's official feed has no Top Grossing list and no per-category charts.
- **Google Play version can be empty** for apps that ship different builds per device (for example Instagram). Those are tracked by `lastUpdated`.
- **The first run only sets the review starting point** (no old reviews are charged); review rows start with the next run.
- **Reviews cover Apple's 50 most recent reviews per app and country**, not the full history. Run often enough (daily is plenty for most apps).
- A rating change is reported when the average moves at least your threshold since the **last reported** value, so slow drifts add up instead of being lost.
- A store page redesign can break the Google Play reader. The `HEALTH` report shows empty-field ratios and `formatAlerts`, and the run logs a warning.

### Pricing

FREE-tier event rates checked on 11 October 2026 (FREE is the tier name, not a free run):

- `apify-actor-start`: $0.005 per event.
- `app-snapshot`: $0.002 per event.
- `review`: $0.0005 per event.

Start event count depends on memory: one per GB, minimum one. Zero output can still incur start and applicable run costs. Row prices do not guarantee the total invoice. Store pricing is authoritative; rates and tier discounts may change.

Pay per event:

- **Actor start:** $0.005 per run.
- **App row:** $0.002 per new, changed or removed app row ($2 per 1,000).
- **Review row:** $0.0005 per review row (only if you ask for reviews as rows).

**Unchanged apps have no app-row event charge.** An app that did not change is not returned and not charged. Check 200 apps daily and you pay only for the few rows that changed, plus the start.

### FAQ

**Why does the first run return everything?** It is the baseline. Every app is `NEW` once; after that only changes.

**Is the tracking memory shared between my tasks?** It is shared by this Actor in your account, per app and country. The same app tracked in two tasks is compared against the same last-reported values.

**Why no rank for my Google Play app?** Google offers no chart feed that its `robots.txt` allows. Use the App Store charts for iOS apps.

**Does it collect personal data?** No. App rows are public store listing data (the developer's *public store name* is included, never contact details). Review rows have no reviewer name or profile.

**How do I find an App Store id?** It is the number after `id` in the app's link: `apps.apple.com/us/app/instagram/id`**`389801252`**.

# Actor input Schema

## `appStoreApps` (type: `array`):

One per line: the numeric App Store id (389801252) or an apps.apple.com link such as https://apps.apple.com/us/app/instagram/id389801252.

## `googlePlayApps` (type: `array`):

One per line: the package name (com.instagram.android) or a play.google.com/store/apps/details?id=... link.

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

Every app is checked in each country's store (price, rating, version and chart rank differ per country). Default: United States.

## `chartLists` (type: `array`):

Adds each tracked App Store app's position in Apple's official top-100 chart per country (RANK_CHANGE). Apple publishes only Top Free and Top Paid in this feed.

## `chartTopN` (type: `integer`):

0 = only your own apps. 10 = your apps plus every app that is in the top 10 of the selected charts (new entrants are reported as NEW). Needs at least one chart.

## `onlyNewOrChanged` (type: `boolean`):

For scheduled runs: each run returns only apps that are NEW, CHANGED since the last run (VERSION_CHANGE, PRICE_CHANGE, RATING_CHANGE, RANK_CHANGE, NEW_REVIEWS) or REMOVED from a store. Unchanged apps are not returned and not charged. Turn off for a full snapshot of every app on every run.

## `ratingChangeThreshold` (type: `number`):

RATING_CHANGE is reported when the average rating moved at least this much since the last reported value. Slow drifts add up until they pass the threshold.

## `rankChangeThreshold` (type: `integer`):

RANK_CHANGE is reported when the chart position moved at least this many places. Entering or leaving the top 100 is always reported.

## `reviews` (type: `string`):

Reads Apple's public review feed of your own App Store apps: 'summary' adds NEW_REVIEWS (count and average of reviews since the last run) to the app row; 'rows' also returns each new review (rating, title, text, app version, date) as its own charged row. Reviewer names and profiles are never collected. Google Play reviews are not available (Google's robots.txt forbids them).

## `minNewReviews` (type: `integer`):

NEW_REVIEWS appears once at least this many new reviews have collected since the last report.

## `maxReviewsPerApp` (type: `integer`):

Apple's feed shows the 50 most recent reviews per country.

## `maxItems` (type: `integer`):

Stop after this many rows (app rows + review rows). You pay per row.

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

Not needed: requests go out without a proxy and both stores answered normally in tests. Only if a store blocks the request is this proxy used (at most 3 new IPs, then the run stops and says so).

## Actor input object example

```json
{
  "appStoreApps": [
    "389801252"
  ],
  "googlePlayApps": [
    "com.instagram.android"
  ],
  "chartTopN": 0,
  "onlyNewOrChanged": true,
  "ratingChangeThreshold": 0.05,
  "rankChangeThreshold": 5,
  "reviews": "off",
  "minNewReviews": 5,
  "maxReviewsPerApp": 50,
  "maxItems": 200
}
```

# Actor output Schema

## `apps` (type: `string`):

One row per new, changed or removed app and country (JSON/CSV/Excel export).

## `reviews` (type: `string`):

New App Store reviews (when 'Customer reviews' is set to rows).

## `allFields` (type: `string`):

Every field, including release notes, category, installs band and the before/after diff.

## `appStatus` (type: `string`):

For each app and country: found, not found, blocked or failed.

## `health` (type: `string`):

Requests, blocked responses, empty-field ratios and format alerts.

# 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 = {
    "appStoreApps": [
        "389801252"
    ],
    "googlePlayApps": [
        "com.instagram.android"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datasmithlab/app-store-play-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 = {
    "appStoreApps": ["389801252"],
    "googlePlayApps": ["com.instagram.android"],
}

# Run the Actor and wait for it to finish
run = client.actor("datasmithlab/app-store-play-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 '{
  "appStoreApps": [
    "389801252"
  ],
  "googlePlayApps": [
    "com.instagram.android"
  ]
}' |
apify call datasmithlab/app-store-play-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datasmithlab/app-store-play-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/usApY2fFS9I1bPelg/builds/fkiVXbxNj2eeRg6y2/openapi.json
