# Apple App Store Scraper (`mlg14/apple-store-scraper`) Actor

Collect public iOS and macOS app reviews by product ID, store URL, or app name. Export ratings, review text, dates, app versions, and helpfulness across country stores.

- **URL**: https://apify.com/mlg14/apple-store-scraper.md
- **Developed by:** [MLG Data](https://apify.com/mlg14) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 80.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.30 / 1,000 results

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

## Apple App Store Scraper

Collect public iOS and macOS app reviews from the Apple App Store by numeric product ID, store listing URL, or app name. Export Apple App Store ratings, review text, dates, versions, and helpfulness as flat records for CSV or JSON workflows; the actor provides a practical App Store reviews API alternative for repeatable collection across country stores.

Each dataset item represents one public review. The actor reads a structured customer review feed, resolves listing details through a public lookup endpoint, and attaches the app and country context to every row. It accepts several app IDs in a run, keeps review IDs unique within each app, and stops at your requested limits. You can collect the newest reviews, source-ranked helpful reviews, or rating-ordered views of the accessible recent window.

### What data can you extract from the Apple App Store?

| Field | Description | Example |
| --- | --- | --- |
| `reviewId` | Public identifier assigned to the review | `14590849716` |
| `rating` | Rating on the one-to-five-star scale | `1` |
| `title` | Review headline in the reviewer's original language | `Localização` |
| `text` | Full public review body | `Não atualiza...` |
| `authorName` | Public reviewer display name | A store display name |
| `authorId` | Public reviewer identifier, when the feed supplies it | Numeric string |
| `reviewDate` | Source timestamp, including its timezone offset | `2026-09-25T01:24:00-07:00` |
| `reviewDateIso` | Timestamp in ISO 8601 form | `2026-09-25T01:24:00-07:00` |
| `reviewedVersion` | App version associated with the review | `9.1.86` |
| `helpfulCount` | Helpful votes reported by the feed | `0` |
| `totalHelpfulCount` | Total votes reported by the feed | `0` |
| `productId` | Numeric store listing ID | `324684580` |
| `appName` | Name returned by the current store listing | Listing name |
| `appUrl` | Public store listing URL | A country-specific listing URL |
| `appPlatform` | Platform inferred from the listing | `ios` or `macos` |
| `country` | Two-letter storefront code used for the request | `us` |
| `sortOrder` | Order requested in the input | `mostrecent` |
| `sourceSort` | Order actually requested from the feed | `mostrecent` |
| `pageNumber` | One-based feed page where the review appeared | `1` |
| `fetchedAt` | UTC timestamp for this collection run | ISO 8601 timestamp |

The review body and title are returned as written by the reviewer. Country selection chooses a storefront; it does not translate text or force every review to use that country's primary language. A US-store result can contain a review written in another language. Dates are timestamp strings with source offsets, so consumers can convert them to a preferred timezone without guessing the calendar day. The two date columns currently contain the same source timestamp because the feed already uses ISO 8601.

### How to scrape Apple App Store reviews

1. Copy a numeric app ID from a public listing URL, paste one or more listing URLs into `productIds`, or enter a name in `appName`.
2. Choose the two-letter `country` store and the desired review order. Add `ratings` if you only need selected star levels.
3. Set `maxReviewsPerApp` and, when collecting several apps, `maxItems` to control the dataset size.
4. Run the actor and open its dataset. Download JSON, CSV, or Excel from the dataset export controls, or read the dataset URL in an automated workflow.

Use a numeric ID when exact app identity matters. A name search chooses the top software result in the selected country store, which can be a similarly named app. Listing URLs are accepted as a convenience: the actor extracts the numeric ID from the `/id...` segment. If both `productIds` and `appName` are supplied, the IDs take precedence.

### Input

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `productIds` | string array | empty | Numeric IDs or public listing URLs, processed in order. |
| `appName` | string | empty | Search term used when no product IDs are supplied. |
| `country` | string | `us` | Two-letter storefront code such as `us`, `gb`, `de`, `jp`, or `tr`. |
| `sort` | string | `mostrecent` | `mostrecent`, `mosthelpful`, `mostcritical`, or `mostfavorable`. |
| `ratings` | integer array | empty | Keep only reviews with these star ratings, from one through five. |
| `maxReviewsPerApp` | integer | `100` | Output cap per app; zero means all accessible matching reviews. |
| `startPage` | integer | `1` | Start at feed page 1 through 10, useful for resuming a collection. |
| `maxItems` | integer | `0` | Overall output cap across apps; zero means no extra cap. |
| `proxyConfiguration` | object | platform proxy | Override the default proxy configuration if needed. |

A realistic input for monitoring recent low-star feedback is:

```json
{
  "productIds": ["324684580"],
  "country": "us",
  "sort": "mostrecent",
  "ratings": [1, 2],
  "maxReviewsPerApp": 100,
  "maxItems": 100
}
```

That input scans recent pages until it finds 100 matching one- and two-star reviews or reaches the feed's page limit. It does not promise the latest 100 reviews from the app's complete history. On a busy app, a 100-review result can span only a short time period; on a quieter app, the same result can span much longer. When comparing successive runs, use `reviewId` as a stable deduplication key together with `productId` and `country`.

### Output example

The following selected fields came from one review in the 60-item golden run. Display names and listing names are omitted from this shortened example; the complete dataset includes the fields documented above.

```json
{
  "reviewId": "14590849716",
  "rating": 1,
  "title": "Localização",
  "text": "Não atualiza automaticamente a localização quando mudamos de país",
  "reviewDate": "2026-09-25T01:24:00-07:00",
  "reviewDateIso": "2026-09-25T01:24:00-07:00",
  "reviewedVersion": "9.1.86",
  "helpfulCount": 0,
  "totalHelpfulCount": 0,
  "productId": "324684580",
  "appPlatform": "ios",
  "country": "us",
  "sortOrder": "mostrecent",
  "sourceSort": "mostrecent",
  "pageNumber": 1
}
```

The golden input requested 60 US-store reviews from one public app ID. The run succeeded with 60 rows, and every row had a review ID, rating, title, body, public display name, date, app ID, app name, platform, and country. Those measurements validate this example; they do not guarantee identical fill rates for every app or storefront.

### Use cases

- **Release monitoring:** Collect recent reviews on a schedule, group them by `reviewedVersion`, and watch for recurring complaints after a new release.
- **Support triage:** Filter one- and two-star reviews, inspect the original text, and route issues into a support queue with the review ID as a reference.
- **Localization checks:** Run the same product ID for several country stores and compare what reviewers report by region. Keep each country's rows separate because store availability and review visibility can differ.
- **Product research:** Compare rating distributions and recurring themes across several public listings without copying reviews by hand.
- **App quality reporting:** Track review volume, low-star share, and version-specific feedback over time by storing each scheduled run and deduplicating IDs.
- **Helpful-feedback review:** Use `mosthelpful` to inspect the source's helpfulness-ranked window, then examine the numeric vote fields beside the original text.

For trend reports, preserve the raw review row before adding your own categories or labels. A source review can be edited or its visible vote counts can change. Keeping `fetchedAt` and `reviewDate` separate lets you tell when you collected the review and when the feed says it was updated.

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

The configured result price is **$0.30 per 1,000 dataset items**, or $0.0003 per delivered review. A 60-review collection is about $0.018, 500 reviews are about $0.15, and 2,000 reviews across several app and country runs are about $0.60 in result charges. These examples are simple item-count calculations, not estimates of how many reviews a specific app will make available. Check the run's usage details for its actual charge.

Set `maxItems` when you need a firm total result count across many apps. `maxReviewsPerApp` limits each listing independently; for example, three app IDs with a per-app cap of 100 can produce at most 300 rows before the overall cap applies. If the platform budget limit is reached, already delivered rows remain in the dataset and collection stops at the next push.

A feed page can contain 50 reviews, but a rating filter may discard most of them. Result charges follow delivered dataset items. The number of source pages examined still affects elapsed run time, so a very narrow rating filter can be slower than collecting all ratings from the same app.

### Tips for best results

Start with `mostrecent` and a known product ID for reliable, repeatable monitoring. The name lookup is useful for exploratory collection, but verify the returned `productId` and `appName` before treating its rows as belonging to the intended listing. A store URL gives the same precision as the numeric ID when its `/id...` part is intact.

Choose a country store deliberately. The same numeric app can have different availability, review counts, and visible feedback in different storefronts. Run separate inputs for countries you want to compare and use `country` in your downstream key. Do not merge review IDs across countries without retaining storefront context.

For small recurring pulls, set a modest `maxReviewsPerApp` and retain the highest review ID or review date from the prior run. The feed does not provide an incremental cursor. A scheduled workflow can collect a recent overlap and deduplicate against stored IDs. If you need to resume a one-time extraction, use `startPage`, bearing in mind that new reviews can shift page boundaries between runs.

For critical or favorable views, the actor gathers the available recent pages and sorts those collected rows by rating. Inspect `sourceSort`: it will read `mostrecent` for those views. This distinction matters when a large app has many older low-star reviews outside the accessible recent window. Use `ratings: [1, 2]` with `mostrecent` if you want low-star reviews in source recency order.

If you request several app IDs, they are handled sequentially. The overall `maxItems` cap can be reached before later IDs are processed, so give each app its own run when balanced coverage matters. Duplicate IDs within one input are removed before lookup. The actor reports an error when no requested app produces any reviews, which helps surface a wrong ID or unavailable country store.

### Limits

The public review feed rejects page 11 and higher. Each accepted page supplies up to 50 entries, so a single app and country can expose at most about 500 reviews through this route in one sort order. The real count may be lower because an app has fewer reviews, a page is sparse, IDs repeat, or a rating filter removes entries. The actor caps `startPage` at 10 and stops when a page is empty or shorter than 50 entries.

The feed supports recent and helpful ordering. Its favorable and critical order URLs did not return usable data during source checks, so these options sort the accessible recent window locally. They are windowed views, not a complete all-time ranking. The actor records both the requested `sortOrder` and the actual `sourceSort` to make that limitation visible per row.

The public feed does not supply developer reply text, review language codes, a direct permanent URL for each individual review, or a guarantee that all historical reviews remain accessible. It does supply public reviewer names and numeric identifiers in many entries. Some review or vote fields may be absent for a particular entry; keep nulls distinct from numeric zero. App names and listing URLs come from the lookup response at collection time, so they can reflect the current listing rather than the version visible when the review was written.

The app name search chooses the first software result. Search ranking can change, and some apps are not available in every country store. A supplied ID that has no matching listing in the chosen store is skipped with a run log warning. The actor uses the public store feed; access and response shapes are controlled by the source and may change.

### Use with automated clients

A client that can start an actor and read its dataset can request reviews with the same input fields shown above. Two practical requests are: “Collect the 50 newest reviews for product ID 324684580 in the US store” and “Collect low-star reviews for this store URL and return their titles, versions, and dates.” The input schema describes each parameter so an MCP-enabled client can set the country, order, and caps without relying on hidden defaults.

Store numeric IDs in recurring tasks. For a one-time investigation, `appName` is convenient, but a name search should be checked against the returned listing details before a report is sent. The dataset is flat JSON, which makes it straightforward to map records to a database table, spreadsheet, or webhook payload. Use `reviewId`, `productId`, and `country` together when inserting rows into a long-lived review store.

### FAQ

#### Is it legal to collect these reviews?

The actor reads publicly visible review data. Your use of that data must follow applicable terms, privacy rules, and laws. Avoid republishing reviewer identifiers unnecessarily or using public feedback for personal-data misuse. If you need legal advice for a particular workflow, consult a qualified professional.

#### Do I need to configure a proxy?

The default input uses the platform proxy configuration. Most users can leave it alone. The source checks and golden run succeeded through that configuration without a browser challenge. If a storefront temporarily rejects requests, retry later or adjust the proxy setting for your account.

#### How fast is a run?

The 60-row golden run completed successfully after fetching a listing lookup and two review pages. Runtime varies with page count, source response speed, retry behavior, and the number of app IDs. A narrow rating filter can require more pages than an all-rating request for the same delivered count.

#### Can I schedule review monitoring?

Yes. Save the input for an app and country as a task, attach a schedule, and store each dataset for comparison. Collect a small overlap because newly posted reviews can move older reviews to later pages. Deduplicate by review ID with app and country context.

#### Can I export to a spreadsheet?

Yes. The dataset can be downloaded as CSV or Excel, or read as JSON by an integration. All output fields are flat, so each review maps to one spreadsheet row. Keep the source timestamp column as text or parse it with timezone awareness.

#### Why is a field empty?

The source may omit it for that review or listing. For example, a version or vote count can be unavailable. Empty output should be interpreted as missing source data rather than a guessed value. The golden run's core text and identity fields were complete for its tested app, but other apps can differ.

#### Why does “most critical” miss an old one-star review?

That view sorts only the recent reviews reachable through up to 10 feed pages. It cannot search the app's complete review history. Check `sourceSort` and `pageNumber` to see the source scope, or use recent low-star filtering when current complaints are the goal.

### Integrations

The actor's default dataset can be consumed through an API, scheduled tasks, webhooks, spreadsheet exports, and workflow connectors. A common pattern is to run one task per app and country, send the dataset URL to a downstream job, and upsert rows by review ID plus app and country. Another is to export a CSV after a one-time competitor study. Keep the raw dataset and collection timestamp so later summaries can be audited against the source rows.

### Support

Open an issue on the Issues tab; we reply within 24h and add fields on request.

# Actor input Schema

## `productIds` (type: `array`):

Numeric product IDs or public store URLs. Multiple apps are collected in order. If empty, appName is used.

## `appName` (type: `string`):

Search a public app name and use the top matching software listing when productIds is empty.

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

Two-letter country store code, such as us, gb, de, jp, or tr.

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

Recent and helpful are source orders. Critical and favorable sort the accessible recent window by rating.

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

Optional star ratings to keep, from 1 to 5. Empty includes all ratings.

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

Maximum matching reviews per app. 0 collects the accessible window, up to the 500 most recent or helpful reviews.

## `startPage` (type: `integer`):

First one-based page of 50 reviews to fetch (page 2 starts at review 51).

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

Total output limit across all apps. 0 means no additional cap.

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

Proxy configuration for public store requests. The default uses the platform proxy.

## Actor input object example

```json
{
  "productIds": [
    "324684580"
  ],
  "country": "us",
  "sort": "mostrecent",
  "ratings": [],
  "maxReviewsPerApp": 100,
  "startPage": 1,
  "maxItems": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Collected review rows in the default dataset.

# 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 = {
    "productIds": [
        "324684580"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mlg14/apple-store-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 = { "productIds": ["324684580"] }

# Run the Actor and wait for it to finish
run = client.actor("mlg14/apple-store-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 '{
  "productIds": [
    "324684580"
  ]
}' |
apify call mlg14/apple-store-scraper --silent --output-dataset

```

## MCP server setup

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