# App Store Reviews Scraper : $0.10 per 1,000 (`workware/app-store-reviews-scraper`) Actor

- **URL**: https://apify.com/workware/app-store-reviews-scraper.md
- **Developed by:** [Workware](https://apify.com/workware) (community)
- **Categories:** Social media, E-commerce, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.10 / 1,000 review returneds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## App Store Reviews Scraper: iOS Reviews to JSON, $0.10 per 1,000

Give it an **iOS app id, bundle id, or App Store URL** and get **every available review** as clean JSON:
rating, title, content, author, the **app version reviewed**, helpful votes, and date, with optional app
metadata. One predictable price: **$0.10 per 1,000 reviews** ($0.0001 each), no start fee.

**Read this first, it decides what you get:** Apple caps its public reviews feed at **50 reviews per page
over 10 pages = 500 reviews per app, per storefront**. That is Apple's ceiling, not ours, and no scraper
can exceed it. To get more than 500 reviews for a popular app, scrape it in **more storefronts**: pass
several `countries` (e.g. `["us","gb","de","jp"]`) and each returns up to 500 of that country's reviews.
When a walk stops at the ceiling (or at your `maxReviewsPerApp`), the app-status row says `truncated: true`
so you always know whether you have all of them.

***

### What is the App Store Reviews Scraper and what can it do?

It turns an iOS App Store listing into a structured review corpus. Give it `618783545`, or
`com.tinyspeck.chatlyio`, or `https://apps.apple.com/us/app/slack/id618783545`, or a list of up to 1,000
apps, and it walks Apple's official customer-reviews feed for each app in each storefront you name and
returns one JSON record per review, plus one status record per app x storefront telling you whether the
app was found, whether it is even sold in that storefront, how many reviews this run returned, and whether
it hit the 500 ceiling.

Typical uses:

- **Release-sentiment tracking**: every record carries the `appVersion` it was written against, so you can
  diff how sentiment moved from one release to the next, which raw star counts cannot show.
- **ASO and competitive monitoring**: pull a competitor's review history across storefronts and watch it
  on a schedule.
- **RAG and AI pipelines**: feed a whole category's review corpus into a retrieval index. The output is
  already normalized and stable.
- **Support and product feedback mining**: filter a warehouse to 1- and 2-star reviews and read what users
  actually complain about, at scale.

It is an API first and a scraper second: every option has a real default, so an API, CLI, or scheduled run
behaves exactly like a run started from the console form.

### What data does it extract? (output fields)

One **review** record per review:

| field | type | notes |
|---|---|---|
| `reviewId` | string | stable id (`appstore_<appId>_<country>_<id>`): safe as a primary key. Review ids are per storefront |
| `appId`, `bundleId` | string | Apple's numeric track id and the reverse-DNS bundle id |
| `country` | string | the ISO-2 storefront this review came from |
| `rating` | number | Apple's 1-5 integer star rating |
| `title`, `content` | string | the review headline and free-text body |
| `authorName` | string | the reviewer's self-chosen display name (public on the store page) |
| `authorUri` | string | null | the reviewer's public profile URI, when Apple provides one |
| `appVersion` | string | null | the app version the review was written against, when present |
| `voteSum`, `voteCount` | number | net helpful votes (can be negative) and total votes cast |
| `updatedAt` | ISO date | when the review was last updated |
| `source`, `scrapedAt` | string | always `"app-store"`, and the run timestamp |
| `appMetadata` | object | app name, seller, genre, current version, aggregate rating and count, when `includeAppMetadata` is on |

Plus one **app-status** record per app x storefront (`type: "app-status"`): the raw `app` you passed,
`appId`, `bundleId`, `country`, `reviewsReturned` (what this run returned), `truncated` (whether the 500
ceiling or your cap was hit), and `status`, one of `found`, `no_reviews`, `unavailable_in_country`,
`not_found`, or `error`.

### How to use the App Store Reviews Scraper (tutorial)

1. **Give it an app.** The numeric id is the `id…` part of an App Store URL
   (`apps.apple.com/us/app/slack/**id618783545**`). Put it in `apps`: `["618783545"]`. A bundle id or a
   full URL works too, and a list runs the whole batch.
2. **Choose storefronts.** `countries` defaults to `["us"]`. Add more (`["us","gb","de"]`) to reach past
   the 500-per-storefront ceiling and to cover non-US markets.
3. **Set a cap.** `maxReviewsPerApp` defaults to `0` (all available, up to 500). Start small: this is the
   field that decides what the run costs.
4. **Run it.** Reviews stream into the dataset as they are parsed. Export as JSON, CSV, or Excel, or pull
   them straight from the API.

### How much does it cost to scrape App Store reviews? $0.10 / 1,000, no start fee

| Event | What it is | Charged for | Price |
|---|---|---|---|
| `review-result` | Review returned | each record delivered | $0.10 / 1,000 |

No start fee, no per-app fee, no platform-usage surcharge. 1,000 reviews cost **$0.10**. That single claim
is the whole product, so nothing else charges: an app with **zero reviews**, a storefront that does not
carry the app (`unavailable_in_country`), an app that does not exist (`not_found`), or a failed fetch
(`error`) pushes a coverage row and charges **nothing at all**. You pay for reviews, and only for reviews.

### Input and output examples

Input:

```json
{
  "apps": ["618783545"],
  "countries": ["us", "gb"],
  "maxReviewsPerApp": 100,
  "sortBy": "mostRecent"
}
```

Output (one review, abridged):

```json
{
  "reviewId": "appstore_618783545_us_11897342001",
  "appId": "618783545",
  "bundleId": "com.tinyspeck.chatlyio",
  "country": "us",
  "rating": 5,
  "title": "Keeps our team in sync",
  "content": "We moved off email for internal chat and never looked back…",
  "authorName": "desk_jockey_92",
  "authorUri": "https://itunes.apple.com/us/reviews/id123456789",
  "appVersion": "25.08.10",
  "voteSum": 4,
  "voteCount": 5,
  "updatedAt": "2026-08-01T12:00:00-07:00",
  "source": "app-store",
  "scrapedAt": "2026-08-15T09:14:02.512Z"
}
```

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `apps` | `array` | Yes | - | The iOS apps to scrape: one run handles the whole batch, one app at a time. Each entry is a numeric App Store track id (`618783545`), a bundle id (`com.tinyspeck.chatlyio`), or an App Store URL (`https://apps.apple.com/us/app/slack/id618783545`). |
| `countries` | `array` | No | `["us"]` | ISO-2 App Store storefront codes to scrape each app in (e.g. `us`, `gb`, `de`, `jp`). Apple caps reviews at 500 per app PER STOREFRONT, so add more countries to reach more reviews. An unknown code fails only that app x country, not the run. |
| `maxReviewsPerApp` | `integer` | No | `0` | Caps the reviews returned per app PER STOREFRONT, taken in `sortBy` order. 0 means all available. Apple returns at most 500 per storefront regardless (10 pages x 50). The primary cost and scope control. |
| `sortBy` | `mostRecent` | `mostHelpful` | No | `mostRecent` | The order Apple serves reviews in, and therefore which reviews a `maxReviewsPerApp` cap keeps: `mostRecent` (newest first) or `mostHelpful`. |
| `includeAppMetadata` | `boolean` | No | `true` | Attach a metadata block to each review: app name, seller, genre, current version, and the aggregate rating and rating count (one extra `lookup` call per app). Turn off for review text only. |

### Other Actors you might need

- **[YouTube Channel Transcript Scraper](https://apify.com/workware/youtube-channel-transcript-scraper)**,
  the sibling media-to-text feed for the same AI, RAG, and research pipelines: another clean, normalized
  corpus source from the same account.
- **[Job Postings API](https://apify.com/workware/job-postings-api)** and the ATS scrapers
  (**[Greenhouse](https://apify.com/workware/greenhouse-jobs-scraper)**,
  **[Ashby](https://apify.com/workware/ashby-jobs-scraper)**): a separate hiring-data suite, same
  API-first design and predictable pricing.

### FAQ, legality, and support

#### How do I get more than 500 reviews for an app?

You scrape it in more storefronts. Apple's feed is capped at 500 reviews per app per storefront (10 pages
of 50), so a single-country run tops out there and reports `truncated: true`. Pass several `countries` and
each returns up to 500 of that storefront's own reviews; review ids are per storefront, so there is no
cross-country double-counting. There is no way to exceed Apple's per-storefront ceiling, and any Actor that
claims otherwise is not reading the same feed.

#### What is the difference between `no_reviews`, `unavailable_in_country`, and `not_found`?

They are three different empty answers, and telling them apart is why the Actor calls Apple's `lookup`
endpoint first. `not_found` means no such app exists. `unavailable_in_country` means the app is real but
Apple does not sell it in the storefront you asked for. `no_reviews` means the app is available there and
simply has no reviews yet. All three push a status row and charge nothing, so you are never billed for an
empty storefront.

#### Can I track sentiment across app releases?

Yes, and it is the reason `appVersion` is a first-class field on every record. Group reviews by
`appVersion` and you can see how ratings and complaints moved from one release to the next, which a raw
average star count hides. The Actor gives you the normalized data; the release-diff analysis is yours to
run.

#### Is scraping App Store reviews legal?

This Actor reads an **official, unauthenticated Apple JSON feed** intended for syndication, and the reviews
are user-generated public content. The only personal data is a self-chosen nickname and an optional public
profile URI, both already visible on the store page. That is a lower-exposure footprint than most review
sources, but **you are the data controller for anything you do downstream**: respect Apple's terms, honour
deletion requests, and make sure your GDPR/CCPA basis covers your own use.

#### What happens when the feed changes shape?

A structural change is detected and reported as an `error` for the affected app x storefront rather than
quietly returning partial data, and a scheduled health check runs this Actor against a known app to catch
it before you do. A rate-limit (HTTP 429) is treated as transient and retried; only a genuine shape change
stops the affected unit and raises an alert.

# Actor input Schema

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

The iOS apps to scrape: one run handles the whole batch, one app at a time. Each entry is a numeric App Store track id (`618783545`), a bundle id (`com.tinyspeck.chatlyio`), or an App Store URL (`https://apps.apple.com/us/app/slack/id618783545`).

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

ISO-2 App Store storefront codes to scrape each app in (e.g. `us`, `gb`, `de`, `jp`). Apple caps reviews at 500 per app PER STOREFRONT, so add more countries to reach more reviews. An unknown code fails only that app x country, not the run.

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

Caps the reviews returned per app PER STOREFRONT, taken in `sortBy` order. 0 means all available. Apple returns at most 500 per storefront regardless (10 pages x 50). The primary cost and scope control.

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

The order Apple serves reviews in, and therefore which reviews a `maxReviewsPerApp` cap keeps: `mostRecent` (newest first) or `mostHelpful`.

## `includeAppMetadata` (type: `boolean`):

Attach a metadata block to each review: app name, seller, genre, current version, and the aggregate rating and rating count (one extra `lookup` call per app). Turn off for review text only.

## Actor input object example

```json
{
  "apps": [
    "618783545"
  ],
  "countries": [
    "us"
  ],
  "maxReviewsPerApp": 0,
  "sortBy": "mostRecent",
  "includeAppMetadata": true
}
```

# Actor output Schema

## `results` (type: `string`):

Every record this run produced, as JSON. Also available as CSV, Excel and XML.

# 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": [
        "618783545"
    ]
};

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

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

```

## MCP server setup

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