# App Store & Google Play Reviews Scraper with AI Themes (`afanasenko/app-reviews-scraper`) Actor

Scrape App Store and Google Play reviews in one run: rating, title, text, author, date, app version and developer reply. Add AI complaint and praise themes per app with shares and quotes. Paste app names or store links.

- **URL**: https://apify.com/afanasenko/app-reviews-scraper.md
- **Developed by:** [Andrey Afanasenko](https://apify.com/afanasenko) (community)
- **Categories:** Developer tools, AI, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 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 with AI Themes

[![Apify Actor](https://apify.com/actor-badge?actor=afanasenko/app-reviews-scraper)](https://apify.com/afanasenko/app-reviews-scraper)

> **Get the reviews of any app from the App Store and Google Play in one run — stars, title, text, author, date, app version and the developer's reply.**
> Type an app's name and it is found in both stores for you. Turn on AI themes to get a broad summary of the main complaint and praise themes for each store, with how many reviews back each one, the share of 1–2 star ratings and real quotes.

> **🆓 Free to start:** 3 apps a month on the free plan · the first 50 reviews of each app in each store in full · the next 50 shown with their stars, date and version.

### 🎯 What it does

**You give** one app per line: a name (`Calm`), an App Store link or id (`https://apps.apple.com/us/app/calm/id571800810`), or a Google Play link or package (`com.calm.android`). A name is matched in both stores; two links on one line pin the pair exactly.

**You get** one row per review: which store, the app, the stars, the title, the text, the reviewer's public name, the date, the app version it was written on, Google Play's helpful votes and the developer's public reply.

**With AI themes on** you also get one summary row per app and store — a broad summary of the main complaint themes (each with what to check first) and the main praise themes, with related issues grouped into one theme. Each theme carries how many reviews back it, what share of all reviews that is, how many of them are 1–2 stars, the app versions they name, and up to three verbatim quotes.

**What you won't get** more than the stores publish. The App Store gives at most **500 reviews per app** — App Store rows stop there whatever you ask for. Google Play goes up to 100,000. The App Store does not publish helpful votes or developer replies, and Google Play reviews have no title.

### 📦 Output sample

There are three kinds of rows, told apart by `rowType`:

- **`review`** — `store`, `appName`, `appId`, `appUrl`, `country`, `position`, `reviewId`, `rating`, `title`, `text`, `author`, `date`, `appVersion`, `helpfulCount`, `developerReply`, `developerReplyDate`, `rowStatus`, `input`, `note`, `scrapedAt`.
- **`theme_summary`** — `store`, `appName`, `appId`, `appUrl`, `country`, `storeRating`, `storeRatingsCount`, `reviewsAnalysed`, `averageRating`, `lowRatingShare`, `summary`, `complaintThemes`, `praiseThemes`, `input`, `note`, `scrapedAt`.
- **`app_skipped`** — `store`, `input`, `skipReason`, `note`, `scrapedAt`: an app a store does not list, or one the free plan's month left out. Never charged.

A Google Play review of Calm (US store; text shortened, reviewer name changed):

```json
{
  "rowType": "review",
  "rowStatus": "full",
  "store": "Google Play",
  "appName": "Calm - Sleep, Meditate, Relax",
  "appId": "com.calm.android",
  "appUrl": "https://play.google.com/store/apps/details?id=com.calm.android&gl=US",
  "country": "US",
  "position": 3,
  "reviewId": "2f436768-3eeb-48b7-b928-e2763ee5f893",
  "rating": 1,
  "title": null,
  "text": "This app constantly drains my battery even with background usage switched off…",
  "author": "sleepyreader",
  "date": "2026-10-26T14:02:11.000Z",
  "appVersion": "7.3",
  "helpfulCount": 2,
  "developerReply": "Thank you for your patience, and we're sorry about the battery drain…",
  "developerReplyDate": "2026-10-26T18:46:02.000Z",
  "input": "Calm",
  "note": null,
  "scrapedAt": "2026-10-27T13:38:40.512Z"
}
```

A theme summary from the same run (App Store, 300 reviews read; one theme of each list shown, texts shortened):

```json
{
  "rowType": "theme_summary",
  "store": "App Store",
  "appName": "Calm",
  "storeRating": 4.8,
  "storeRatingsCount": 1990602,
  "reviewsAnalysed": 300,
  "averageRating": 3.63,
  "lowRatingShare": 30.7,
  "summary": "Reviewers love the sleep stories and daily meditations. The biggest complaint is that paying subscribers are locked out or shown as free after an update…",
  "complaintThemes": [
    {
      "rank": 1,
      "title": "Paid subscribers locked out or not recognized",
      "kind": "account",
      "insight": "After the 7.x update, long-time subscribers are shown the paywall again.",
      "action": "Investigate the subscription restore flow for purchases made before the 7.x update.",
      "reviews": 21,
      "shareOfReviews": 7,
      "lowRatingShare": 90.5,
      "averageRating": 1.38,
      "versions": ["7.1", "7.3", "7.2"],
      "quotes": [{ "text": "Paid for years and now it says I'm on the free plan…", "rating": 1, "date": "2026-10-21T00:00:00.000Z", "appVersion": "7.3" }]
    }
  ],
  "praiseThemes": [
    { "rank": 1, "title": "Sleep stories and sounds help people sleep", "kind": "content", "reviews": 20, "shareOfReviews": 6.7, "lowRatingShare": 0, "averageRating": 4.9, "versions": ["7.3"], "quotes": [] }
  ]
}
```

In Apify Console the dataset has two views:

| View | What it shows |
|---|---|
| **Reviews** | store, app, stars, title, review, author, date, app version, helpful votes, developer reply, row status |
| **Themes** | store, app, reviews analysed, average stars, 1–2 star share, summary, complaint themes, praise themes, store rating |

### ⚡ Quick start

1. Put `Calm` in **Apps**.
2. Leave **Stores** on *App Store and Google Play* and **Max reviews per app** on 500.
3. Tick **Complaint and praise themes (AI)** if you want the summaries.
4. Click **Start**. A run like this takes about a minute.

### 🧭 When to use it

- **Product and app teams** — what users complain about after the latest release, store by store, with the app version.
- **Competitor research** — the complaints and praise of a rival app in both stores, side by side.
- **Customer support and ASO** — the reviews without a developer reply on Google Play, the 1–2 star reviews since a date.
- **Market research** — reviews of many apps in one country's store, or one app in several countries (one run per country).

### 🛠 Input

| Field | What it does |
|---|---|
| **Apps** | One app per line: a name, an App Store link or id, a Google Play link or package. Two links on one line pin the pair. Up to 50 apps a run. |
| **Stores** | Both, App Store only, or Google Play only. |
| **Max reviews per app** | The most reviews per app in each store. Default 500. Google Play: up to 100,000. The App Store gives at most 500. |
| **Complaint and praise themes (AI)** | One summary row per app and store: a broad summary of the main complaint and praise themes. Reads up to 300 reviews per summary, in the order you sorted by. |
| **Country** | Whose store to read — 104 countries both stores serve. |
| **Review language** | Google Play returns only the reviews written in this language; the App Store returns the country's reviews in any language. Default: the country's main language. |
| **Sort by** | Newest first, or the store's most-helpful order (Google Play calls it most relevant). |
| **Star ratings** | Keep only these stars, e.g. 1 and 2 for complaints. |
| **Reviews since** | Keep only reviews written on or after this date. |

### 💰 How much does it cost to scrape app reviews?

You pay per result, and nothing for a lookup that found nothing:

- **Review** — charged per review delivered in full.
- **Theme summary** — charged per app and store when its themes are written (only with AI themes on).

Filters are applied before you pay: a review that does not pass your stars or date filter is not charged. Reviews shown locked on the free plan are not charged. A theme summary that could not be written is not charged. The price per event for your plan is on the **Pricing** tab.

### 🆓 Free vs paid plan

| | Free plan | Paid plan |
|---|---|---|
| Apps a month | 3 | no limit |
| Reviews in full per app in each store | 50 | up to 100,000 (App Store: 500) |
| Next reviews | 50 shown locked (stars, date, version) | — |
| AI themes | yes, on the reviews in full | yes |

### 🧪 Recipes

**Only complaints:** Star ratings `1`, `2`, Sort by *Newest first*, AI themes on — the themes then read only the complaints.

**What changed after a release:** Reviews since the release date, Sort by *Newest first*.

**A competitor in both stores:** two lines, `Calm` and `Headspace`, AI themes on — four summary rows to compare.

**Pin an app exactly:** `https://apps.apple.com/us/app/calm/id571800810 https://play.google.com/store/apps/details?id=com.calm.android` on one line.

### 📡 Live status & storage records

| Record | What it holds |
|---|---|
| **Live Status** (`status.html`) | Progress while the run works, then what was saved — or why nothing was. |
| **Run Summary** (`RUN_SUMMARY`) | Per app and store: how it was matched, the store rating, reviews fetched, delivered, shown locked and filtered out, the themes; prices and the stop reason. |
| **User Message** (`USER_MESSAGE`) | What happened and what to change — on every run that returned nothing, and whenever the App Store's 500 limit applied. |
| **Free-Plan Limits Applied** (`FREE_LIMITS_APPLIED`) | The free-plan limits that affected the run. |

### 🤖 Programmatic / API use

```bash
curl -X POST "https://api.apify.com/v2/acts/afanasenko~app-reviews-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"apps": ["Calm", "Headspace"], "maxReviewsPerApp": 500, "ratings": ["1", "2"], "complaintThemes": true}'
```

Filter the rows by `rowType`: `review` for reviews, `theme_summary` for the themes.

### 💡 Tips & Best Practices

#### Getting maximum results

- Type the name as the store shows it. If an app is not found, paste its store link.
- For more than 500 App Store reviews, read several countries' stores — each country has its own reviews.

#### Cost optimization

- Set **Max reviews per app** to what you will read; the default 500 is enough for themes.
- Use **Star ratings** instead of filtering afterwards — what does not pass is not charged.

#### Performance

- A run with one app in both stores takes about a minute with themes, 20–30 seconds without.

#### Data quality

- The themes are counted from the reviews themselves: every count, share and quote comes from real reviews, and quotes are verbatim.
- The App Store gives the day of a review, not the time.

### ❓ FAQ

**Why do I get only 500 App Store reviews?**
The App Store publishes at most 500 reviews per app per country. Google Play goes much deeper. The run says so in the log, the status message and the User Message.

**How is my app found in the other store?**
A name is searched in each store and matched to the app whose title fits it. An App Store or Google Play link is read for the app's name and developer, and that name is searched in the other store. The Run Summary says how each app was matched. Two links on one line skip matching altogether.

**What does "most helpful" mean on Google Play?**
Google Play has no most-helpful order; its own "most relevant" order is used.

**Are the themes written by AI?**
The grouping is. The model only says which reviews belong to which theme; every number and quote in the row is computed from those reviews. The themes are broad: related problems are grouped together (for example, the price and what sits behind the paywall), so read them as the main topics reviewers raise, not as a list of every single issue.

**In what language are the themes?**
English, whatever the language of the reviews. Quotes stay in the reviewer's own words.

**Do I pay for an app that was not found?**
No. Nothing is charged for an app a store does not list, or for one the run could not reach.

### 🔗 Other related actors (same author)

- [Instagram Audience Insights](https://apify.com/afanasenko/instagram-audience-insights) — themes and post ideas from Instagram comments.
- [Backlink Scraper](https://apify.com/afanasenko/backlink-scraper) — backlinks of any website.
- [Keyword Search Volume](https://apify.com/afanasenko/keyword-search-volume) — monthly search volume and keyword ideas.

### 🛟 Support & feedback

Open the **Issues** tab with the input you used and what you expected. Ideas are welcome there too.

### ⚖️ Is it legal to scrape app reviews?

The reviews are public pages of the App Store and Google Play. Reviewers' names are their public display names. Use the data in line with the stores' terms and the privacy laws that apply to you, especially if you store or publish reviewers' names.

### 📋 Changelog

See the **Changelog** tab.

# Changelog

This Actor's version history is a separate document: https://apify.com/afanasenko/app-reviews-scraper/changelog.md

# Actor input Schema

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

One app per line: a name (Calm), an App Store link or id (https://apps.apple.com/us/app/calm/id571800810), or a Google Play link or package (com.calm.android). A name is matched in both stores; put both links on one line to pin the pair.

## `stores` (type: `string`):

Which stores to read. Each app is matched in every store you pick.

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

The most reviews returned for each app in each store. Google Play: up to 100,000. The App Store gives at most 500 reviews per app — App Store rows stop at 500 whatever you set here.

## `complaintThemes` (type: `boolean`):

Adds one summary row per app and store: a broad summary of the main complaint and praise themes (related issues grouped together), how many reviews back each, the share of 1–2 star ratings, and verbatim quotes. Reads up to 300 reviews per summary. Charged per summary written.

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

Whose store to read: reviews belong to a country's store.

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

Google Play returns only the reviews written in this language. The App Store returns the country's reviews in any language.

## `sortBy` (type: `string`):

Newest first, or the store's own most-helpful order (Google Play calls it most relevant).

## `ratings` (type: `array`):

Keep only reviews with these ratings — for example 1 and 2 stars for complaints. Empty keeps all. Filters are applied before you pay.

## `reviewsSince` (type: `string`):

Keep only reviews written on or after this date. Works best with Newest first.

## Actor input object example

```json
{
  "stores": "both",
  "maxReviewsPerApp": 500,
  "complaintThemes": false,
  "country": "US",
  "language": "",
  "sortBy": "newest",
  "ratings": []
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `themes` (type: `string`):

No description

## `liveStatus` (type: `string`):

No description

## `userMessage` (type: `string`):

What happened this run and what to change — written on every run that returned no reviews, on free-plan and first-paid runs, and whenever the App Store's 500-review limit applied.

## `runSummary` (type: `string`):

Per app and store: how it was matched, the store rating, reviews fetched, delivered, shown locked and filtered out, and the themes; prices and the stop reason.

## `freeLimitsApplied` (type: `string`):

Free-plan limits that affected this run. Empty on paid plans.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("afanasenko/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 = {}

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

```

## MCP server setup

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