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

Scrape App Store and Google Play reviews in one run. Unified schema, pagination, date filter, CSV/JSON export. $0.15 per 1,000 reviews.

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

## Pricing

from $0.15 / 1,000 review scrapeds

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

Scrape public user reviews from the **Apple App Store** and **Google Play** in one run, with one unified output format. Built for app-review monitoring, competitor research, sentiment analysis and product feedback mining.

### Why this scraper

- **Real pagination on both stores.** Google Play reviews are fetched page by page with continuation tokens, so you can collect thousands of reviews per app. On the App Store we combine the "most recent" and "most helpful" public feeds to go past the usual 500-review limit (up to ~1,000 per app and country).
- **One schema for both stores.** Every review has the same fields, so you can merge iOS and Android feedback without any post-processing.
- **No duplicates.** Reviews are deduplicated by store + review id.
- **Date filter.** Use `sinceDate` to get only fresh reviews, perfect for daily or weekly monitoring.
- **Robust.** Network errors are retried with exponential backoff, requests are rate-limited politely, and invalid apps are logged and skipped instead of failing the whole run.
- **No login, no cookies, no API keys.** Only public data is collected.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `store` | `both` | `appstore` | `googleplay` | `both` | Which store(s) to scrape. |
| `apps` | array of strings | – | App Store ids (`310633997`), Google Play package names (`com.whatsapp`), iOS bundle ids (with `store: appstore`) or store URLs. |
| `country` | string | `us` | Two-letter storefront country code. |
| `language` | string | `en` | Two-letter language code. |
| `maxReviews` | integer | `500` | Maximum reviews per app. |
| `sort` | `newest` | `relevant` | `rating` | `newest` | Fetch order. |
| `sinceDate` | ISO date | – | Only return reviews posted on or after this date. |

How `apps` entries are routed:

- `https://apps.apple.com/us/app/whatsapp-messenger/id310633997` → App Store (country taken from the URL)
- `https://play.google.com/store/apps/details?id=com.whatsapp&gl=us` → Google Play (country taken from `gl`)
- `310633997` → App Store
- `com.whatsapp` → Google Play (or an iOS bundle id lookup when `store` is `appstore`)

#### Example input

```json
{
    "store": "both",
    "apps": ["310633997", "com.whatsapp", "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580"],
    "country": "us",
    "language": "en",
    "maxReviews": 1000,
    "sort": "newest",
    "sinceDate": "2025-01-01"
}
```

### Output

Each review is saved as one dataset item:

```json
{
    "store": "googleplay",
    "appId": "com.spotify.music",
    "reviewId": "3501ac36-26ef-4534-93fd-40813dc76e4c",
    "userName": "Mike T.",
    "rating": 5,
    "title": null,
    "text": "The best music app you can use...",
    "date": "2026-09-08T16:47:12.008Z",
    "appVersion": "9.1.78.2218",
    "developerReply": null,
    "developerReplyDate": null,
    "thumbsUp": 2,
    "country": "us",
    "lang": "en",
    "url": "https://play.google.com/store/apps/details?id=com.spotify.music&reviewId=3501ac36-26ef-4534-93fd-40813dc76e4c"
}
```

| Field | Notes |
|---|---|
| `store` | `appstore` or `googleplay` |
| `appId` | Numeric App Store id or Google Play package name |
| `reviewId` | Store review id (unique per store) |
| `rating` | 1–5 stars |
| `title` | Review title (App Store only; `null` on Google Play) |
| `date` | ISO 8601 timestamp |
| `appVersion` | App version the review was written for, when available |
| `developerReply`, `developerReplyDate` | Developer response (Google Play; not exposed by the public App Store feed) |
| `thumbsUp` | Helpful votes |
| `url` | Link to the review (Google Play) or the app's reviews page (App Store) |

A run summary (reviews per app, timing and any skipped apps with the reason) is stored in the default key-value store under `RUN_SUMMARY`.

### Pricing

This Actor is prepared for pay-per-event pricing: you are charged per review saved to the dataset (`review-scraped` event). Runs that return no reviews are not charged.

### Performance

Typical speed measured on popular apps (US storefront):

- Google Play: ~1,000 reviews in about 10 seconds
- App Store: ~1,000 reviews in 30–45 seconds

### Limitations

- **App Store volume:** Apple's public review feed returns at most 500 reviews per sort order. This Actor merges two sort orders, giving up to about 1,000 unique reviews per app and country. For more, run the Actor for several countries.
- **App Store `sinceDate`:** for very popular apps that get more than 500 reviews per month, older reviews in the date window may be out of reach.
- **App Store `sort: rating`:** Apple's feed has no rating order, so the Actor collects the available reviews and sorts them by rating itself.
- **App Store developer replies** are not available in the public feed (`developerReply` is always `null`).
- **Google Play `language`:** Google Play returns reviews written in the requested language, so the same app can return different reviews for different `language` values.
- Only publicly visible reviews are collected. Stores can change their public endpoints at any time.

### FAQ

**What happens with an invalid app id?** The app is skipped, an error is logged with the reason (e.g. "App Store app 999999999999 was not found in storefront us"), and the remaining apps are still scraped. No empty records are saved.

**Do I need an Apple or Google account?** No. The Actor only uses public, unauthenticated pages and feeds.

# Actor input Schema

## `store` (type: `string`):

Which store(s) to scrape. With "both", numeric ids go to the App Store and package names (com.example.app) go to Google Play. With "appstore", dotted names are treated as iOS bundle ids.

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

App Store ids (e.g. 310633997), iOS bundle ids, Google Play package names (e.g. com.whatsapp) or store URLs (apps.apple.com/... or play.google.com/store/apps/details?id=...).

## `country` (type: `string`):

Two-letter storefront country code (e.g. us, gb, de). A country in an App Store URL path or a Play URL gl= parameter overrides this.

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

Two-letter language code (e.g. en, de). Google Play returns reviews written in this language; the App Store feed is per country.

## `maxReviews` (type: `integer`):

Maximum number of reviews to return for each app. Note: the public App Store feed exposes at most ~1,000 reviews per app and country.

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

Order in which reviews are fetched.

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

Optional. Only return reviews posted on or after this date (ISO format, e.g. 2025-01-31). Works best with sort = newest.

## Actor input object example

```json
{
  "store": "both",
  "apps": [
    "310633997",
    "com.whatsapp"
  ],
  "country": "us",
  "language": "en",
  "maxReviews": 500,
  "sort": "newest"
}
```

# Actor output Schema

## `reviews` (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": [
        "310633997",
        "com.whatsapp"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("evanatlasx/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": [
        "310633997",
        "com.whatsapp",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("evanatlasx/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": [
    "310633997",
    "com.whatsapp"
  ]
}' |
apify call evanatlasx/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,evanatlasx/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/QztodTHB9yyBMNxWK/builds/bPhanoidzHgjurCut/openapi.json
