# App Store & Google Play Monitor: Versions, Ratings, Prices (`nswk_api/app-store-google-play-monitor`) Actor

Track any iOS or Android app across countries: version, release notes, rating, ratings count, price and installs. Changes mode returns only new versions, rating moves and price changes. No login, no reviews.

- **URL**: https://apify.com/nswk_api/app-store-google-play-monitor.md
- **Developed by:** [Bryan Masias](https://apify.com/nswk_api) (community)
- **Categories:** Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 & Google Play Monitor: Versions, Ratings, Prices

Track any iOS or Android app across countries. Get one clean record per app with version,
release notes, rating, ratings count, price and installs, or schedule it daily in **changes**
mode to get only what is new: **new versions, rating moves, price changes** and apps that
disappear from a store.

Both stores come out in one schema. No login, no reviews, no developer names or contacts.

### What it does

- Reads the App Store through Apple's public lookup API, in batches of 50 apps per call.
- Reads the public Google Play app page, with `hl` and `gl` set to your language and country.
- Normalizes both into the same record, so one table holds your iOS and Android apps.
- In changes mode, compares each run with the last one and returns only the differences.

### Use cases

- **Competitor tracking:** know the day a rival ships a release, changes its price or loses rating.
- **Release monitoring:** watch your own apps in every country you sell in, with the release notes.
- **ASO and market research:** follow ratings, ratings counts and install ranges over time.
- **AI agents:** three input fields, a flat output, and you pay only for apps that were read.

### Input

```json
{
  "apps": ["https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580", "com.spotify.music"],
  "countries": ["us", "gb"],
  "mode": "changes"
}
```

| Field | Default | What it does |
| --- | --- | --- |
| `apps` | required | App Store URL or numeric id, Google Play URL or package name. The store is detected per entry. Up to 500. |
| `countries` | `["us"]` | 2-letter country codes. Each app is checked in each country. Up to 20. |
| `mode` | `changes` | `changes` returns only what changed; `snapshot` returns every app in full. |
| `monitorId` | from apps + countries | Name of the saved state. Use one per watch list. |
| `language` | `en` | Language of texts such as release notes and category. |
| `minRatingDelta` | `0.05` | Smallest rating move that is reported. |
| `minRatingsCountDeltaPct` | `1` | Smallest change in the number of ratings that is reported, in percent. |
| `includeReleaseNotes` | `true` | Add the "What's new" text. |
| `maxConcurrency` | `2` | Play pages loaded at once (1 to 4). |

Duplicates, mixed formats and invalid entries are cleaned up; invalid entries are listed in the run summary.

### Output

In `snapshot` mode, one record per app and country:

```json
{
  "type": "snapshot",
  "store": "app_store",
  "appId": "324684580",
  "bundleId": "com.spotify.client",
  "country": "us",
  "title": "Spotify: Music and Podcasts",
  "url": "https://apps.apple.com/us/app/id324684580",
  "category": "Music",
  "price": 0,
  "currency": "USD",
  "rating": 4.77,
  "ratingsCount": 42776956,
  "currentVersionRating": 4.77,
  "currentVersionRatingsCount": 42776956,
  "installsRange": null,
  "version": "9.1.94",
  "versionReleasedAt": "2026-10-23T17:59:53Z",
  "releaseNotes": "We're always making changes and improvements to Spotify...",
  "contentRating": "12+",
  "minOsVersion": "16.1",
  "sizeBytes": 325112832,
  "checkedAt": "2026-10-26T12:00:00.000Z"
}
```

On Google Play, `installsRange` holds text such as `"1B+"`, `currentVersionRating` and
`sizeBytes` are `null`, and `version` is `null` for apps whose version "varies with device".

### Changes mode

The first run returns one `FIRST_SEEN` item per app and country, with the full snapshot. Later
runs return only changes:

```json
{
  "type": "change",
  "changeType": "VERSION_RELEASED",
  "store": "google_play",
  "appId": "com.spotify.music",
  "country": "us",
  "title": "Spotify: Music and Podcasts",
  "url": "https://play.google.com/store/apps/details?id=com.spotify.music",
  "field": "version",
  "previous": "9.1.90",
  "current": "9.1.94",
  "releaseNotes": "Bug fixes and improvements.",
  "detectedAt": "2026-10-26T12:00:00.000Z",
  "monitorId": "competitors-us"
}
```

| `changeType` | When |
| --- | --- |
| `FIRST_SEEN` | The first time an app is checked in a country. Free. |
| `VERSION_RELEASED` | A new version, or the same version with a new release date. On Play, apps that vary by device are tracked by date. |
| `RATING_CHANGED` | The rating moved at least `minRatingDelta` since it was last reported. |
| `RATINGS_COUNT_CHANGED` | The number of ratings moved at least `minRatingsCountDeltaPct` percent. |
| `PRICE_CHANGED` | The price or currency changed, including free to paid. |
| `INSTALLS_RANGE_CHANGED` | The Play installs range moved, e.g. `5M+` to `10M+`. |
| `APP_UNAVAILABLE` | The app was missing two runs in a row, so a one-off empty answer never raises an alarm. |
| `APP_AVAILABLE_AGAIN` | An unavailable app is back. |

Google Play shows the same version, ratings count and installs in every country, so those
changes are reported once per app, not once per country. Ratings and prices are per country.

The state is saved in a key-value store named `app-store-monitor-state` in your own Apify account.
Two runs with the same `monitorId` never overlap. A run summary (checked, changes by type, not
found, blocked, invalid) is saved in the `OUTPUT` record.

### Example run

The prefilled input runs in about a minute and costs a few cents at most. Snapshot mode returns one record per app and country. Switch to "changes" mode for alerts once you have a schedule.

Input:

```json
{
  "apps": [
    "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580",
    "com.spotify.music"
  ],
  "countries": ["us"],
  "mode": "snapshot"
}
```

First result (long text shortened):

```json
{
  "type": "snapshot",
  "store": "app_store",
  "appId": "324684580",
  "country": "us",
  "title": "Spotify: Music and Podcasts",
  "category": "Music",
  "price": 0,
  "currency": "USD",
  "rating": 4.77,
  "ratingsCount": 42804731,
  "version": "9.1.94",
  "versionReleasedAt": "2026-10-23T17:59:53Z",
  "checkedAt": "2026-10-29T03:33:27.745Z"
}
```

### Pricing

Pay per event:

| Event | Price | When |
| --- | --- | --- |
| `app-checked` | $0.002 | One app in one country, read successfully. |
| `change-detected` | $0.005 | One change returned in changes mode. `FIRST_SEEN` is free. |

Apps that are not found, blocked or unreadable are never charged. Watching 50 apps in one
country every day costs about $3 a month plus the changes you get.

### Data policy

Public data only, no login. The output has no reviews, no images and no developer names,
emails or addresses; emails and phone numbers in release notes are masked. Requests are polite:
App Store lookups stay around Apple's 20 calls per minute, Google Play pages at most 2 per second
with a plain user agent that names this Actor. A blocked page is skipped and never retried, and if
more than 5% of Play pages are blocked, Play checks stop for that run.

You define the legal basis for your use of the data.

Not affiliated with, endorsed by or sponsored by Apple or Google. App Store is a trademark of
Apple Inc. Google Play is a trademark of Google LLC.

### FAQ

**Where do I find an app id?** On the App Store it is the number after `id` in the app URL. On
Google Play it is the `id=` value in the app URL, such as `com.spotify.music`.

**Why is the Play rating different from the App Store rating?** They are separate stores with
separate users. The Play rating also differs by country.

**Why did I get `VERSION_RELEASED` with the same version?** The store shows a new release date
for the same version number, which usually means a re-submitted build.

**Does it return reviews?** No. Reviews carry personal data, so this Actor leaves them out.

**How do I watch two lists separately?** Give each its own `monitorId`.

# Actor input Schema

## `apps` (type: `array`):

App Store URLs or numeric ids (e.g. 324684580), and Google Play URLs or package names (e.g. com.spotify.music). The store is detected from each entry. Up to 500 apps.

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

2-letter country codes (ISO 3166). Each app is checked in each country. Up to 20.

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

"changes" returns only what changed since the last run with the same monitor ID (schedule it daily). "snapshot" returns the full record of every app.

## `monitorId` (type: `string`):

Name of the saved state for changes mode. Leave empty to derive it from the apps and countries. Letters, digits and dashes, max 40.

## `minRatingDelta` (type: `number`):

Report RATING_CHANGED when the rating moved at least this much since it was last reported, e.g. 0.05.

## `minRatingsCountDeltaPct` (type: `number`):

Report RATINGS_COUNT_CHANGED when the number of ratings moved at least this many percent. Keeps big apps from reporting every day.

## `includeReleaseNotes` (type: `boolean`):

Add the "What's new" text to snapshots and to VERSION_RELEASED changes.

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

2-letter language code for texts such as release notes and category, e.g. "en" or "es". Numbers are read the same way in every language.

## `maxConcurrency` (type: `integer`):

Google Play pages loaded at the same time (1 to 4). Requests stay polite: at most 2 Play pages per second, and App Store lookups at about 20 per minute.

## Actor input object example

```json
{
  "apps": [
    "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580",
    "com.spotify.music"
  ],
  "countries": [
    "us"
  ],
  "mode": "snapshot",
  "minRatingDelta": 0.05,
  "minRatingsCountDeltaPct": 1,
  "includeReleaseNotes": true,
  "language": "en",
  "maxConcurrency": 2
}
```

# Actor output Schema

## `items` (type: `string`):

One snapshot per app and country, or one item per change in changes mode.

## `summary` (type: `string`):

Apps checked, changes by type, and apps not found, blocked or invalid with the reason.

# 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 = {
    "apps": [
        "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580",
        "com.spotify.music"
    ],
    "countries": [
        "us"
    ],
    "mode": "snapshot"
};

// Run the Actor and wait for it to finish
const run = await client.actor("nswk_api/app-store-google-play-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 = {
    "apps": [
        "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580",
        "com.spotify.music",
    ],
    "countries": ["us"],
    "mode": "snapshot",
}

# Run the Actor and wait for it to finish
run = client.actor("nswk_api/app-store-google-play-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 '{
  "apps": [
    "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580",
    "com.spotify.music"
  ],
  "countries": [
    "us"
  ],
  "mode": "snapshot"
}' |
apify call nswk_api/app-store-google-play-monitor --silent --output-dataset

```

## MCP server setup

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