# App Store Review Insights (`singgendarhan/app-store-review-insights`) Actor

Turn iOS App Store reviews into insights: rating trends, app-version regression alerts, complaint themes (crashes, login, pricing, ads, bugs...) and the phrases customers repeat. Compare competitors. Official Apple review feed, no login.

- **URL**: https://apify.com/singgendarhan/app-store-review-insights.md
- **Developed by:** [Nick Na](https://apify.com/singgendarhan) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 insights reports

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 Review Insights

**Turn iOS App Store reviews into answers.** Paste one or more App Store links, pick countries, and get:

- every written review as a clean, normalized row (rating, title, text, app version, date, helpful votes, theme tags), and
- a ready-to-share **insights report** per app: rating trend, **app-version regression alerts**, the complaint themes that drive 1-2 star reviews, and the exact phrases customers keep repeating, plus a **side-by-side competitor comparison**.

Data comes from **Apple's official public customer-review feed**. No login, no cookies, no browser automation, no scraping of App Store web pages.

### Who it is for

- **Product managers and mobile teams**: catch a bad release fast. The regression detector flags a version whose share of 1-2 star reviews jumps compared with the previous version, and tells you which themes rose (for example "crashes 3% to 25%").
- **App marketers and ASO specialists**: see what people praise in their own words ("easy to use", "sleep stories") and what blocks 5-star ratings ("free trial", "customer service").
- **Agencies and consultants tracking competitors**: run your client and 2-5 competitors together, per country, and get a comparison showing which app over-indexes on ads, pricing, bugs or support complaints. Schedule it weekly and send the report link to the client.
- **Indie developers**: a weekly health check of your app for a few cents.

### What you get

| Output | Where | What is in it |
|---|---|---|
| Reviews | Default dataset | One row per review: `appId`, `appName`, `country`, `reviewId`, `rating`, `ratingGroup`, `title`, `text`, `version`, `date`, `dateUtc`, `helpfulVotes`, `totalVotes`, `themes`, `sortOrder`, `appStoreUrl`, `fetchedAt` |
| App insights | `insights` dataset | One record per app: rating distribution, 1-2 star share, App Store rating for context, per-country breakdown, weekly and daily trend, recent-vs-previous trend per country, regressions, themes, top complaint and praise phrases (with an example quote each), keywords, notes and a plain-English summary |
| Version insights | `versions` dataset | One record per app version: reviews, average, 1-2 star share, change vs the previous version, z-score, regression or improvement flag, rising themes |
| Comparison | `insights` dataset (`recordType: comparison`) | When you enter 2+ apps: ranking, theme shares per app, themes each app over-indexes on |
| Report | Key-value store `INSIGHTS.html` (also `INSIGHTS.md`, `INSIGHTS.json`) | A readable report with a public link, shown in the run's Output tab. Works in light and dark mode |

Problems with individual inputs (an unknown storefront, an app with no reviews, a typo in a link) are listed as `recordType: error` records and in the report. They never stop the run.

### How to use it

1. Paste App Store links, numeric app IDs (`571800810` or `id571800810`) or bundle IDs (`com.calm.calmapp`) into **Apps**.
2. Pick one or more **Countries**. Each storefront has its own reviews.
3. Optionally set **Only reviews since** (`2026-09-01` or `30 days`) and **Max reviews per app and country**.
4. Click **Start**. A typical run with 3 apps in 2 countries (3,000 reviews) finishes in about a minute.
5. Open the **Report** in the Output tab, or export the datasets as JSON, CSV or Excel, or connect them to Google Sheets, Slack, Make or Zapier with Apify integrations.

**Tip:** Apple's feed only exposes the most recent 500 reviews per app, country and sort order. For busy apps that can be just a few days. Create a **schedule** (for example weekly) to build a longer history and get alerted to regressions as they happen.

#### Input example

```json
{
  "apps": [
    "https://apps.apple.com/us/app/calm/id571800810",
    "https://apps.apple.com/us/app/headspace-sleep-meditation/id493145008"
  ],
  "countries": ["us", "gb"],
  "maxReviewsPerCountry": 500,
  "sinceDate": "90 days",
  "sortBy": "mostRecent",
  "compareApps": true,
  "dropReviewerNames": true,
  "customThemes": { "dark mode": ["dark mode", "night mode"] }
}
```

| Field | Default | Notes |
|---|---|---|
| `apps` | required | App Store URLs, numeric IDs or bundle IDs |
| `countries` | `["us"]` | Any of the 177 App Store storefront codes. `uk` is accepted as `gb` |
| `maxReviewsPerCountry` | 500 | 1-1000. Also caps your cost |
| `sinceDate` | none | `YYYY-MM-DD` or relative (`30 days`, `6 weeks`, `3 months`, `1 year`) |
| `sortBy` | `mostRecent` | `mostRecent`, `mostHelpful`, or `both` (deduplicated, up to ~1,000 per app and country) |
| `compareApps` | `true` | Adds the comparison when 2+ apps have reviews. No extra charge |
| `dropReviewerNames` | `true` | Reviewer nicknames are not saved unless you turn this off. Profile links are never saved |
| `includeAppDetails` | `true` | One call per app to Apple's public iTunes Lookup API for the app name, store rating and current version |
| `customThemes` | none | Your own themes, e.g. `{"widgets": ["widget", "widgets"]}` |
| `regressionThresholdPct` | 15 | Percentage-point rise in 1-2 star share that flags a version |
| `regressionMinReviews` | 10 | Minimum reviews a version needs to be compared |
| `topPhrasesCount` | 10 | Phrases per list |

#### Output example: one review (illustrative)

```json
{
  "appId": "123456789",
  "appName": "Example Notes",
  "country": "us",
  "reviewId": "14690000001",
  "rating": 2,
  "ratingGroup": "negative",
  "title": "Sync broke after the update",
  "text": "Since the last update my notes no longer sync between my iPhone and iPad, and it crashed twice today.",
  "version": "5.12.1",
  "date": "2026-10-22T04:45:30-07:00",
  "dateUtc": "2026-10-22T11:45:30Z",
  "helpfulVotes": 3,
  "totalVotes": 4,
  "themes": ["crash", "sync", "update"],
  "sortOrder": "mostRecent",
  "appStoreUrl": "https://apps.apple.com/us/app/id123456789",
  "fetchedAt": "2026-10-23T22:00:48Z"
}
```

#### Output example: app insights (shortened)

Real numbers from a test run on 2026-10-23 (US + GB, 1,000 reviews). The app name is hidden here.

```json
{
  "recordType": "app",
  "appName": "Meditation app B",
  "reviewCount": 1000,
  "avgRating": 2.29,
  "lowStarShare": 63.8,
  "storeRating": 4.84,
  "topComplaintTheme": "subscription_price",
  "regressions": [{
    "version": "8.11.4", "comparedTo": "8.9.0", "lowStarShare": 93.5, "lowStarShareDelta": 39.0, "severity": "high",
    "reason": "1-2 star share rose from 54.5% (v8.9.0, n=11) to 93.5% (n=31), +39.0 pts, z=2.98; rising themes: bugs / broken features 9.1%→19.4%"
  }],
  "topComplaintPhrases": [
    {"phrase": "free trial", "reviews": 63, "share": 9.9},
    {"phrase": "behind a paywall", "reviews": 16, "share": 2.5},
    {"phrase": "refused to refund", "reviews": 11, "share": 1.7}
  ],
  "topPraisePhrases": [
    {"phrase": "changed my life", "reviews": 11, "share": 4.4},
    {"phrase": "highly recommend", "reviews": 9, "share": 3.6}
  ],
  "summary": [
    "Average rating in this sample is 2.29★, with 63.8% of reviews at 1-2★ and 25.2% at 4-5★. That is 2.5★ below the overall App Store rating (4.84★, US storefront).",
    "US: rating is trending down, from 2.55★ (n=22) in the previous 28 days to 1.65★ (n=20) in the last 28 days (-0.90).",
    "Most common complaint theme: subscription / price, mentioned in 48.3% of 1-2★ reviews."
  ]
}
```

### How the insights are computed

Everything is deterministic: no AI, no sampling, so the same reviews always give the same report and every number can be traced back to rows in the dataset.

- **Themes**: keyword rules for crashes/freezes, login, subscription/price, ads, bugs, slow/performance, battery, sync/data loss, customer support and "since the update" complaints, in English plus common Spanish, German, French, Portuguese, Italian and Japanese terms. Add your own with `customThemes`.
- **Phrases**: 2-3 word phrases counted once per review, kept only if they recur and are clearly more common in 1-2 star reviews than in 4-5 star reviews (or the reverse for praise). Brand names and filler words are skipped.
- **Regression detector**: each version is compared with the closest earlier version that has enough reviews. It is flagged when the 1-2 star share rises by at least the threshold (default 15 points) and the rise is statistically meaningful (one-sided two-proportion z-test, about 95%). When an app ships many small patch releases, versions are grouped by minor release (8.34.0 + 8.34.1 = 8.34.x).
- **Trends**: weekly and daily tables, and a per-country "last N days vs the N days before" comparison using the shortest window (7 to 91 days) with enough reviews.

### Pricing

Pay per event. You only pay for results:

| Event | Price |
|---|---|
| Review saved to the dataset | **$0.20 per 1,000 reviews** ($0.0002 each) |
| Insights report per app | **$0.05 per app** (covers all selected countries) |
| Actor start | Apify's standard $0.00005 |

Free: the competitor comparison, error records, apps with no reviews, and reports built from fewer than 10 reviews.

Examples: one app, one country, 500 reviews = **$0.15**. Five competitors in two countries, 5,000 reviews = **$1.25**. A weekly schedule for that = about $5 a month.

The Actor respects the maximum cost you set for a run. It finishes apps one at a time, always keeps enough budget for the report of the app it is working on, and skips the remaining apps instead of going over.

### Limits

- **500 reviews per app, country and sort order.** This is Apple's limit (10 pages of 50). `sortBy: both` merges the most-recent and most-helpful windows for up to about 1,000.
- **Written reviews only.** Star-only ratings are not in the feed, so the sample average usually sits below the App Store rating. The report shows both.
- **No developer responses** (not included in Apple's feed).
- **iOS App Store only.** Google Play is not supported yet.
- Phrase extraction works for languages that separate words with spaces. Japanese, Chinese, Korean and Thai reviews still count in ratings, trends and themes.
- Requests are paced to at most one per second to be polite to Apple's servers, so a run takes roughly 1 second per 50 reviews.

### FAQ

**Is this allowed?** The Actor reads Apple's public customer-review RSS feed and the public iTunes Lookup API, which are unauthenticated endpoints Apple provides for RSS feeds and app lookups. It does not log in, does not scrape App Store web pages and does not bypass any protection. Reviewer nicknames are dropped by default and profile links are never stored. You are responsible for how you use the data; check the terms that apply to your use case.

**Why does the average differ from the App Store rating?** The App Store rating includes millions of star-only ratings. Written reviews skew more negative, which is exactly why they are useful for finding problems.

**Why did I get fewer reviews than my limit?** The app may have fewer written reviews in that country, the date filter may cut older ones, or Apple's 500-per-sort cap was reached. Each app record has `byCountry` and `notes` explaining the coverage.

**Does it use AI?** No. v1 is deterministic on purpose: reproducible, cheap and auditable.

**How do I get alerts?** Schedule the Actor and connect the `insights` dataset to Slack or email with Apify integrations, or check `regressions` in the app record.

**Can I monitor many apps?** Yes. Apps are processed one after another; 10 apps in 2 countries at 500 reviews each take about 3.5 minutes.

### Changelog

See [CHANGELOG.md](CHANGELOG.md).

# Changelog

This Actor's version history is a separate document: https://apify.com/singgendarhan/app-store-review-insights/changelog.md

# Actor input Schema

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

One app per line. Accepts App Store links (https://apps.apple.com/us/app/calm/id571800810), numeric app IDs (571800810 or id571800810) and bundle IDs (com.calm.calmapp). Add competitors to compare them side by side.

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

Reviews are stored per country. Each country is fetched separately (up to 500 reviews per sort order). Pick the markets you care about.

## `maxReviewsPerCountry` (type: `integer`):

Upper limit of reviews saved for each app in each country. Apple's feed returns at most 500 per sort order (1,000 with 'Both'). You are charged per saved review, so this also caps cost.

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

Optional. Skip reviews older than this date, e.g. 2026-09-01 or '30 days'. Leave empty to take as many as the feed allows.

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

'Most recent' is best for monitoring and trends. 'Most helpful' surfaces older, highly voted reviews. 'Both' merges the two windows (deduplicated) for up to ~1,000 reviews per app and country.

## `compareApps` (type: `boolean`):

When you enter 2 or more apps, add a competitor comparison (rating, 1-2 star share, themes each app over-indexes on). Included at no extra charge.

## `dropReviewerNames` (type: `boolean`):

On by default for privacy: reviewer nicknames are not saved. Turn off only if you need them. Reviewer profile links are never saved.

## `includeAppDetails` (type: `boolean`):

Looks up each app once via Apple's public iTunes Lookup API so reports show the app name, overall store rating and current version. Required for bundle-ID inputs.

## `customThemes` (type: `object`):

Optional. Your own themes as {"theme name": \["keyword", "another keyword"]}, matched case-insensitively as whole words. Example: {"dark mode": \["dark mode", "night mode"], "widgets": \["widget", "widgets"]}. Built-in themes: crash, login, subscription_price, ads, bug, slow, battery, sync, support, update.

## `regressionThresholdPct` (type: `integer`):

Flag a version when its share of 1-2 star reviews rises by at least this many percentage points vs the previous version (and the rise is statistically meaningful).

## `regressionMinReviews` (type: `integer`):

Versions with fewer reviews are reported but not used for regression flags.

## `topPhrasesCount` (type: `integer`):

How many complaint and praise phrases to list per app.

## Actor input object example

```json
{
  "apps": [
    "https://apps.apple.com/us/app/calm/id571800810",
    "https://apps.apple.com/us/app/headspace-sleep-meditation/id493145008"
  ],
  "countries": [
    "us"
  ],
  "maxReviewsPerCountry": 100,
  "sortBy": "mostRecent",
  "compareApps": true,
  "dropReviewerNames": true,
  "includeAppDetails": true,
  "regressionThresholdPct": 15,
  "regressionMinReviews": 10,
  "topPhrasesCount": 10
}
```

# Actor output Schema

## `report` (type: `string`):

Readable report with summary, trends, version regressions, themes and phrases.

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

One row per review, normalized, with theme tags.

## `insights` (type: `string`):

One record per app, plus a comparison record and any per-item problems.

## `versions` (type: `string`):

One record per app version, with regression flags.

## `markdown` (type: `string`):

No description

## `json` (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": [
        "https://apps.apple.com/us/app/calm/id571800810",
        "https://apps.apple.com/us/app/headspace-sleep-meditation/id493145008"
    ],
    "countries": [
        "us"
    ],
    "maxReviewsPerCountry": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("singgendarhan/app-store-review-insights").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/calm/id571800810",
        "https://apps.apple.com/us/app/headspace-sleep-meditation/id493145008",
    ],
    "countries": ["us"],
    "maxReviewsPerCountry": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("singgendarhan/app-store-review-insights").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/calm/id571800810",
    "https://apps.apple.com/us/app/headspace-sleep-meditation/id493145008"
  ],
  "countries": [
    "us"
  ],
  "maxReviewsPerCountry": 100
}' |
apify call singgendarhan/app-store-review-insights --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,singgendarhan/app-store-review-insights"
        }
    }
}
```

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/Y7OKYbfkkkxpsctaN/builds/cC1v5168gC8n99X3n/openapi.json
