# App Store & Google Play Reviews Scraper (`simiodev/app-store-google-play-reviews-scraper`) Actor

User reviews, ratings, developer replies and app info from the Apple App Store and Google Play in one run. No login, no proxy.

- **URL**: https://apify.com/simiodev/app-store-google-play-reviews-scraper.md
- **Developed by:** [Nestor Cabrera](https://apify.com/simiodev) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 reviews

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 Reviews Scraper

Extract user reviews, star ratings, developer replies and app details from the **Apple App Store** and **Google Play** in a single run. No account, no login, no proxy and no API keys. Results are sorted newest first (or most helpful first) and are ready to export as JSON, CSV or Excel.

Apple reviews come from Apple's public customer-reviews feed and app lookup API. Google Play reviews are read through the open-source `google-play-scraper` library. Both are public data.

### Use cases

- **Review monitoring and alerts.** Turn on `incremental`, set `minRating: 1` and `maxRating: 2`, schedule the actor hourly or daily and connect the dataset to Make, n8n, Slack or a webhook to get notified about new complaints.
- **Competitor and ASO research.** Compare ratings, complaints and feature requests of your app and its competitors across stores and countries in one dataset.
- **Support triage.** Pull low-star reviews with their app version and route them to your support or engineering queue.
- **Product feedback mining.** Find what users love or hate by version, country or language, and see how often the developer replies on Google Play.
- **Datasets for analysis.** Export clean review text with dates and metadata to JSON, CSV or Excel for sentiment analysis or NLP. Check the licensing and privacy rules that apply to your use.

### Input

| Field | Description |
|---|---|
| `apps` | App Store URLs, Google Play URLs, numeric Apple ids (`310633997`) or Android package names (`com.whatsapp`). The store is detected automatically. Duplicates are merged. Entries that cannot be recognised are skipped with a warning. |
| `countries` | 2-letter storefront codes. Default `["us"]`. |
| `languages` | Google Play only. Default `["en"]`. |
| `maxReviewsPerApp` | Default 100. Applied per app, country and language. Apple caps at about 500 reviews per app and country. |
| `sort` | `newest` (default) or `mostHelpful`. |
| `sinceDate` / `untilDate` | ISO date (`2026-10-01`) or relative (`7d`, `12h`, `2w`). With `newest` sorting, paging stops once `sinceDate` is passed. |
| `minRating` / `maxRating` | Keep only reviews within these stars (1-5). Filtered-out reviews are not charged and do not count toward the cap. |
| `incremental` | Return only reviews newer than the last run, tracked per app, country and language in a store on your account. Needs `sort: newest`. Default off. See below. |
| `includeSummary` | Adds one free summary record per app unit. Default on. |
| `includeAppInfo` | Adds one free record per app and country. Default on. |

Every app is scraped once per country, and Google Play apps once per country and language.

Example:

```json
{
  "apps": [
    "https://apps.apple.com/us/app/whatsapp-messenger/id310633997",
    "com.whatsapp"
  ],
  "countries": ["us", "gb"],
  "maxReviewsPerApp": 200,
  "minRating": 1,
  "maxRating": 2,
  "sinceDate": "30d"
}
```

### Output

One dataset item per review (`type: "review"`):

```json
{
  "type": "review",
  "store": "apple",
  "appId": "310633997",
  "appName": "WhatsApp Messenger",
  "country": "gb",
  "language": null,
  "reviewId": "14633530350",
  "rating": 1,
  "title": "Lost the data",
  "text": "I have lost all my data ...",
  "author": "Karan Nelapati",
  "date": "2026-10-06T08:03:37+00:00",
  "appVersion": "26.39.73",
  "helpfulCount": 0,
  "totalVotes": 0,
  "developerReply": null,
  "url": null
}
```

Field notes:

- `title` exists only on the App Store. `language` and `developerReply` (`{text, date}`) exist only on Google Play.
- `helpfulCount` is the thumbs-up count on Google Play and the helpful vote sum on the App Store. `totalVotes` is the App Store vote count and null on Google Play.
- `url` links to the review on Google Play. The App Store has no per-review link, so it is null there.
- `date` is ISO 8601 in UTC.

Plus these records, which are never charged:

- `type: "app"`: `store`, `appId`, `name`, `developer`, `rating`, `ratingCount`, `version`, `price`, `currency`, `category`, `icon`, `country`, `url`.
- `type: "summary"`: one per completed app unit, after its reviews: `store`, `appId`, `appName`, `country`, `language`, `reviewCount`, `averageRating` (1 decimal), `ratingDistribution` (`{"1": n, ..., "5": n}`), `developerReplyRate` (0 to 1, null on the App Store), `oldestReviewDate`, `newestReviewDate`. It is computed only from the reviews returned in that run, so rating filters and incremental mode apply. No summary is written for units that failed, were interrupted by your maximum charge, or (in incremental mode) had no new reviews.
- `type: "error"`: `app`, `store`, `country`, `error` (and `language` on Google Play). Written when an app does not exist in that storefront, has no reviews there, or keeps failing. An error on one app never stops the others.

### Incremental mode in detail

- First run: you get the newest reviews (up to `maxReviewsPerApp`) and the actor stores a watermark per app, country and language in a key-value store named `app-reviews-state` on your account. The watermark is the date of the newest review it saw (before rating filters) plus the ids of the reviews at exactly that timestamp.
- Next runs: paging stops as soon as it reaches a review at or below the watermark, so only newer reviews are returned and charged. Reviews that share the watermark's exact timestamp but were not seen before are still delivered. If nothing is new, the run costs almost nothing and writes no summary.
- Known gap: if more than `maxReviewsPerApp` new reviews appear between two runs, you get the newest ones and the older ones in between are skipped. Raise the limit or run more often if you must not miss any.
- If an app fails or the run stops early (for example, you hit your maximum charge), that app's watermark is not advanced, so the next run may repeat some reviews but will never skip any.
- Rating filters, date filters, countries and languages can be combined with it. Changing the `apps`, `countries` or `languages` lists simply starts new watermarks for the new combinations.
- Incremental mode needs `sort: newest`, because the watermark relies on newest-first order.

### Pricing

Pay per event: you are charged per **review** returned. App info, summary and error records are free. `maxReviewsPerApp` is therefore also your cost cap per app and country, and the run stops cleanly when your maximum charge is reached.

### Good to know

- **Apple returns at most about 500 reviews per app and country** (10 pages of 50). To get more, add more countries.
- Google Play reviews are largely shared between countries for the same language, so different countries can return many identical reviews. Use more `languages` or one country for deduplicated results.
- With `mostHelpful` sorting, `sinceDate` cannot stop paging early and older reviews are skipped instead, which means more requests.
- Narrow rating filters on large apps require scanning more reviews. A single exact rating (for example only 1 star) is filtered by Google Play itself.
- Public data only: no private reviews, no reviewer profiles, no data behind a login.
- Both stores rate-limit heavy traffic. The actor paces requests, runs a few apps at a time and retries with backoff, but very large runs can still hit limits and report errors.
- Counts, ratings and votes are a snapshot at the time of the run.

### Is it legal?

It only collects reviews that the stores already show publicly. You are responsible for how you use the data, including compliance with the stores' terms and with data-protection law such as GDPR, since reviews contain usernames and free text.

# Actor input Schema

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

App Store URLs (https://apps.apple.com/us/app/whatsapp-messenger/id310633997), Google Play URLs (https://play.google.com/store/apps/details?id=com.whatsapp), numeric Apple ids (310633997) or Android package names (com.whatsapp). The store is detected automatically.

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

2-letter storefront codes such as us, gb, es, de. Each app is scraped once per country.

## `languages` (type: `array`):

Language codes such as en, es, pt-BR. Each Google Play app is scraped once per country and language. Ignored for the App Store.

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

Cap applied per app, country and language. Apple only exposes about 500 reviews per app and country, so higher values return at most that many from the App Store. You are charged per review returned.

## `sort` (type: `string`):

Newest first (default), or most helpful first.

## `sinceDate` (type: `string`):

ISO date such as 2026-10-01 or relative value such as 7d, 12h, 2w. With newest sorting, paging stops as soon as this date is passed.

## `untilDate` (type: `string`):

Same formats as above. Combine with the previous field to fetch a past time window.

## `minRating` (type: `integer`):

Only keep reviews with at least this many stars (1-5).

## `maxRating` (type: `integer`):

Only keep reviews with at most this many stars (1-5). Set minimum 1 and maximum 2 to collect complaints. Reviews filtered out are not charged and do not count toward the cap.

## `includeAppInfo` (type: `boolean`):

Adds one record per app and country with name, developer, rating, rating count, version, price and category (free).

## `incremental` (type: `boolean`):

Return only reviews newer than the last run, tracked per app, country and language in a store named app-reviews-state on your account. Requires newest sorting. Ideal for scheduled monitoring.

## `includeSummary` (type: `boolean`):

Adds one free summary record per app unit with review count, average rating, rating distribution, developer reply rate and date range of the reviews returned in this run.

## Actor input object example

```json
{
  "apps": [
    "https://apps.apple.com/us/app/whatsapp-messenger/id310633997",
    "com.whatsapp"
  ],
  "countries": [
    "us"
  ],
  "languages": [
    "en"
  ],
  "maxReviewsPerApp": 100,
  "sort": "newest",
  "includeAppInfo": true,
  "incremental": false,
  "includeSummary": true
}
```

# Actor output Schema

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

Scraped reviews in table view. Switch the format in the dataset page to export JSON, CSV or Excel.

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

Reviews, app info and error records.

## `summaries` (type: `string`):

One summary per app unit: count, average rating, distribution and reply rate.

# 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/whatsapp-messenger/id310633997",
        "com.whatsapp"
    ],
    "countries": [
        "us"
    ],
    "languages": [
        "en"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("simiodev/app-store-google-play-reviews-scraper").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/whatsapp-messenger/id310633997",
        "com.whatsapp",
    ],
    "countries": ["us"],
    "languages": ["en"],
}

# Run the Actor and wait for it to finish
run = client.actor("simiodev/app-store-google-play-reviews-scraper").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/whatsapp-messenger/id310633997",
    "com.whatsapp"
  ],
  "countries": [
    "us"
  ],
  "languages": [
    "en"
  ]
}' |
apify call simiodev/app-store-google-play-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,simiodev/app-store-google-play-reviews-scraper"
        }
    }
}
```

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/Rxe5MWVG9eMpVW4Lp/builds/yq4Tn1tcEaWKGmtIj/openapi.json
