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

Export Google Play and Apple App Store reviews together, with ratings, dates, developer replies and app metadata on every row. One consistent schema for Android and iPhone review analysis. No login required; failed and empty inputs are free.

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

## Pricing

from $0.10 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 — Google Play and App Store

Export written app reviews from **both stores in one dataset**, with app metadata on every review. Use Play packages, App Store ids, or store URLs in the same input list. No login required.

### Quick start

```json
{
  "apps": ["com.whatsapp", "310633997"],
  "maxReviewsPerApp": 100,
  "sort": "newest",
  "country": "us",
  "language": "en"
}
```

Each review includes the app title, developer, average rating, rating count and version. Google Play also includes installs, helpful votes and developer replies when available. Export JSON, CSV or Excel from the dataset. Compare written feedback across Android and iPhone, track new complaints, or feed review text into your own analysis workflow.

### Input

| Field | Default | Behavior |
|---|---|---|
| apps | Required | Play package (com.whatsapp), Play details URL, App Store id (310633997 or id310633997), or App Store URL. Up to 100 inputs, deduplicated by store + id. |
| maxReviewsPerApp | 100 | 1–10,000 on Google Play. App Store caps at 500 per app and country. |
| sort | newest | newest or most_relevant (Play helpfulness, App Store mosthelpful). |
| country | us | Two-letter storefront country. One country per run; run again for another country. |
| language | en | Google Play only. App Store review language is not selected by this field. |

Default Store example requests only 10 reviews from each of two apps. App metadata is fetched once per app. Two apps run concurrently; each app's pages are fetched sequentially.

### Output

One flat row per written review. All keys are always present; absent strings are "", absent numbers are 0. No nulls.

| Fields | Meaning |
|---|---|
| inputIndex, input | Original input position and value; duplicate apps are removed. |
| store, appId | google_play or app_store, and normalized package/id. Invalid inputs have empty store/id. |
| appTitle, developer, appRating, appRatingsCount | App metadata from the selected country. |
| appInstalls, appVersion | Install range on Play; installs is empty on App Store. Current app version. |
| reviewId, userName, rating | Review identity, public display name and 1–5 score. |
| title, text, date | Written review and UTC ISO date. Title is empty on Play. |
| reviewedVersion, helpfulCount | Reviewed app version; Play thumbs-up or App Store vote count. |
| replyText, replyDate | Play developer reply when supplied. Empty on App Store's public feed. |
| url | Play review URL; App Store app reviews page (the feed does not expose a stable review permalink). |
| country, language | Storefront country; language is empty for App Store because the RSS feed does not report it. |
| status, subStatus, error, scrapedAt | Result status, machine-readable detail, error and UTC collection timestamp. |

A failed app produces a free failure row. If a later page fails after reviews were saved, those review rows remain and a free terminal failure row explains the stop.

| status / subStatus | Charged review event? |
|---|---|
| ok / review | Yes |
| no_reviews / no_reviews | No; app exists but returned no written reviews |
| failed / invalid_input | No |
| failed / not_found | No; app missing in the selected country |
| failed / http_CODE, rate_limited, network_error | No |
| failed / free_work_limit | No; internal guard stopped unproductive work |
| failed / cost_limit_reached | No; your event spending cap stopped the run |

### Pricing

One **review** event per saved written review; app metadata included. FREE $0.0002, BRONZE $0.00015, SILVER $0.00012, GOLD and above $0.0001 per review ($0.20 / $0.15 / $0.12 / $0.10 per 1,000). Standard Actor start event: $0.00005 per GB of memory, minimum one event. Failed and empty rows have no review charge; the start event still applies. No extra dataset-item fee and no separate app lookup fee.

Rows are saved before review events are charged. The actor honors your maximum charge setting and bounds free work. A successful 4,000-review Apify spike used 256 MB with no proxy; this is a feasibility measurement, not a guaranteed throughput promise.

### Honest limits

- **App Store public RSS exposes at most 10 pages / 500 reviews per app and country**, ordered newest or most helpful. Asking for more logs the cap and returns at most 500. For other storefront feedback, run separately with another country; it does not bypass the per-country limit.
- Both feeds contain written reviews, not the full population of star ratings. Returned review count can differ from the app's overall rating/review counters.
- Google Play depends on public web endpoints through **google-play-scraper 10.1.4**, pinned exactly. Store changes can break parsing or pagination.
- Feed availability, country coverage, pagination and helpfulness order are controlled by the stores. There is no guarantee of all historical reviews, a particular count, or identical results across runs.
- App Store developer replies and install counts are not exposed by these endpoints. We do not extract private bearer tokens or use amp-api.
- Only public endpoints are used. No login, residential proxy or user-supplied cookie. Play 429 responses get one direct retry after backoff, then at most one Apify datacenter proxy attempt if available; persistent failures return free rows.
- Requests have hard deadlines; an internal cost guard can stop repeated failures with free_work_limit. No sentiment analysis or translation is performed.

### API examples

Use your own Apify token via an environment variable. Replace the placeholder locally.

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/sumitr_mardy~app-reviews-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"apps":["com.whatsapp","310633997"],"maxReviewsPerApp":10,"country":"us"}'
```

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("sumitr_mardy/app-reviews-scraper").call(
    run_input={"apps": ["com.whatsapp", "310633997"], "maxReviewsPerApp": 10}
)
for review in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(review["store"], review["rating"], review["text"])
```

### Use it from AI agents (MCP)

Hosted clients supporting OAuth can connect to the [Apify MCP server](https://mcp.apify.com/?tools=sumitr_mardy/app-reviews-scraper) and sign in with Apify.

```json
{
  "mcpServers": {
    "app-reviews": {
      "url": "https://mcp.apify.com/?tools=sumitr_mardy/app-reviews-scraper"
    }
  }
}
```

For clients using Bearer authentication, supply your token through local secret configuration:

```json
{
  "mcpServers": {
    "app-reviews": {
      "url": "https://mcp.apify.com/?tools=sumitr_mardy/app-reviews-scraper",
      "headers": {"Authorization": "Bearer <YOUR_APIFY_TOKEN>"}
    }
  }
}
```

For stdio clients with Node.js:

```json
{
  "mcpServers": {
    "app-reviews": {
      "command": "npx",
      "args": ["-y", "@apify/actors-mcp-server", "--actors", "sumitr_mardy/app-reviews-scraper"],
      "env": {"APIFY_TOKEN": "<YOUR_APIFY_TOKEN>"}
    }
  }
}
```

Agent tips: start with 10 reviews per app, inspect status before analyzing text, use the same country when comparing stores, and report the App Store cap. Never treat failure rows as customer reviews. For recurring collection, use your own Apify schedule and deduplicate by store + appId + country + reviewId.

Support: use the [Actor issues page](https://apify.com/sumitr_mardy/app-reviews-scraper/issues).

# Actor input Schema

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

Google Play packages or URLs, App Store numeric ids or URLs. Up to 100 inputs; deduplicated by store and id.

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

Maximum written reviews per app. Play up to 10,000; App Store public RSS stops at 500 per country.

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

Newest or Google Play helpfulness / App Store mosthelpful order.

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

Two-letter storefront country code, e.g. us or vn.

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

Google Play review language code, e.g. en or vi. App Store is selected by country; output language is empty.

## Actor input object example

```json
{
  "apps": [
    "com.whatsapp",
    "310633997"
  ],
  "maxReviewsPerApp": 10,
  "sort": "newest",
  "country": "us",
  "language": "en"
}
```

# Actor output Schema

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

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

# Run the Actor and wait for it to finish
run = client.actor("sumitr_mardy/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": [
    "com.whatsapp",
    "310633997"
  ],
  "maxReviewsPerApp": 10
}' |
apify call sumitr_mardy/app-reviews-scraper --silent --output-dataset

```

## MCP server setup

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