# App Reviews Scraper (App Store + Google Play) (`signalclear/app-reviews-scraper`) Actor

Reviews from the Apple App Store and Google Play in one run: rating, title, text, app version, helpful votes and developer replies. Paste app URLs, ids or package names. Bounded retries on fresh sessions; failed apps are never charged.

- **URL**: https://apify.com/signalclear/app-reviews-scraper.md
- **Developed by:** [signal clear](https://apify.com/signalclear) (community)
- **Categories:** E-commerce, Marketing
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.10 / 1,000 results

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 Reviews Scraper (App Store + Google Play)

Get user reviews from the **Apple App Store and Google Play in one run**. Paste app URLs, App Store ids or Play package names and get back every review as clean JSON: star rating, title, text, app version, date, helpful votes and the developer's reply.

**You only pay for apps that succeed.** Each app gets at most 3 attempts, each on a fresh proxy session that resumes where the last one stopped. An app that still fails is listed in the `FAILED_APPS` record and none of its reviews are saved or charged. Runs are bounded: every request has a timeout and every app has a review cap, so a run never hangs until the platform timeout.

### What you can use it for

- **Product and UX research:** read what users say about your app, or a competitor's, right after each release.
- **Release monitoring:** schedule a daily run sorted by most recent and catch a bad update from the 1-star spike.
- **Competitor benchmarking:** the same fields for iOS and Android, so both stores fit in one spreadsheet or dashboard.
- **Support and reply tracking:** see which reviews got a developer reply and how fast.
- **Sentiment analysis and AI agents:** a flat, predictable JSON row per review, ready for an LLM or a BI tool.

### How to use it

1. Add one or more **apps**. Any of these work, and you can mix stores in one list:
   - `https://apps.apple.com/us/app/whatsapp-messenger/id310633997`
   - `310633997` or `id310633997`
   - `https://play.google.com/store/apps/details?id=com.whatsapp`
   - `com.whatsapp`
2. Pick a **country** (App Store storefront, e.g. `us`, `gb`, `de`) and a **language** (Google Play review language, e.g. `en`, `de`).
3. Choose **sort** (most recent or most helpful), the **maximum reviews per app** and, optionally, a **minimum star rating**.
4. Turn on **Also fetch app metadata** if you want the developer, category, average rating and rating count on every row.
5. Click **Start**.

#### Example input

```json
{
  "apps": ["310633997", "com.whatsapp"],
  "country": "us",
  "language": "en",
  "sort": "newest",
  "maxReviewsPerApp": 200,
  "minRating": 1,
  "includeAppMetadata": false
}
```

### Output

One row per review:

```json
{
  "store": "googlePlay",
  "appId": "com.ubercab",
  "appTitle": "Uber: Rides, eats, hotels",
  "reviewId": "9d243b45-6ac7-45b1-b63f-3e75e393fccc",
  "author": "Sample User",
  "rating": 2,
  "title": null,
  "text": "Driver cancelled twice and support never answered.",
  "version": "4.654.10002",
  "reviewedAt": "2026-10-27T03:57:45+00:00",
  "helpfulCount": 14,
  "voteCount": null,
  "developerReply": {
    "text": "We're sorry to hear this. Please reach out through the Help section in the app.",
    "repliedAt": "2026-10-27T09:12:03+00:00"
  },
  "country": "us",
  "language": "en",
  "url": "https://play.google.com/store/apps/details?id=com.ubercab&hl=en&gl=us&reviewId=9d243b45-6ac7-45b1-b63f-3e75e393fccc",
  "source": "batchexecute",
  "input": "com.ubercab",
  "scrapedAt": "2026-10-28T04:01:29+00:00"
}
```

| Field | App Store | Google Play |
|---|---|---|
| `title` | yes | always `null` (Play reviews have no title) |
| `version` | RSS source only | yes |
| `helpfulCount` | RSS source only (Apple's helpful vote sum) | yes (thumbs-up count) |
| `voteCount` | RSS source only (total votes) | `null` |
| `developerReply` | web API source only | yes |
| `url` | the app's review page | a link to the single review |

`source` tells you where a row came from: `rss` or `amp` (App Store) or `batchexecute` (Google Play). With **Also fetch app metadata** on, each row also has an `appInfo` object.

Apps that failed are listed in the key-value store record `FAILED_APPS` with the reason, for example `not found (no App Store app 9999999999 in storefront "us")`.

### How the App Store source is chosen

Apple offers two public review sources, and they return different fields:

- **RSS feed:** newest first only, 50 reviews a page, and Apple stops at **page 10 (500 reviews)**. Includes app version and vote counts. No developer replies.
- **App Store web API:** the endpoint the App Store website uses. Pages deeper than 500, supports most helpful, and includes developer replies. No app version or vote counts.

With **App Store review source** on *Auto*, the scraper uses RSS when you ask for 500 or fewer newest reviews without a rating filter, and the web API otherwise. You can force either one in the advanced settings.

### Pricing

You pay per result: one result per review saved. Apps that fail are never pushed to the dataset, so they cost nothing, and a run where every app fails exits with an error and charges nothing. See the Pricing tab for current rates.

### Limitations

- **Apple RSS cap:** the RSS feed stops at 500 reviews and has no "most helpful" sort (Apple returns an empty feed for it). Use the web API source for more.
- **App Store reviews are per country.** An app with few reviews in one storefront can have thousands in another. An app that isn't sold in the chosen storefront is reported as not found.
- **Google Play reviews are per language**, not per country. Set *language* to the language the reviews are written in.
- **Google Play "most helpful"** is Play's own *most relevant* order.
- **Rating filter:** filtering happens after fetching, and each app scans at most 10x your maximum (at least 500 reviews). For a rare rating that can return fewer rows than the maximum.
- **Deep runs take time:** the web API returns 20 reviews per request, and both stores rate-limit fast clients, so the scraper paces its requests.
- Both stores can change these undocumented endpoints without notice. When that happens, the affected apps land in `FAILED_APPS` (not charged) and a fix follows.

### Tips

- **Proxy:** the default Apify proxy (datacenter) is usually enough. If the log shows many retries, switch the proxy to residential.
- **Large lists:** keep *Apps in parallel* at 2-4.
- **Monitoring:** run on a schedule with *Most recent* and a small maximum, then deduplicate on `reviewId`.

### Legal and data

This Actor reads reviews that the App Store and Google Play publish openly to anyone, without logging in. For each review it stores the reviewer's display name exactly as the store shows it next to the review. It does not collect profile pictures, user ids, profile links, emails or any other personal data. You are responsible for using the data in line with the stores' terms and with the privacy law that applies to you (for example GDPR if you process reviews from EU users).

### FAQ

**Why are there fewer App Store reviews than the app page shows?** The rating count on the app page includes star ratings without text. Only written reviews are returned, and the RSS source stops at 500.

**Can I get reviews from several countries?** Run the Actor once per country. Reviews differ per storefront.

**Something broke?** Open an issue on the Issues tab with your run ID.

# Actor input Schema

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

One app per line. App Store: an apps.apple.com URL or the numeric app id (e.g. 310633997). Google Play: a play.google.com URL or the package name (e.g. com.whatsapp). The store is detected automatically.

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

Two-letter country code, such as us, gb or de. Picks the App Store storefront (reviews differ per country) and is sent to Google Play as the country.

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

Language code, such as en, de or pt-BR. Google Play returns reviews written in this language. For the App Store it only localizes the request; App Store reviews follow the country.

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

Order reviews by newest first or by the store's most-helpful ranking. Most helpful always uses the deeper Apple endpoint.

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

Stop after this many reviews for each app.

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

Keep only reviews with at least this many stars (1-5). Leave empty for all ratings. Filtering scans at most 10x the maximum (at least 500 reviews) per app, so a rare rating can return fewer results.

## `includeAppMetadata` (type: `boolean`):

Adds an appInfo object to each review: developer, category, average rating, rating count, price, icon and description (App Store also: current version and release dates).

## `appleSource` (type: `string`):

Auto uses Apple's RSS feed (includes app version and vote counts, newest only, at most 500 reviews) when it can, otherwise the App Store web API (deeper, supports most helpful, includes developer replies, no version or votes).

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

Apps fetched at the same time. Higher is faster but more likely to be rate-limited.

## `maxAttempts` (type: `integer`):

Each attempt uses a fresh proxy session and resumes where the last one stopped. Apps that still fail are listed in FAILED_APPS and are not charged.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for a single HTTP response before the attempt counts as failed and is retried on a fresh session.

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

Both stores' review endpoints work from datacenter IPs, so the default Apify proxy is usually enough. Switch to residential if you see many retries.

## Actor input object example

```json
{
  "apps": [
    "https://apps.apple.com/us/app/whatsapp-messenger/id310633997",
    "com.whatsapp"
  ],
  "country": "us",
  "language": "en",
  "sort": "newest",
  "maxReviewsPerApp": 100,
  "includeAppMetadata": false,
  "appleSource": "auto",
  "maxConcurrency": 3,
  "maxAttempts": 3,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

Dataset results in the "Reviews" view.

## `developerReplies` (type: `string`):

Dataset results in the "Developer replies" view.

## `failed` (type: `string`):

JSON list of apps that failed after every retry, with the error for each. Empty when everything succeeded. Failed inputs are never charged.

# 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"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("signalclear/app-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",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("signalclear/app-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"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call signalclear/app-reviews-scraper --silent --output-dataset

```

## MCP server setup

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