# App Store Review Scraper: iOS Reviews by Country (`axiorasolutions/app-review-scraper`) Actor

Scrape Apple App Store reviews for any iOS or iPadOS app across up to 175 country storefronts. Returns rating, title, body, author, app version and helpful votes per review, plus an app profile row with rating counts, price, genres and release notes. Accepts app IDs, bundle IDs, URLs or names.

- **URL**: https://apify.com/axiorasolutions/app-review-scraper.md
- **Developed by:** [Axiora Solutions](https://apify.com/axiorasolutions) (community)
- **Categories:** Business, Marketing, For creators
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.16 / 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 Store Review Scraper — iOS App Store reviews across 175 country storefronts

**App Store reviews** are served per storefront, so this Actor scrapes them for any iOS or iPadOS app across as many country storefronts as you choose — returning star rating, title, body, reviewer nickname, app version, helpful votes and country for every review. Because Apple stores reviews per country, your **country list decides which reviews exist at all**: a US-only run will never show you the German one-star reviews tanking your DACH conversion. No API key or login is needed — add your apps and countries, then click **Start**.

### What you get

- `rating`, `title`, `body`, `authorName` and `reviewedAt` for each review.
- `appVersion` plus `isCurrentVersion`, so you can attribute complaints to a specific build.
- `storefront` on every row, tagging the country the review came from.
- `helpfulVotes` / `totalVotes`, and `sentimentHint` (deterministic, rule-based).
- `reviewUid` and `contentHash` for clean de-duplication across runs.
- An optional app profile row with ratings, price, genres, release notes and screenshots.

### Quick start

1. Add your apps — a numeric App Store ID, bundle ID, full App Store URL, or `name:Duolingo`.
2. Add country storefronts — two-letter codes such as `us`, `gb`, `de`, `fr`, `jp`.
3. Set **Max reviews per app** (this is the number that controls your cost).
4. Click **Start** and read the **Reviews** and **App profiles** dataset tabs.

```json
{
  "apps": ["310633997", "com.spotify.client"],
  "countries": ["us", "gb", "de"],
  "maxReviewsPerApp": 300
}
```

Want a free look first? Set **Max reviews per app** to `10` with one app and one country.

### Example output

One representative review row:

```json
{
  "recordType": "review",
  "ok": true,
  "errorCode": null,
  "reviewUid": "apple:310633997:us:14614285121",
  "reviewId": "14614285121",
  "appId": "310633997",
  "appName": "WhatsApp Messenger",
  "bundleId": "net.whatsapp.WhatsApp",
  "developerName": "WhatsApp Inc.",
  "storefront": "us",
  "rating": 2,
  "title": "Keeps crashing after update",
  "body": "Since 26.38 the app closes whenever I open a group chat.",
  "bodyChars": 56,
  "authorName": "appuser2024",
  "appVersion": "26.38.74",
  "isCurrentVersion": true,
  "helpfulVotes": 12,
  "totalVotes": 15,
  "reviewedAt": "2026-10-01T09:50:55.000Z",
  "sentimentHint": "negative",
  "contentHash": "7c1aa3f05be24d19",
  "scrapedAt": "2026-10-02T12:00:00.000Z"
}
```

### Why storefront choice is the whole game

Apple stores reviews **per country**. A US-only run will never show you the German one-star reviews that are tanking your DACH conversion. This Actor takes a **list of countries** and a **list of apps**, so one run covers your whole market footprint instead of one run per app per country.

### What this App Store review scraper does

- 🌍 **Multi-country by design** — pass `["us","gb","de","fr","jp"]` and get every storefront in a single dataset, each row tagged with `storefront`.
- 🔢 **Version-mapped reviews** — `appVersion` plus `isCurrentVersion` means you can answer "did release 26.38 fix the sync complaints?" directly from the data. Join it against `releaseNotes` on the app profile row.
- 🪪 **Four ways to name an app** — numeric App Store ID, bundle ID (`com.whatsapp.WhatsApp`), a full App Store URL, or `name:Duolingo` to resolve the top search match.
- 🎯 **Filters that cut your bill** — `minRating`/`maxRating`, `reviewedAfter` and review **keywords** are applied before anything is written, so filtered reviews are never charged. Set both ratings to `1` to collect only one-star complaints.
- 🧮 **Deterministic sentiment** — `sentimentHint` buckets 1–2 stars as negative, 3 as neutral, 4–5 as positive. Rule-based, so it is reproducible and costs nothing. No LLM, no hidden third-party API fee.
- 🔁 **Built for schedules** — `reviewUid` deduplicates across runs and `contentHash` catches edited reviews, so you can diff two runs to get only what's new.
- 🛟 **Honest failures** — an app that does not exist in a storefront produces an `ok: false` row explaining exactly that, and every other storefront still lands.

Running on Apify adds scheduling, webhooks, monitoring, API and SDK access, and one-click export to JSON, CSV, Excel, Google Sheets and 20+ integrations.

### How to use it

1. Add your apps to **Apps**. Competitor apps work just as well as your own.
2. Add the storefronts to **Country storefronts** — two-letter codes such as `us`, `gb`, `de`, `fr`, `es`, `it`, `br`, `jp`, `kr`, `in`.
3. Set **Max reviews per app**. This is the number that determines your cost.
4. Choose **Most recent** for monitoring, **Most helpful** for the reviews Apple actually shows shoppers.
5. Optionally narrow with star range, **Reviewed after**, or **Review keywords** such as `crash`, `refund`, `login`.
6. Click **Start**, then use the **Reviews**, **Release quality** and **App profiles** dataset tabs.

#### How do I track only new reviews?

Set **Reviewed after** to a relative value like `7 days`, schedule the Actor daily, and deduplicate downstream on `reviewUid`. With **Most recent** sorting the Actor also stops paging once it is past your cutoff, so a daily run is cheap.

### Full example input and output

```json
{
  "apps": ["310633997", "com.spotify.client", "name:Duolingo"],
  "countries": ["us", "gb", "de"],
  "maxReviewsPerApp": 300,
  "maxReviewsPerCountry": 200,
  "sortBy": "mostRecent",
  "includeAppProfile": true,
  "minRating": 1,
  "maxRating": 3,
  "reviewedAfter": "30 days",
  "keywords": ["crash", "subscription"]
}
```

An app profile row from the same run:

```json
{
  "recordType": "app",
  "ok": true,
  "appId": "310633997",
  "appName": "WhatsApp Messenger",
  "developerName": "WhatsApp Inc.",
  "storefront": "us",
  "formattedPrice": "Free",
  "isFree": true,
  "primaryGenre": "Social Networking",
  "genres": ["Social Networking", "Utilities"],
  "averageUserRating": 4.7,
  "userRatingCount": 15324991,
  "averageUserRatingCurrentVersion": 4.6,
  "userRatingCountCurrentVersion": 48211,
  "version": "26.38.74",
  "currentVersionReleaseDate": "2026-09-28T14:02:11Z",
  "releaseNotes": "Bug fixes and performance improvements.",
  "contentAdvisoryRating": "12+",
  "minimumOsVersion": "15.0",
  "screenshotCount": 8,
  "appStoreUrl": "https://apps.apple.com/us/app/whatsapp-messenger/id310633997"
}
```

### Use cases

- **Release triage** — group negative reviews by `appVersion` to find out which build broke what.
- **Competitor intelligence** — scrape rivals' one- and two-star reviews to find the feature gaps their users complain about.
- **Localisation and market priority** — compare `averageUserRating` and complaint themes across storefronts.
- **Voice-of-customer feeds** — pipe `body` into an LLM or a BI tool; the text is already clean.
- **ASO and store-listing research** — pair with the **App Store Search & ASO Keyword Scraper** to see where an app ranks and how users respond to it.
- **Support deflection** — alert on new one-star reviews containing `refund`, `charged` or `cancel`.

### How much does it cost to scrape App Store reviews?

Pricing is **pay per event**:

| Event | What triggers it | Billed |
|---|---|---|
| Review | One review written to the dataset | per review |
| App profile | One app metadata row per app and storefront | per profile row |
| Actor start | Once per run, platform fee | per run |

Reviews removed by your filters are **not** billed, because they are never written. Apps that cannot be resolved are **not** billed either.

A concrete example: 3 apps × 3 countries × 200 reviews = 1,800 review events, plus 9 app profile rows. Multiply by the per-review price and that is your total. Compute, bandwidth and storage are included — there is no separate platform-usage charge on top.

Set **Max cost per run** in the run options for a hard ceiling; the Actor stops cleanly and says so in the log. Higher Apify plans get progressively lower per-review pricing through Apify Store tier discounts.

### Related Actors by Axiora Solutions

| Actor | Use it for |
|---|---|
| **App Store Search & ASO Keyword Scraper** | Keyword rankings, competitor discovery and top-chart positions for the same apps |
| **News & RSS Feed Scraper** | Catch press and release coverage about the apps you monitor |
| **Domain Contact Enricher** | Enrich the developer websites behind the apps into contactable company records |

### Frequently asked questions

#### How many reviews can I actually get per app?

Apple's public customer-reviews feed serves **up to 500 reviews per app per country storefront** — 10 pages of 50. That is a hard platform limit, not a limit of this Actor. The way to get more volume is **more storefronts**, which is exactly why countries is an array. Note that `userRatingCount` on the app profile row is often in the millions; that is the number of *ratings*, while only the most recent or most helpful 500 *written reviews* per storefront are published.

#### Does it scrape Google Play too?

Not in this version. This Actor is Apple-only on purpose: Apple publishes a stable public feed, which is why it is reliable enough to run on a schedule. Google Play has no equivalent public endpoint, so bolting it on here would make the Actor fail unpredictably and would be dishonest about what you are paying for.

#### What personal data does it return?

Only the public nickname the reviewer chose to display on the App Store, plus the review text itself. Apple publishes no real name, no e-mail address and no other identifier, and this Actor does not attempt to resolve one. You are responsible for your lawful basis when processing review text.

#### Why is a review in a language I did not expect?

Because storefront and language are different things. German-storefront reviews are usually German, but Apple does not restrict language. Keep `storefront` on every row and filter downstream.

#### Why did an app return nothing for one country?

Either the app is not published in that storefront, or it has no written reviews there. You will get an `ok: false` row with `NOT_FOUND` in the first case, and simply no review rows in the second. Both are visible in the run summary.

#### Is `sentimentHint` a real sentiment model?

No, and it does not pretend to be. It is a deterministic mapping of the star rating. That makes it free, reproducible and auditable. If you want genuine text sentiment, send `body` to your own model — you will not be paying this Actor for an opaque inference.

#### Can I run this on a schedule?

Yes. Daily with **Reviewed after** set to `2 days` and **Most recent** sorting is the cheap monitoring pattern. Deduplicate on `reviewUid`.

#### Something looks wrong — how do I report it?

Open the **Issues** tab on this Actor page with the app ID, the storefront and what you expected to see.

***

Runnable examples and how-to guides for these Actors: [github.com/batow133/axiora-apify-actors](https://github.com/batow133/axiora-apify-actors)

# Actor input Schema

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

One app per entry. All of these work: a numeric App Store ID (310633997), a full App Store URL, a bundle ID (com.whatsapp.WhatsApp), or name:Search Term to resolve the top match by name.

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

Two-letter App Store country codes. Reviews are stored per storefront, so add every market you care about. Common: us, gb, de, fr, es, it, br, jp, kr, in, ca, au, nl, se, mx.

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

Total review cap for each app across every country. This is the number that controls your bill.

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

Per-storefront cap. Apple publishes at most 500 reviews per app per country through its public feed, so values above 500 have no effect.

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

mostRecent walks the newest reviews first and is what you want for monitoring. mostHelpful returns the reviews Apple surfaces on the store page.

## `includeAppProfile` (type: `boolean`):

Add one row per app and country with name, developer, price, genres, average rating, total rating count, current version, release notes and screenshot URLs.

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

Keep only reviews at or above this many stars. Set to 1 to keep everything.

## `maxRating` (type: `integer`):

Keep only reviews at or below this many stars. Set both to 1 to collect only one-star complaints.

## `reviewedAfter` (type: `string`):

Keep only reviews written on or after this date. Accepts 2026-01-31 or a relative value such as 30 days.

## `keywords` (type: `array`):

Keep only reviews whose title or body contains one of these words, case-insensitive. Useful for tracking a specific feature, bug or competitor mention.

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

Optional. Apple's public review feed normally answers direct requests, so leave this off unless you are collecting very large volumes and start seeing rate limiting.

## Actor input object example

```json
{
  "apps": [
    "310633997",
    "https://apps.apple.com/us/app/spotify/id324684580",
    "com.whatsapp.WhatsApp",
    "name:Duolingo"
  ],
  "countries": [
    "us",
    "gb",
    "de"
  ],
  "maxReviewsPerApp": 200,
  "maxReviewsPerCountry": 500,
  "sortBy": "mostRecent",
  "includeAppProfile": true,
  "minRating": 1,
  "maxRating": 5,
  "reviewedAfter": "30 days",
  "keywords": [
    "crash",
    "subscription",
    "login"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Every review collected, plus one app profile row per app and storefront when that option is on. Filter on recordType to separate them.

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

Per-app review counts, storefronts covered, how many reviews each filter removed, billing and network totals.

# 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.spotify.client"
    ],
    "countries": [
        "us"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiorasolutions/app-review-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.spotify.client",
    ],
    "countries": ["us"],
}

# Run the Actor and wait for it to finish
run = client.actor("axiorasolutions/app-review-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.spotify.client"
  ],
  "countries": [
    "us"
  ]
}' |
apify call axiorasolutions/app-review-scraper --silent --output-dataset

```

## MCP server setup

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