# App Store Reviews Scraper - iOS App Reviews API (`glasswing/app-store-reviews-scraper`) Actor

Scrape public Apple App Store reviews by app ID or link: stars, title, text, date, app version and helpful votes. Sort by recent or helpful, any country. No reviewer names. JSON, CSV, Excel.

- **URL**: https://apify.com/glasswing/app-store-reviews-scraper.md
- **Developed by:** [Raffy](https://apify.com/glasswing) (community)
- **Categories:** Developer tools, Automation, SEO tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.53 / 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

### What does App Store Reviews Scraper do?

App Store Reviews Scraper reads the **public customer reviews of any iPhone, iPad or Mac app** in the Apple App Store and delivers them as clean JSON, CSV or Excel: star rating, review title and text, date, app version and helpful votes. Give it an app ID such as `389801252` or an App Store link, pick how many reviews you want, and get one row per review in seconds. No Apple account, no API key, no browser.

Typical use cases:

- **Review monitoring:** schedule a daily run sorted by most recent and de-duplicate on `reviewId` to see only new reviews of your app or a competitor's.
- **Sentiment and topic analysis:** export up to 500 reviews per app and country and feed them to your own text analysis.
- **Release tracking:** `version` ties every review to the app version it was written for, so you can see whether a release made things better or worse.

It does **not** log in, solve challenges or collect reviewer names or profiles.

#### Result status (tri-state output)

| `status` | Meaning | Billed? |
|---|---|---|
| `ok` | A review was found and extracted. | Yes |
| `not_found` | Apple has no such app, or the app has no written reviews in that country. If Apple's feed answers an empty first page, the Actor asks again up to 3 times (after 3, 8 and 15 seconds) before it writes the free `not_found` row. If the app has ratings but Apple's feed still returns no reviews, the row is a free `error` instead (see below). | No |
| `error` | Apple's reviews feed could not be read after retries (network error, block, or format change). `error` says why. | No |

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

| Field | Description |
|---|---|
| `appId` | Apple's numeric app ID (the number in the App Store link). |
| `name` | The app's name. |
| `rating` | Stars given by the reviewer, 1 to 5. |
| `title` | The review headline. |
| `text` | The review text. |
| `reviewDate` | When the review was written or last edited (ISO 8601). |
| `version` | App version the review was written for. |
| `helpfulVotes` | Net helpful votes. `totalVotes` is the number of people who voted. |
| `reviewId` | Apple's id of the review, handy for de-duplication. |
| `reviewPosition`, `reviewSort` | Position of the review in the chosen order and the order used. |
| `country` | The App Store country of the run. |
| `appStoreUrl`, `url` | Link to the app page and to its reviews. |
| `status`, `error`, `scrapedAt` | Tri-state status, the reason for non-ok rows, and the extraction time. |

Apple's public reviews feed does not include the developer's reply, so rows have no reply field.

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

1. Open the Actor in Apify Console and click **Try for free**.
2. Paste one or more app IDs or App Store links into **App IDs or App Store URLs**.
3. Set **Max reviews per app** (start with the default 20 to see the output), and optionally sort order and country.
4. Click **Start**. The default input finishes in well under a minute.
5. Open the **Output** tab or **Export** the dataset as JSON, CSV, Excel, XML or HTML.

To automate it, use the **API** tab (Node.js, Python, curl examples) or add a **Schedule**.

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

This Actor uses **pay-per-event** pricing. The per-review price falls with your Apify plan:

| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| Actor start | $0.005 | $0.005 | $0.0045 | $0.004 |
| Review (`status: ok` row) | $0.000862 | $0.00075 | $0.000638 | $0.000525 |

Example: 1,000 reviews cost about $0.87 on the Free plan ($0.862 per 1,000 reviews, plus the start fee). Rows with `status` `not_found` or `error` are never billed. You can cap spending per run with **Max reviews per app**, **Maximum reviews in total** and the run's **Max total charge** option.

### Input

| Field | What it does |
|---|---|
| `appIds` | App IDs, App Store links or bundle IDs, one per line. |
| `maxReviewsPerApp` | Reviews to read per app, 1 to 500 (default 20). |
| `sort` | `mostRecent` (default) or `mostHelpful`. |
| `country` | App Store country code, e.g. `us`, `gb`, `de` (default `us`). |
| `maxItems` | Hard cap on rows in the whole run (default 100,000). |
| `proxyConfiguration` | On the Apify platform the Actor always uses Apify Proxy (datacenter), because Apple's feed answers some direct cloud IPs with an empty page. |

Example input:

```json
{
    "appIds": ["https://apps.apple.com/us/app/instagram/id389801252"],
    "maxReviewsPerApp": 20,
    "sort": "mostRecent",
    "country": "us"
}
```

### Output

A real row from a run (shortened):

```json
{
    "status": "ok",
    "appId": 389801252,
    "name": "Instagram",
    "country": "us",
    "reviewId": "14735122794",
    "rating": 1,
    "title": "Inconsistent error-filled experience",
    "text": "Features are limited to specific versions of the app. Can only do mixed size reels on iPad. Can only do multiple caption reels on iPhone. ...",
    "version": "453.0",
    "reviewDate": "2026-10-31T20:37:30.000Z",
    "helpfulVotes": 0,
    "totalVotes": 0,
    "reviewSort": "mostRecent",
    "reviewPosition": 1,
    "url": "https://apps.apple.com/us/app/id389801252?see-all=reviews",
    "scrapedAt": "2026-11-02T06:09:59.934Z"
}
```

### Tips

- Put all your apps in **one run**: you pay the start fee once.
- For monitoring, schedule a daily run with sort `mostRecent` and de-duplicate on `reviewId`.
- Reviews are per country: use `country` = `de` for the German store. Each run covers one country.

### Limitations

- **No reviewer identity.** Rows never include the reviewer's name or profile. E-mail addresses and phone numbers that reviewers write into a title or text are replaced with `[email]` and `[phone]`; role mailboxes such as support@ stay.
- Apple's public feed holds the latest **500 reviews** per app and country. Older reviews are not available from it.
- No star-rating filter: Apple's feed cannot filter by stars, so filter the exported rows on `rating`.
- No developer replies: they are not part of Apple's public feed.
- Apple changes its feed now and then; when it does, rows come back as `error` (never as silently wrong data) and the Actor is updated; report it in the **Issues** tab.

### FAQ

#### Do I need an Apple account or an API key?

No. The Actor reads Apple's public customer-reviews feed, which needs no key and no login.

#### Is it legal to scrape App Store reviews?

The Actor reads only public data and collects no reviewer names or contact details. Review text is written by the public and can itself mention people; handle it accordingly. See the legal notice below.

#### Can I use this Actor from an AI agent or MCP client?

Yes. Called with no arguments it returns 20 reviews of a well-known app; every input is a plain string or list and every row explains itself with `status` and `error`.

#### Why is an app `not_found`?

The ID does not exist, or the app has no ratings at all in that country. `not_found` rows are free.

#### Why did I get an `error` row saying Apple's reviews feed returned no reviews?

The app has ratings, but Apple's reviews feed answered empty even after retries. This is a temporary Apple feed issue, not a property of the app. The row is free; run again later.

#### Why did I get fewer rows than `maxReviewsPerApp`?

The app has fewer written reviews in that country than you asked for, or more than 500 were requested (Apple's limit).

### Legal and data-protection notice

This Actor reads only data that Apple publishes publicly in its App Store customer-reviews feed: the public text of app reviews. It does not extract reviewer names or profiles, e-mail addresses, phone numbers or other contact data, and it does not log in or get around any access control. Review text is written by the public and can itself mention people or contact details. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you are unsure whether your reason is legitimate, consult your lawyers. You are responsible for complying with Apple's terms and applicable law when using the extracted data.

This Actor is an independent tool and is not affiliated with, endorsed by or sponsored by Apple Inc. App Store is a service mark of Apple Inc. All trademarks belong to their respective owners.

# Changelog

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

# Actor input Schema

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

Apps to read reviews for, one per line: numeric app IDs (389801252 or id389801252), App Store links (https://apps.apple.com/us/app/instagram/id389801252) or bundle IDs (com.spotify.client). An app that does not exist, or has no written reviews, gives one free `not_found` row.

## `startUrls` (type: `array`):

Hidden alias of App IDs for API callers that use this name. Same format. Used only when App IDs is empty or still the built-in example.

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

How many reviews to read per app. Apple's public feed holds the latest 500 reviews per app and country, so 500 is the maximum. Each review row with status `ok` is one billable result.

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

Most recent first (best for monitoring) or most helpful first (Apple's ranking by helpful votes).

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

App Store country as a two-letter code: `us`, `gb`, `de`, `jp`, `br`. Reviews are per storefront. Default `us`.

## `maxItems` (type: `integer`):

Hard cap on rows saved in the whole run, across all apps. Leave the default unless you want a lower overall limit.

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

Optional. On the Apify platform the Actor always uses Apify Proxy (datacenter), because Apple's reviews feed answers some direct cloud IPs with an empty page. Residential proxies are not needed.

## Actor input object example

```json
{
  "appIds": [
    "https://apps.apple.com/us/app/instagram/id389801252"
  ],
  "startUrls": [
    "https://apps.apple.com/us/app/instagram/id389801252"
  ],
  "maxReviewsPerApp": 20,
  "sort": "mostRecent",
  "country": "us",
  "maxItems": 100000,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (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": [
        "https://apps.apple.com/us/app/instagram/id389801252"
    ],
    "startUrls": [
        "https://apps.apple.com/us/app/instagram/id389801252"
    ],
    "maxReviewsPerApp": 20,
    "country": "us",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("glasswing/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": ["https://apps.apple.com/us/app/instagram/id389801252"],
    "startUrls": ["https://apps.apple.com/us/app/instagram/id389801252"],
    "maxReviewsPerApp": 20,
    "country": "us",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("glasswing/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": [
    "https://apps.apple.com/us/app/instagram/id389801252"
  ],
  "startUrls": [
    "https://apps.apple.com/us/app/instagram/id389801252"
  ],
  "maxReviewsPerApp": 20,
  "country": "us",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call glasswing/app-store-reviews-scraper --silent --output-dataset

```

## MCP server setup

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