# App Store & Google Play Scraper - ASO Ranks & Ratings Monitor (`ivora/app-store-monitor`) Actor

Monitor iOS and Android apps: rating, rating count, installs, price, version, release notes, App Store chart positions and keyword search ranks. Each run returns the current state plus change rows (field, old, new) since the last run. Optional new Google Play reviews.

- **URL**: https://apify.com/ivora/app-store-monitor.md
- **Developed by:** [Ivora Tools](https://apify.com/ivora) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 app checkeds

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 Scraper: ASO Ranks, Ratings & Change Monitor

Track **your apps and your competitors' apps on both stores** in one run:

- **Current state per app and country**: rating, rating count, installs (Google Play), price, version, release notes, last update, category, content rating, ads and in-app purchases (Play), and **App Store chart positions** (top 100: Top Free or Top Paid, plus Top Grossing, overall and in the app's category).
- **Change rows since the last run** (`field`, `oldValue`, `newValue`, `delta`), for example: new version, new release notes, price change, rating up or down, rating count jump, installs bucket change, chart position move, title change.
- **Keyword search ranks**: where your apps rank for each keyword in each store and country, the top results, and which apps entered or left the top since the last run.
- **New Google Play reviews** (optional). Reviewer names are off by default.

Built for ASO freelancers, app marketers, mobile agencies, product managers and investors watching app traction. Schedule it daily and get only what changed.

### Sample output

An app row and a keyword-rank row from a real Apify cloud run (Oct 2026), shortened:

```json
[
  {
    "type": "app",
    "store": "google_play",
    "appId": "com.spotify.music",
    "country": "gb",
    "rating": 4.2545,
    "ratingCount": 36447699,
    "installs": "1,000,000,000+",
    "version": "Varies with device",
    "lastUpdated": "2026-10-07T06:27:03Z",
    "containsAds": true,
    "changedFields": []
  },
  {
    "type": "keywordRank",
    "store": "apple",
    "keyword": "habit tracker",
    "country": "us",
    "trackedApps": [{"appId": "1438388363", "title": "Habit Tracker", "rank": 1, "previousRank": null}],
    "topResults": [{"rank": 1, "title": "Habit Tracker", "developer": "InnerGrow", "rating": 4.79}, …]
  }
]
```

### Data sources

| Store | Source |
|---|---|
| App Store (Apple) | Apple's **official iTunes Search and Lookup APIs** (app data, keyword search) and Apple's **official RSS chart feeds** (top 100). |
| Google Play | Google Play's **public app and search pages**. The embedded page data is parsed with the same data paths as the widely used open-source (MIT) `google-play-scraper` library. Reviews come from the public review list that the Play website itself loads. |

No login, no API keys, normally no proxy.

### Input example

```json
{
  "apps": ["324684580", "https://apps.apple.com/us/app/habit-tracker/id1438388363", "com.spotify.music", "com.habitnow"],
  "keywords": ["habit tracker", "music streaming"],
  "countries": ["us", "gb", "de"],
  "language": "en",
  "monitorMode": true,
  "checkCharts": true,
  "includePlayReviews": true,
  "maxReviewsPerApp": 50
}
```

Apps can be given as an App Store ID or URL, or a Google Play package name or URL. Optional prefixes: `apple:` and `play:`. The apps you list are also the apps whose keyword ranks are reported.

### Output

There are four row types, each with its own dataset view:

- **`app`**: the current state of one app in one country (charged as `app-checked`):

```json
{
  "type": "app", "store": "apple", "appId": "1438388363", "country": "us", "title": "Habit Tracker",
  "developer": "InnerGrow", "rating": 4.7918, "ratingCount": 147698, "price": 0.0, "currency": "USD",
  "version": "2.25", "releaseNotes": "- support iOS 27\n- fix bugs ...", "lastUpdated": "2026-10-06T22:46:31Z",
  "genre": "Productivity", "contentRating": "4+", "chartPositions": {},
  "changesSinceLastRun": 0, "changedFields": [], "firstRun": false, "url": "https://apps.apple.com/us/app/habit-tracker/id1438388363"
}
```

Google Play rows also carry `installs` ("1,000,000,000+"), `minInstalls`, `installsEstimate` (Google's own exact-ish figure), `reviewCount`, `histogram` (1-5 stars), `containsAds`, `offersIAP` / `iapPriceRange` and `summary`.

- **`change`** (free): `{"field": "version", "oldValue": "9.1.86", "newValue": "9.1.88", ...}`. Chart moves look like `chartPosition:topfree/Music` with `delta` = places gained.
  - A rating change is reported only when the rating (rounded to 2 decimals) moves by at least `ratingChangeThreshold` (default 0.01).
  - Rating and review counts are reported only when they move by at least `ratingCountChangePct` (default 1%).
- **`keywordRank`** (charged as `keyword-rank`): `trackedApps` (rank, previousRank, rankChange), `bestTrackedRank`, `topResults`, `newInTop` and `droppedFromTop`.
- **`review`** (Google Play, charged as `review`): rating, text, date, app version, thumbs-up count, developer reply and reply date. `userName` is null unless `includeReviewerNames` is on.
- **`error`** (free): an app that was not found or is not available in a country, or a failed search.

### Honest limits

- **App Store reviews are not included.** Apple's official customer-reviews RSS feed currently returns zero entries for the apps we tested. Getting reviews would require Apple's private web-app API, which we chose not to depend on. Google Play reviews are supported.
- **App Store keyword ranks** come from Apple's official iTunes Search API. Its order is close to, but **not guaranteed identical** to, what an iPhone shows for the same search (Apple personalises the App Store and adds Search Ads). Treat ranks as a consistent trend signal.
- **Google Play keyword ranks** cover the first page of results (about 20-30 apps). An app below that shows `rank: null`.
- **Charts are App Store only** (top 100, the limit of Apple's RSS feed). Google Play charts are not supported.
- **Google Play parsing** depends on the page's embedded data layout, which Google changes a few times a year. The Actor is self-tested daily, and the data paths follow the maintained open-source library.
- Google Play shows the same rating count worldwide, but the rating and texts per country and language. Apps with "Varies with device" have no version number on Play, so version changes show up as `lastUpdated` changes.
- Google Play serves reviews per **language**, not per country, so each Play app's reviews are fetched once per run (in the first country of your list). Duplicates are never charged.
- Developer replies are published text. They sometimes greet the reviewer by first name even when reviewer names are off.

### Pricing (pay per event)

| Event | Price |
|---|---|
| Actor start | $0.005 per run |
| App checked (one app in one country, incl. change rows) | $0.002 |
| Keyword rank (one keyword × store × country) | $0.003 |
| Google Play review | $0.0005 |

Change and error rows are free.

Example: 10 apps × 2 countries + 5 keywords × 2 stores × 2 countries, daily = $0.005 + 20 × $0.002 + 20 × $0.003 = **about $0.105 per day** (about $3.15 per month).

### Tips

- Run it on a schedule (daily is typical). The first run stores a baseline, and every later run reports what changed.
- Use different `stateStoreName` values for independent monitors (for example, one per client).
- For big runs (hundreds of Play apps), enable Apify Proxy in case Google Play starts rate-limiting.

### Daily alerts to Slack or email

1. Fill in the input and click **Save as a new task** (one task per client or competitor set is a good pattern).
2. In **Schedules**, create a schedule (for example every day at 08:00 in your time zone) and add the task.
3. In the task's **Integrations** tab, add the **Slack** or **Gmail** integration to get a message when a run finishes,
   or a **webhook** on "Run succeeded" that passes the run to Zapier, Make, n8n or your own endpoint. Those tools can read the rows from
   `https://api.apify.com/v2/datasets/{defaultDatasetId}/items` and format them however you like.

Because monitor mode outputs **only change rows since the previous run (plus one current-state row per app)**, every scheduled run's dataset *is* your alert list. An empty dataset (apart from free summary rows) means nothing changed.
Turn on Apify's run-failure notifications too, so you hear about a failed run instead of silence.

### Related actors

Part of a small **competitor-intelligence suite** by the same developer. Same conventions everywhere: pay per event, failed items are never charged, and the monitors return only what changed since the last run.

- [Google Trends Scraper & API](https://apify.com/ivora/google-trends-api): interest over time, by region/city, top queries and Trending now for any country.
- [Google Ads Transparency Scraper & New Ads Monitor](https://apify.com/ivora/google-ads-transparency-monitor): competitors' Google Search, Display and YouTube ads, with only-new-ads alerts.
- [LinkedIn Ad Library Scraper & New Ads Monitor](https://apify.com/ivora/linkedin-ad-library-monitor): competitors' LinkedIn ads without login, incl. EU impressions and targeting.
- [Bing Ads Library Scraper - Microsoft Ads Monitor (EU)](https://apify.com/ivora/microsoft-ads-library-monitor): Bing ads from Microsoft's official Ad Library (EU/EEA), with impressions by country.
- [ATS Jobs Scraper & Hiring Monitor](https://apify.com/ivora/company-hiring-monitor): new and closed jobs from Greenhouse, Lever, Ashby, Workday and 6 more job boards, by company domain.
- [Shopify Store Monitor - Product, Price & Stock Change Scraper](https://apify.com/ivora/shopify-store-monitor): new and removed products, price drops, sales and stock changes in competitor Shopify stores.
- [Google Hotels Scraper & Rate Monitor](https://apify.com/ivora/google-hotels-rate-monitor): hotel prices by booking site (Booking.com, Expedia, Agoda, own site) for any dates, with price-change alerts.

# Actor input Schema

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

One app per line. App Store: numeric ID or URL (<code>324684580</code>, <code>https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580</code>). Google Play: package name or URL (<code>com.spotify.music</code>, <code>https://play.google.com/store/apps/details?id=com.spotify.music</code>). These apps are also the ones whose ranks are reported for your keywords.

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

Store search terms. For each keyword, country and store you get the rank of your apps in the search results, the top results and who entered or left the top since the last run.

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

2-letter store country codes (us, gb, de, ua...). Every app and keyword is checked in each country (and charged per country).

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

Language for Google Play texts, search and reviews (en, de, uk, pt-BR...). The App Store API returns the country store's default language.

## `keywordStores` (type: `string`):

Which store(s) to search for each keyword.

## `monitorMode` (type: `boolean`):

On: besides the current state of each app, output one row per changed field since the previous run (version, release notes, price, rating, rating count, installs, chart position...), and only NEW reviews. State is kept in a named key-value store.

## `checkCharts` (type: `boolean`):

Look up each App Store app in the official top-100 charts (Top Free or Top Paid, plus Top Grossing), overall and in its category. Google Play charts are not supported.

## `chartCategory` (type: `string`):

Use this category's charts instead of each app's own category. Genre name (Productivity, Games, Health & Fitness...) or App Store genre ID (6007).

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

Report a rating change only if the rating (rounded to 2 decimals) moved at least this much.

## `ratingCountChangePct` (type: `number`):

Report rating/review count changes only above this percentage (popular apps gain ratings every day). 0 = every change.

## `includePlayReviews` (type: `boolean`):

Also output the newest Google Play reviews (only new ones in monitor mode). Charged per review. App Store reviews are not available (see README).

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

How many of the newest reviews to read per Google Play app each run (reviews are per language, read once per app).

## `reviewsFirstRun` (type: `string`):

Output the newest reviews on the first run, or only remember them (then later runs output only new reviews).

## `includeReviewerNames` (type: `boolean`):

Off by default (personal data). Turn on only if you have a legitimate reason to process reviewer names.

## `appleSearchDepth` (type: `integer`):

How many App Store search results to scan for ranks (max 200). Google Play search returns about 30 results per keyword.

## `topResults` (type: `integer`):

How many top search results to include in each keyword row (0-50).

## `stateStoreName` (type: `string`):

Named key-value store that remembers the previous state between runs. Use different names for independent monitors.

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

Concurrent requests (pages are also paced per host).

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

Not needed normally. Enable Apify Proxy if Google Play starts rate-limiting (large runs).

## Actor input object example

```json
{
  "apps": [
    "324684580",
    "com.spotify.music",
    "https://apps.apple.com/us/app/habit-tracker/id1438388363"
  ],
  "keywords": [
    "music streaming"
  ],
  "countries": [
    "us"
  ],
  "language": "en",
  "keywordStores": "both",
  "monitorMode": true,
  "checkCharts": true,
  "ratingChangeThreshold": 0.01,
  "ratingCountChangePct": 1,
  "includePlayReviews": false,
  "maxReviewsPerApp": 50,
  "reviewsFirstRun": "outputAll",
  "includeReviewerNames": false,
  "appleSearchDepth": 100,
  "topResults": 10,
  "stateStoreName": "app-store-monitor-state",
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

## `changes` (type: `string`):

No description

## `keywords` (type: `string`):

No description

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

No description

## `runSummary` (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 = {
    "apps": [
        "324684580",
        "com.spotify.music"
    ],
    "keywords": [
        "music streaming"
    ],
    "countries": [
        "us"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ivora/app-store-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": [
        "324684580",
        "com.spotify.music",
    ],
    "keywords": ["music streaming"],
    "countries": ["us"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ivora/app-store-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": [
    "324684580",
    "com.spotify.music"
  ],
  "keywords": [
    "music streaming"
  ],
  "countries": [
    "us"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call ivora/app-store-monitor --silent --output-dataset

```

## MCP server setup

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