# App Store Reviews Scraper (`axiomworks/review-firehose`) Actor

Scrape Apple App Store reviews by app ID or App Store URL for any country storefront, up to 10,000 per run: rating, title, text, author and date, newest or most helpful first. Delta mode returns only reviews not returned before, so scheduled runs get just what is new.

- **URL**: https://apify.com/axiomworks/review-firehose.md
- **Developed by:** [Kyle Adkins](https://apify.com/axiomworks) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.06 / 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.
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

### What does App Store Reviews Scraper do?

App Store Reviews Scraper collects customer reviews for any app on the Apple App Store, from any country storefront, and returns one record per review with the rating, title, text, author and timestamp, plus the app version and helpful votes for recent reviews when Apple provides them. It reaches the app's full review history, up to 10,000 reviews per run, newest first or most helpful first. Its main feature is **delta mode**: switch it on and each run returns only the reviews that were not returned by earlier runs, so a scheduled run gives you just what is new.

It is built for product and support teams tracking feedback on their own app, marketers and analysts comparing competitors, and developers who need a simple review feed for Slack, a spreadsheet, a database or a sentiment model. It reads the same public review data the App Store website shows, so there is no login and no API key. Runs are HTTP-only and light and usually finish in seconds.

### What data can you get?

Each item is one written review. The `reviewId` is stable across runs, so you can use it as a primary key.

| Field | Description | Example |
|---|---|---|
| `reviewId` | Apple review identifier, stable across runs | `14603402613` |
| `id` | Same as `reviewId`; a stable unique key | `14603402613` |
| `appId` | Numeric App Store app ID | `310633997` |
| `country` | Two-letter storefront country code | `us` |
| `sourceUrl` | App Store reviews page for the app and storefront | `https://apps.apple.com/us/app/id310633997?see-all=reviews` |
| `author` | Review author display name | `Stve82v` |
| `rating` | Star rating from 1 to 5 | `5` |
| `title` | Headline of the review | `WhatsApp` |
| `text` | Full body of the review | `I need to update my chat` |
| `version` | App version the review was written for (recent reviews only, when Apple's older feed returns it; often `null`) | `26.37.76` |
| `voteCount` | Users who voted on whether the review was helpful (recent reviews; otherwise `null`) | `0` |
| `voteSum` | Net helpful votes (recent reviews; otherwise `null`) | `0` |
| `isEdited` | `true` if the author edited the review after posting | `false` |
| `updated` | ISO 8601 timestamp of when the review was posted or last edited | `2026-09-28T13:34:56Z` |

The dataset has three views in the Console: **Reviews** (date, rating, title, text, author and version), **Feedback** (a compact table of rating, version, title and text, handy for sentiment analysis) and **Full** (every field).

### How to use App Store Reviews Scraper

1. Open the Actor in Apify Console and go to the **Input** tab.
2. Enter the **App Store app ID** or paste the app's App Store URL. The ID is the number after `id` in the URL, for example `310633997` in `https://apps.apple.com/us/app/whatsapp-messenger/id310633997`.
3. Choose the **Store country** (`us`, `gb`, `de`, `jp` and so on) and how many reviews you want.
4. Pick a mode. `full` returns reviews newest first (or most helpful first) every time. `delta` returns only reviews not seen in earlier runs.
5. Click **Start**. When the run finishes, open the **Output** tab and export the dataset as JSON, CSV, Excel, XML or HTML, or read it through the API.
6. To track an app over time, save the input as a task and add a schedule, with the mode set to `delta`.

### Input

`appId` is required: a numeric App Store ID or an App Store URL. If it is missing or has no ID in it, the run fails immediately with a clear message.

| Field | Type | Default / prefill | Description |
|---|---|---|---|
| `appId` | string | prefill `310633997` | Numeric App Store app ID, or the app's App Store URL. App names such as 'Spotify' are not accepted. |
| `country` | string | `us` | Two-letter lowercase country code of the App Store storefront, for example `us`, `gb` (United Kingdom, not `uk`), `de`, `jp`. |
| `mode` | string | `full` | `full` returns the most recent reviews on every run. `delta` returns only reviews not seen in previous runs, tracked per app and country. The first delta run behaves like `full`. |
| `sort` | string | `recent` | `recent` for newest first, `helpful` for Apple's most helpful reviews first. Delta mode always uses `recent`. |
| `stateKey` | string | empty (automatic) | Optional key under which delta mode remembers returned reviews in the `review-firehose` key-value store. Leave empty for one automatic key per app and country. |
| `maxReviews` | integer | default `100`, prefill `10` (1 to 10,000) | Maximum number of reviews to return in this run. |
| `proxyConfiguration` | object | Apify Proxy | Proxy settings. If Apple returns nothing for the proxy IPs, the Actor retries through residential proxies and then a direct connection. |

Example input for a scheduled delta run:

```json
{
  "appId": "310633997",
  "country": "us",
  "mode": "delta",
  "maxReviews": 500,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

### Output

Below is a review from a real run (app `310633997`, country `us`, mode `full`).

```json
[
  {
    "id": "14603402613",
    "reviewId": "14603402613",
    "appId": "310633997",
    "country": "us",
    "sourceUrl": "https://apps.apple.com/us/app/id310633997?see-all=reviews",
    "author": "Stve82v",
    "rating": 5,
    "title": "WhatsApp",
    "text": "I need to update my chat",
    "version": "26.37.76",
    "voteCount": 0,
    "voteSum": 0,
    "isEdited": false,
    "updated": "2026-09-28T13:34:56Z"
  }
]
```

### Delta mode: only new reviews on scheduled runs

In delta mode the Actor keeps a list of the review IDs it has already returned in a named key-value store called `review-firehose`. On the next run it skips those and pushes only reviews it has not returned before. The state is stored per app and country, so one Actor can track many apps, each on its own schedule. It keeps the most recent 20,000 review IDs per key. It also remembers how far back it has covered. Each run pages newest first, skips reviews it already returned (they are not charged), and stops at that point, so scheduled runs stay fast and cheap.

A practical setup:

1. Run once in `delta` mode with `maxReviews` set as high as the history you want (for example 2,000) to load the backlog.
2. Schedule the same task hourly or daily in `delta` mode. Each run outputs only new reviews.
3. Create one saved task per app and country. Use `stateKey` only if you want two tasks for the same app and country to keep separate state.

Set `maxReviews` high enough to cover the reviews you expect between runs. Reviews are read newest first, so if more new reviews arrived than `maxReviews`, the run returns the newest ones and the next run picks up the rest: coverage only advances after a run that got everything, so a capped or interrupted run never leaves a gap. A delta run with nothing new finishes successfully with an empty dataset and a status message saying so.

### How much does it cost?

The Actor uses pay-per-event pricing: you are charged for each review saved to the dataset. A delta run with no new reviews saves nothing, so it adds no result charges. Apify's free plan credit covers small runs, so you can test a few hundred reviews before paying anything. For the exact price per result on each plan, open the Pricing tab on the Actor page. You can also set a maximum cost per run, and the Actor stops when it is reached.

### Use with the API

Start runs and read datasets over the Apify API with the snippets below.

Python:

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("axiomworks/review-firehose").call(run_input={
    "appId": "310633997",
    "country": "us",
    "mode": "delta",
    "maxReviews": 500,
})
for review in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(review["rating"], review["title"])
```

JavaScript:

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('axiomworks/review-firehose').call({
    appId: '310633997',
    country: 'us',
    mode: 'delta',
    maxReviews: 500,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, 'new reviews');
```

cURL:

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~review-firehose/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"appId": "310633997", "country": "us", "mode": "full", "maxReviews": 50}'
```

Because it runs on Apify, the Actor works with Zapier, Make, n8n, Google Sheets and any tool that accepts webhooks through Apify integrations. A common pattern is a scheduled delta run that triggers a webhook, which posts each new review to a Slack channel or adds a row to a spreadsheet. You can also start runs and read datasets over the Apify API.

### Use with AI agents (MCP)

App Store Reviews Scraper can be called by AI agents through Apify's MCP server at https://mcp.apify.com. Agents find it with the `search-actors` tool and run it with `call-actor`. To expose only this Actor to your client, add it to the MCP configuration of Claude, ChatGPT, Cursor or any MCP-compatible tool:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/review-firehose"
    }
  }
}
```

Example prompts you can type once it is connected:

- "Get the latest 100 App Store reviews for app 310633997 in the US and summarize the main complaints."
- "Fetch new App Store reviews for app 310633997 in Germany using delta mode, then list anything rated 1 or 2 stars."
- "Compare the recent App Store reviews of these two apps in the `gb` (United Kingdom) storefront and tell me which has more crash complaints."

The input and output schemas are typed, so the agent knows which fields to set (`appId`, `country`, `mode`, `maxReviews`) and what each review item contains.

### FAQ

**How many App Store reviews can I get?** Up to 10,000 per run, per app and country. Popular apps have tens of thousands of reviews available, going back many months. Apple's older RSS review feed stops at about 500 reviews per app and country; this Actor is not limited to it.

**Why did a delta run return nothing?** No new reviews were posted since the last run. Switch to `full` mode to see the latest reviews again, or change `stateKey` to start a fresh state.

**Which countries and languages are supported?** Any two-letter storefront code that Apple serves. Reviews are returned as written in that storefront, so run once per country to cover several markets.

**How fast is it and do I need a proxy?** A run is HTTP-only and usually takes seconds. Apify Proxy is used by default. If Apple does not answer from a proxy IP, the Actor retries the first page with fresh proxy IPs, then residential proxies if you did not pin a proxy group, then a direct connection. If Apple's review API is unavailable, it falls back to Apple's RSS review feed.

**Why did the run fail with "Apple returned no reviews"?** Either the app has no written reviews in that storefront, or Apple is throttling the proxy IPs. Try another country or run again later. A wrong app ID fails with "not found".

**Can it fetch developer replies or ratings without text?** No. It returns written reviews only, without developer responses or star-only ratings.

**How fresh is the data?** Reviews are read live from Apple on every run, so results reflect what Apple shows at that moment. Schedule the task as often as you need, for example hourly or daily.

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

The Actor reads publicly visible App Store reviews, the same ones the App Store website shows. It does not log in or access private data. Reviews can contain personal data such as author names, so make sure your use complies with privacy laws such as GDPR and CCPA and with Apple's terms. You are responsible for how you use the data you collect.

### Feedback

Found a bug or need another field? Open an issue in the Issues tab of this Actor with your input and the run link. Feature requests are welcome there too.

# Actor input Schema

## `appId` (type: `string`):

Numeric Apple App Store app ID, or the app's App Store URL. App names such as 'Spotify' are not accepted. The ID is the number after `id` in the URL, e.g. https://apps.apple.com/us/app/whatsapp-messenger/id310633997 has ID 310633997.

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

Two-letter lowercase ISO country code of the App Store storefront, e.g. `us`, `gb` (United Kingdom, not `uk`), `de`, `jp`. Default `us`.

## `mode` (type: `string`):

`full` returns the most recent reviews on every run. `delta` returns only reviews not seen in previous runs, tracked per app and country. Use `delta` for scheduled runs. The first delta run behaves like `full`.

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

`recent` returns newest reviews first. `helpful` returns Apple's most helpful reviews first. Delta mode always uses `recent`.

## `stateKey` (type: `string`):

Optional. Key under which delta mode remembers already-returned reviews in the `review-firehose` key-value store. Leave empty to use one automatic key per app and country.

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

Maximum number of reviews to return in this run (min 1, max 10,000). Apple keeps the full review history, so large backlogs are available. In delta mode, set this high enough to cover new reviews between runs.

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

Apify Proxy is used by default. If Apple returns nothing for the proxy IPs, the Actor automatically retries through residential proxies and then a direct connection. Data volume is only a few hundred KB per run.

## Actor input object example

```json
{
  "appId": "310633997",
  "country": "us",
  "mode": "full",
  "sort": "recent",
  "maxReviews": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

All results in the 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 = {
    "appId": "310633997",
    "country": "us",
    "mode": "full",
    "maxReviews": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/review-firehose").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 = {
    "appId": "310633997",
    "country": "us",
    "mode": "full",
    "maxReviews": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/review-firehose").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 '{
  "appId": "310633997",
  "country": "us",
  "mode": "full",
  "maxReviews": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call axiomworks/review-firehose --silent --output-dataset

```

## MCP server setup

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

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/ECdaekF4IsPSLAT3s/builds/8JYQGOGvQUGEc62UP/openapi.json
