# App Store Reviews Scraper (`rastriq/app-store-reviews-scraper`) Actor

Reviews of any Apple App Store app by country: rating, title, text, version, date, helpful votes. Up to 500 per country. Author data hashed, emails and phones redacted.

- **URL**: https://apify.com/rastriq/app-store-reviews-scraper.md
- **Developed by:** [Rastriq — Structured data from the world](https://apify.com/rastriq) (community)
- **Features:** Limited permissions
- **Stats:** 2 total users, 0 monthly users, 77.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.08 / 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 Reviews Scraper

**App Store Reviews Scraper** extracts customer reviews from any Apple App Store app, country by country: star rating, title, review text, app version, publication date and helpful votes. Give it app ids or App Store URLs and get clean, deduplicated JSON, CSV or Excel. It is the fastest way to scrape App Store reviews for sentiment analysis, competitor tracking, product feedback and ASO research, with no Apple account and no login.

Author names are included and can be hidden with one switch for GDPR (`hideAuthorNames`). A keyed `author_hash` is always output; avatars, profile URLs and raw author ids never are. Emails and phone numbers typed into a review are redacted.

### What is App Store Reviews Scraper?

App Store Reviews Scraper reads the public customer reviews feed that Apple publishes for every app and storefront, and turns it into a flat, consistent dataset. Run it once for a snapshot, or schedule it daily with `sort = recent` and `dateFrom` to get only new reviews. It is built for product teams, analysts and agencies who need an App Store reviews API without maintaining a scraper.

It shares one output contract with [Google Play Reviews Scraper](https://apify.com/rastriq/google-play-reviews-scraper), so you can ingest both stores with a single integration.

### Important limits of the App Store feed

Please read this before you plan a large job. These limits come from Apple's feed, not from the Actor:

- **Maximum 10 pages x 50 = 500 reviews per country and per sort order.** Apple does not serve anything beyond page 10. To collect more, add more countries to `countries`: every storefront has its own 500.
- **Order.** `recent` returns the newest reviews first (feed order `mostrecent`); `helpful` returns the most helpful first (`mosthelpful`). Each order is its own window of up to 500 reviews.
- **No developer replies.** The App Store feed does not expose responses from the developer, so `developer_reply` and `developer_reply_at` are always `null`.
- **No review language.** The feed does not say which language a review is written in, so `lang` is always `null`. The country is the storefront you asked for.

When the Actor reaches the limit, the run summary says `page_limit`, so you always know why it stopped.

### What data does App Store Reviews Scraper extract?

| Field | What it is |
|---|---|
| ⭐ `rating` | Stars, 1 to 5 |
| 📝 `title`, `text` | Review title and body (emails and phones redacted) |
| 🕒 `published_at` | Publication time, ISO 8601, UTC |
| 📱 `app_version` | App version the review refers to |
| 👍 `helpful_count`, `ext_vote_count` | Helpful votes and total votes |
| 🌍 `country` | Storefront country, lowercase ISO 3166 alpha-2 |
| 🏷️ `app_id`, `app_name` | Numeric App Store id and app name |
| 🔑 `review_id` | Durable review id, used to deduplicate |
| 👤 `author_name` | Author display name. `null` if you enable *Hide author names* |
| 🔒 `author_hash` | Keyed HMAC-SHA256 pseudonym of the author id. Stable across runs while the salt is unchanged |
| 🔗 `source_url`, `scraped_at` | RSS feed page the review came from (for traceability), and extraction time (UTC) |
| 🍎 `ext_app_url` | Public App Store page of the app, `https://apps.apple.com/{country}/app/id{app_id}`, openable in a browser |
| 🚩 `_quality_*` | Flags for missing text, rating or date. Flagged, never filtered |

Fields the source does not provide are `null`, never invented.

### How to scrape App Store reviews with App Store Reviews Scraper

1. Open **App Store Reviews Scraper** on Apify and click **Try for free**.
2. In **Apps**, paste numeric ids such as `284882215`, or full URLs such as `https://apps.apple.com/es/app/facebook/id284882215`.
3. In **Countries**, pick one or more App Store countries (Spain, United States, Germany...). If you leave it empty the Actor uses the country in the URL, or the United States.
4. Set **Max reviews per app and country** (up to 500 per country in practice) and choose **Sort**.
5. Optionally set **Reviews since** to keep only reviews from that date on. With `recent`, the run stops as soon as it meets older reviews.
6. Click **Start**, then download the dataset as JSON, CSV, Excel or XML, or read it through the API.

#### Input parameters

| Parameter | Type | Description |
|---|---|---|
| `appIds` | array, required | App Store ids or URLs |
| `countries` | array | Storefront country codes |
| `maxReviews` | integer | Max per app x country. If empty, 100 |
| `sort` | `recent` or `helpful` | If empty, `recent` |
| `dateFrom` | date `YYYY-MM-DD` | Only reviews published on or after this date (UTC) |
| `hideAuthorNames` | boolean | If on, `author_name` is `null` in every row (GDPR). Default off |

#### Example input

```json
{
  "appIds": ["284882215"],
  "countries": ["es", "us"],
  "maxReviews": 200,
  "sort": "recent",
  "dateFrom": "2026-10-01"
}
```

### Output example

```json
{
  "review_id": "14764815021",
  "store": "app_store",
  "app_id": "284882215",
  "app_name": "Facebook",
  "country": "es",
  "lang": null,
  "rating": 5,
  "title": "Great app",
  "text": "Works well after the last update.",
  "author_hash": "3f1c0c5a0a6d6b7e9d2b8f4c1a7e5d3b9c0f2a6e8d4b1c7a5e3f9d0b2c4a6e81",
  "author_name": "Jane Example",
  "app_version": "586.0.0",
  "published_at": "2026-11-08T07:13:50Z",
  "developer_reply": null,
  "developer_reply_at": null,
  "helpful_count": 0,
  "source_url": "https://itunes.apple.com/es/rss/customerreviews/page=1/id=284882215/sortby=mostrecent/json",
  "scraped_at": "2026-11-09T10:00:00Z",
  "ext_vote_count": 0,
  "ext_app_url": "https://apps.apple.com/es/app/id284882215",
  "ext_pii_redactions": 0,
  "ext_sort": "recent",
  "ext_author_hash_weak": false,
  "_quality_missing_text": false,
  "_quality_missing_rating": false,
  "_quality_missing_published_at": false,
  "_quality_missing_app_name": false,
  "_quality_bad_number": false,
  "_quality_pii_redacted": false
}
```

Every run also writes a `SUMMARY` record with, for each app and country: reviews scanned, emitted and dropped (duplicates, before `dateFrom`, invalid), pages read and the reason it stopped.

### How much does it cost to use App Store Reviews Scraper?

App Store Reviews Scraper uses pay-per-event pricing: you pay per review delivered. A typical job of 500 reviews for one app and country costs a fraction of a cent in compute, plus the per-review price shown on the Actor page. Start with 10 reviews to see the exact bill before you scale, and set a maximum charge per run in the Apify Console to cap spending.

### Privacy & GDPR

- **Author name.** `author_name` is the display name published with the review. If you want to minimise personal data, switch on **Hide author names** (`hideAuthorNames`): every row then has `author_name = null`.
- **Author hash.** `author_hash` is a keyed pseudonym: HMAC-SHA256 of the author id, computed with the secret `AUTHOR_HASH_SALT` of the Actor. It is stable across runs (as long as the salt does not change), so you can count repeat reviewers, but it is pseudonymisation, not anonymisation: whoever holds the salt can recompute it, and if no salt is set the Actor flags every row with `ext_author_hash_weak = true`.
- **Never output.** Avatars, profile URLs and raw author ids are never output, in either mode. Emails and phone numbers written inside the review text are redacted (`[email]`, `[phone]`).
- **Your responsibility.** Review text is free text and may contain personal information. You remain responsible for your lawful basis, retention and use of the data under GDPR and the store's terms.

App Store Reviews Scraper only collects review data that Apple publishes in its public feed.

### FAQ

**Can App Store Reviews Scraper get more than 500 reviews for an app?**
Not for one country: Apple stops at page 10. Add more countries, or schedule recurring runs with `sort = recent` and `dateFrom` and keep the history on your side; `review_id` makes deduplication trivial.

**Does App Store Reviews Scraper return developer replies or the review language?**
No. The App Store feed does not include them, so those fields are `null`. For developer replies use [Google Play Reviews Scraper](https://apify.com/rastriq/google-play-reviews-scraper).

**What happens if Apple blocks a request?**
The Actor retries with backoff and then switches to an Apify datacenter proxy. If one app or country keeps failing, the others still run. The run always ends cleanly with a `SUMMARY` record: `completed`, `no_results`, `partial` (some groups failed) or `failed` (all of them), with a `stopped_reason` per app and country.

**How do I get only new reviews each day?**
Schedule the Actor with `sort = recent` and `dateFrom` set to yesterday.

### Related Actors

- [Google Play Reviews Scraper](https://apify.com/rastriq/google-play-reviews-scraper): same output contract for Android apps, with developer replies.

# Changelog

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

# Actor input Schema

## `appIds` (type: `array`):

App Store URLs (<code>https://apps.apple.com/us/app/facebook/id284882215</code>) or numeric app ids (<code>284882215</code>). Add one app per line. Tip: the id is the number after <code>id</code> in the app's URL.

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

App Store countries to read reviews from. Each country has its own reviews, <b>up to 500 per app</b>, so add more countries to get more reviews. Leave empty to use the country in the app URL, or the United States.

## `maxReviews` (type: `integer`):

Stop after this many reviews for each app in each country. Apple serves at most <b>500 per country</b> (and per sort order). Leave empty for 100.

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

Order in which Apple returns the reviews. Leave empty for <b>Most recent first</b>.

## `dateFrom` (type: `string`):

Only reviews published on or after this date (UTC). Leave empty for all. With <b>Most recent first</b> the run stops as soon as it reaches older reviews, which makes scheduled daily runs fast and cheap.

## `hideAuthorNames` (type: `boolean`):

Output <code>author_name</code> as null in every row to minimise personal data under GDPR. The hashed <code>author_hash</code> is kept, so you can still group reviews by author.

## Actor input object example

```json
{
  "appIds": [
    "284882215"
  ],
  "countries": [
    "es"
  ],
  "maxReviews": 10,
  "sort": "recent"
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "appIds": [
        "284882215"
    ],
    "countries": [
        "es"
    ],
    "maxReviews": 10,
    "sort": "recent"
};

// Run the Actor and wait for it to finish
const run = await client.actor("rastriq/app-store-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 = {
    "appIds": ["284882215"],
    "countries": ["es"],
    "maxReviews": 10,
    "sort": "recent",
}

# Run the Actor and wait for it to finish
run = client.actor("rastriq/app-store-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 '{
  "appIds": [
    "284882215"
  ],
  "countries": [
    "es"
  ],
  "maxReviews": 10,
  "sort": "recent"
}' |
apify call rastriq/app-store-reviews-scraper --silent --output-dataset

```

## MCP server setup

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