# App Store Reviews Scraper & API - Ratings, Rankings, Charts (`akhil_rajesh/app-store-reviews-scraper`) Actor

Scrape Apple App Store reviews newest first and as deep as you need, with developer replies, filters (stars, dates, words, replies) and Slack, Discord or Teams alerts for new reviews, plus app details, privacy labels, keyword search rankings and top charts in 175 countries.

- **URL**: https://apify.com/akhil_rajesh/app-store-reviews-scraper.md
- **Developed by:** [Akhil rajesh](https://apify.com/akhil_rajesh) (community)
- **Categories:** Marketing, SEO tools, MCP servers
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.07 / 1,000 reviews

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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** reads **Apple App Store reviews**, newest first and as deep as you need (thousands per app, not the 500 the old RSS feed stops at), with **developer replies**, in any of **175 countries**, filtered by stars, dates, words, replies or length, and posts **new reviews to Slack, Discord or Microsoft Teams** after each scheduled run. It also gives you each app's **details** (ratings histogram, price, in-app purchases, version history, privacy labels), where apps **rank in App Store search** for your keywords, and the **top charts**, each with **what moved since your last run**. Paste App Store links, app ids, bundle ids or app names; get JSON, CSV or Excel, or use the API. No login, API key or proxy needed. AI agents can call it as an **MCP server** too, with tools for reviews, app details, rankings and charts ([see below](#for-ai-agents-mcp-server-and-live-api)).

- **Reviews, newest first and deep.** Each review's stars, title, text, reviewer, date, whether it was edited, and the developer's reply with its date. The Actor reads the App Store's own review list 20 at a time, as deep as Apple keeps it (Spotify's US list still answered at review 10,000), at about 25 pages a minute (Apple's pace limit): 1,000 reviews take about 2 minutes.
- **Per country.** The App Store keeps reviews, ratings and prices per country: pick one or many of 175 countries, and each app's reviews are read in each.
- **Filters that stop early.** Only 1-star reviews (asked from Apple's own critical list), only 5-star (its favorable list), any mix of stars, or reviews since a date or for the last 30 days: with newest first, reading stops at the first older review, so you pay only for what you asked for.
- **Filters on what reviews say.** Only reviews that mention words or phrases you pick ("crash", "refund", "dark mode"; each review lists the ones it matched), only those the developer replied to or those still waiting for a reply, or only those of at least N characters. You pay only for the reviews returned.
- **Only new reviews.** For a daily or hourly schedule: each run returns, and charges for, only the reviews earlier runs didn't, and stops reading where those begin.
- **Alerts in Slack, Discord or Teams.** Add a webhook URL and each scheduled run posts its new 1-2 star reviews (or the stars you pick) to your channel, with stars, title, text, version, date and a link. Zapier, Make, n8n or your own server get them as JSON. No extra charge.
- **A review summary per app.** Average stars of the reviews read, the share of 1-2 star reviews, the developer's reply rate, reviews per day, and the words most 1-2 star and 4-5 star reviews use ("login", "crash", "ads"...): a quick read on what users complain about.
- **App details.** Rating and rating count per country with the 1-5 star histogram, price, in-app purchases with their prices, version history with release notes, privacy labels ("Data Used to Track You", "Data Linked to You" and their categories), size, minimum iOS, languages, age rating and advisories, developer and seller with the seller's website, and the app's chart position.
- **Keyword rankings.** Where apps rank in App Store search for each keyword and country, in the **App Store's own order** for the first ~11 results, then, up to 200, in Apple's Search API's order (marked as an estimate). Your apps are marked, and listed even when they don't rank. Each run adds the previous rank and the move since.
- **Top charts.** Top free, top paid and top grossing, overall (apps and games together, as Apple's chart feeds list them) or for any of 41 categories (24 app categories such as Finance and Health & Fitness, Games, and 16 game genres), 100 positions each, with each app's previous rank, its move, new entries and the apps that dropped out.
- **Honest about failures.** An app Apple doesn't have, or doesn't sell in a country, gets a free "not found" note, never a charged empty row. When Apple refuses or doesn't answer, the run says what didn't load; it never reports "no reviews" for a page it couldn't read.

### Why this scraper

What people most often report about App Store review scrapers, and what this one does about it:

| Common problem | Here |
|---|---|
| Stops at 500 reviews, or at the first few pages | Reads Apple's own review list as deep as Apple keeps it: Spotify's US list still answered at review 10,000 |
| The same reviews come back twice | Each review is stored once, even when new reviews arrive mid-run and shift Apple's pages, and when a run is restarted: a live run rebooted in the middle of its reviews stored every review once |
| Reviews without dates, or a shape that changes between runs | Every review has its date (and its reply's date); every row follows the Actor's published dataset schema |
| Only some countries, or another country's reviews | All 175 App Store countries, each review marked with its country |
| A name or id that isn't found returns some other app | It never substitutes another app: an app it can't find gets a free row saying why, with the App Store's suggestions |
| Rate-limit errors and runs that die halfway | Paced under Apple's limit (2,000 reviews in about 4 minutes on Apify, without a refusal), and a run that stops says what it didn't read; resurrect it to finish |

### Use cases

- **Review monitoring and alerts.** Schedule a daily or hourly run with an alert webhook: new 1-2 star reviews land in your Slack, Discord or Teams channel as soon as the App Store lists them (its review lists ran about a day behind the reviews' dates on 2026-10-19). Add **Not replied to** to see which complaints still need an answer. A cheap alternative to review-monitoring subscriptions: 5 apps with 20 new reviews a day cost about $0.45 a month.
- **Support and product feedback.** Pull every review that mentions "refund", "login" or "crash" since your last release, with the version history beside it.
- **Competitor analysis.** Read competitors' reviews, ratings by country, pricing, in-app purchases and release cadence; compare their review summaries to see what their users ask for.
- **App store optimization (ASO).** Track where your app and your competitors rank for your keywords in every country, and how ranks move after a release or a metadata change.
- **Market and chart research.** Follow the top free, paid and grossing charts by category and country, and spot newcomers the day they enter.
- **Sentiment analysis and AI.** Clean, deduplicated review text with stars, dates and replies, ready for a spreadsheet, a database, a BI tool or a language model.

### How to use it in 4 steps

1. Add apps (links, ids, bundle ids or names) and pick countries.
2. Set Max reviews per app, and filters if you want them (stars, a date, words, replies, only new reviews).
3. For alerts, paste a Slack, Discord or Teams webhook URL, then put the run on a schedule (Schedules in Apify Console).
4. Optionally add keywords to track rankings and charts to follow.
5. Start the run, then download the results as JSON, CSV or Excel from the Output tab, or read them through the API.

### What you get

Every row has `type`: `review`, `reviewSummary`, `app`, `keywordRank`, `chart`, or `notFound` (free). The Output tab has a view for each kind, showing that kind's columns; every view lists all the run's rows, so filter on `type` (a view can't filter rows on Apify).

**Review**

| Field | Example |
|---|---|
| `appId`, `appTitle`, `country` | 324684580, Spotify: Music and Podcasts, gb |
| `reviewId`, `rating`, `title`, `text` | 14679323862, 5, SO MUCH ADS!!!, but actually really really good apart from the ads... |
| `userName`, `date`, `isEdited` | IDontLikeYourGirlfriend, 2026-10-17T22:58:13Z, true |
| `developerReply`, `developerReplyDate` | Hi. We appreciate your feedback..., 2026-09-11T23:51:46Z |
| `matchedTerms` | \[ads] (with Reviews that mention) |

**Review summary** (one per app and country): `reviewsRead`, `averageRating`, `ratingCounts`, `lowRatingShare`, `developerReplies`, `developerReplyRate`, `oldestReviewDate`, `newestReviewDate`, `daysCovered`, `reviewsPerDay`, `topWordsLowRatings`, `topWordsHighRatings`, and the filters used (`starFilter`, `since`, `reviewFilter`).

**App details** (one per app and country)

| Field | Example |
|---|---|
| `appId`, `bundleId`, `title`, `subtitle`, `url` | 324684580, com.spotify.client, Spotify: Music and Podcasts, Songs, Playlists & Audiobooks |
| `rating`, `ratingCount`, `histogram` | 4.77, 42,649,888, {"1": 939206, "2": 371928, "3": 948123, "4": 2990970, "5": 37399661} |
| `price`, `currency`, `free`, `inAppPurchases`, `inAppPurchaseItems` | 0, USD, true; Duolingo: Super Duolingo $12.99, Barrel of Gems (1200) $4.99... |
| `version`, `updated`, `releaseNotes`, `versionHistory` | 9.1.90, 2026-10-08T07:37:17Z, the last 25 versions with dates and notes |
| `privacy` | Data Used to Track You: Contact Info, Identifiers, Usage Data; Data Linked to You: 12 categories |
| `genre`, `genres`, `contentRating`, `contentAdvisories`, `chartPosition` | Music, \[Music, Entertainment], 13+ (the rating the App Store shows now), In-App Controls: Parental Controls, Infrequent: Cartoon or Fantasy Violence..., #1 top free in Music |
| `developer`, `developerId`, `seller`, `sellerUrl` | Spotify, 324684583, Spotify, https://www.spotify.com/ |
| `released`, `sizeBytes`, `minOsVersion`, `languages`, `devices`, `screenshots`, `description` | 2011-07-14, 308086784, 16.1, 60+ languages, \[iphone, ipad, tvos, watch] |

**Keyword rank**: `keyword`, `country`, `rank`, `rankSource` (`appStoreSearch` or `searchApi`), `appId`, `title`, `developer`, `rating`, `ratingCount`, `price`, `isTrackedApp`, `notRanked`, `previousRank`, `rankChange`, `isNew`, `droppedOut`.

**Chart**: `chart`, `category`, `country`, `rank`, `appId`, `title`, `developer`, `genre`, `price`, `released`, `previousRank`, `rankChange`, `isNew`, `droppedOut`, `url`.

A review row as it comes:

```json
{
  "type": "review",
  "store": "appStore",
  "appId": "324684580",
  "appTitle": "Spotify: Music and Podcasts",
  "country": "gb",
  "reviewId": "14679323862",
  "rating": 5,
  "title": "SO MUCH ADS!!!",
  "text": "but actually really really good apart from the ads, but overall it is a very enjoyable app...",
  "userName": "IDontLikeYourGirlfriend",
  "date": "2026-10-17T22:58:13Z",
  "isEdited": true,
  "developerReply": "Hi. We appreciate your feedback, and we'll pass it along to the Ads team...",
  "developerReplyDate": "2026-09-11T23:51:46Z"
}
```

### How to use it

#### Apps

Add apps in any form: an App Store link (`https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580`), an id (`324684580` or `id324684580`), a bundle id (`com.spotify.client`) or a name (`duolingo`). A name is looked up on the App Store's search and must hold every word you type; among matching apps the closest title wins, then the most-rated one. The status message and each row's `matchedBy` say which app a name matched, so check it, or use links and ids to be sure.

#### Countries

Each app is read in each country you pick (Max reviews per app applies to each). The country in an App Store link doesn't matter: the Countries field decides. Apps Apple doesn't sell in a country are named in the status message and skipped there.

#### Reviews

- **Max reviews per app**: per app and country, after the filters. 0 turns reviews off.
- **Order**: newest first, or Apple's "most helpful".
- **Star ratings**: 1 star alone or 5 stars alone is asked from Apple directly; other mixes are filtered as read (a list with none of them stops after 50 pages in a row without a match).
- **Reviews since**: a date (`2026-01-31`) or a period (`30 days`, `3 months`). The App Store's review lists ran about a day behind on 2026-10-19, so "2 days" gave about one day of reviews.
- **Reviews that mention**: words or phrases, any of which a review's title or text must contain, in any case and with or without accents (`cafe` finds `café`). A word also matches the longer words it begins: `crash` finds "crashes" and "crashing", not "scrash". Each review lists what it matched in `matchedTerms`.
- **Developer reply**: only reviews the developer replied to, or only those without a reply.
- **Minimum review length**: only reviews whose text has at least this many characters (100 leaves out "great app").
- **How far filters read**: Apple can't apply the word, reply and length filters, so the run reads reviews until Max reviews per app pass them, or at most 10 times that number (at least 2,000 reviews) per app and country, and says so when it stops there. Raise Max reviews per app to read further. Only the reviews returned are charged.
- **Only new reviews**: see below.

#### Keyword rankings

Add keywords and pick how many positions to read (25 by default, up to 200). The App Store's own search page shows about 11 apps, in the order the App Store app shows them; those ranks are exact (`rankSource: appStoreSearch`). Past them, positions come from Apple's public Search API (`rankSource: searchApi`), which knows the same apps but orders them differently: on four keywords tested on 2026-10-19, 6 to 11 of the App Store's first 11 were in the Search API's first 11, but only 1 to 4 at the same position. Treat ranks past ~11 as estimates. Your apps (in Apps) are marked `isTrackedApp`, and an app of yours that isn't in the positions read gets a row with `notRanked: true`.

#### Top charts

Pick top free, top paid and/or top grossing, and categories (empty: all apps). The App Store's chart feeds list 100 apps each.

### Alerts in Slack, Discord or Microsoft Teams

Paste a webhook URL in **Alert webhook URL**, pick the stars to post (1 and 2 by default), and schedule the run (daily or hourly). Setting a webhook turns on **Only new reviews**.

- **The first run** sets the baseline: it posts a short "alerts are set up" message naming the apps and countries it watches, so you know the webhook works, and no reviews.
- **Each later run** posts the reviews new since the run before, newest first: stars, title, text (the first 600 characters), app, country, date, and a link to the app's reviews. Up to 50 reviews a run; past that, the last message counts the rest, which are all in the dataset.
- **Where to get the URL**:
  - **Slack**: create an app at api.slack.com/apps, turn on Incoming Webhooks, click Add New Webhook to Workspace, pick the channel and copy the `https://hooks.slack.com/services/...` URL.
  - **Discord**: Server Settings → Integrations → Webhooks → New Webhook, pick the channel, then Copy Webhook URL.
  - **Microsoft Teams**: in the channel, open Workflows and pick "Post to a channel when a webhook request is received", then copy its URL.
  - **Zapier, Make, n8n or your own server**: any HTTPS URL that takes JSON gets `{"text": "...", "reviews": [...], "moreReviews": 0}`, each review with its fields and a `link`.
- **Set Max reviews per app above the new reviews you expect between two runs.** A popular app gets dozens an hour (Spotify's English Google Play list had 20 new ones a few minutes after a run on 2026-10-19). When more arrive than Max reviews per app, the run returns and posts the newest, and its status says the older new ones were skipped.
- **Kept secret.** The URL is stored encrypted with the run's input and never shown in the log, the status or the output. It is only ever sent to its own address.
- **If posting fails**, the run still succeeds with its reviews in the dataset, and the status message says why (for example "HTTP 404: check the webhook URL"). Alerts cost nothing extra: you pay for the new reviews returned, as without alerts.

### Tracking changes on a schedule

Runs with the same **History name** compare with each other (empty name: one shared default history). Give each schedule its own name.

- **Rankings and charts**: each row gets `previousRank` and `rankChange` (positive is up: 5 to 2 is +3), new apps get `isNew`, and apps that left the positions read get a row with `droppedOut: true` (switch those off with Include apps that dropped out). The first run sets the baseline.
- **Only new reviews**: each run returns the reviews earlier runs with the same history didn't, newest first, and stops reading where the known ones begin. The first run returns the newest up to Max reviews per app. Edited reviews keep their id, so an edit doesn't count as new.

The history lives in a key-value store in your account (`app-store-reviews-history` by default). Under Apify's limited permissions the Actor can only open stores it created itself, so pick a new name rather than one made elsewhere, including one made by the Google Play Reviews Scraper.

### Run summary for pipelines

Each run saves `RUN_SUMMARY` in its key-value store: rows by type, what wasn't found, what didn't load and why, notes (names matched, countries where an app isn't sold, filters that ended a list), and the requests made. The output tab links it.

### Use it via the API, from code or from an AI assistant

Start a run and get the rows in one call (replace `<YOUR_TOKEN>`; a call that waits for its rows gives up after 5 minutes, about 2,500 App Store reviews, so start bigger runs without waiting and read the dataset afterwards):

```bash
curl -X POST "https://api.apify.com/v2/acts/akhil_rajesh~app-store-reviews-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"apps": ["324684580"], "countries": ["us", "gb"], "maxReviewsPerApp": 200, "starRatings": ["1", "2"]}'
```

Or from Python with `apify-client`:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_TOKEN>")
run = client.actor("akhil_rajesh/app-store-reviews-scraper").call(run_input={
    "apps": ["https://apps.apple.com/us/app/duolingo-language-lessons/id570060128"],
    "maxReviewsPerApp": 500, "reviewsSince": "30 days", "includeAppDetails": True,
})
for row in client.dataset(run.default_dataset_id).iterate_items():
    print(row["type"], row.get("rating"), row.get("text", "")[:80])
```

#### For AI agents: MCP server and live API

The Actor also runs as a **live endpoint** (Apify Standby): an **MCP server** that agents call directly, and plain HTTP endpoints. Once a Standby run is up, a request is answered in seconds; the first request starts one. Authenticate with your Apify API token in the `Authorization: Bearer <token>` header.

**MCP server** (Streamable HTTP): `https://akhil-rajesh--app-store-reviews-scraper.apify.actor/mcp`

```json
{"mcpServers": {"app-store-reviews": {"type": "http", "url": "https://akhil-rajesh--app-store-reviews-scraper.apify.actor/mcp",
  "headers": {"Authorization": "Bearer <YOUR_APIFY_TOKEN>"}}}}
```

In Claude Code:

```bash
claude mcp add --transport http app-store-reviews https://akhil-rajesh--app-store-reviews-scraper.apify.actor/mcp --header "Authorization: Bearer <YOUR_APIFY_TOKEN>"
```

A client that can't send headers can use `https://akhil-rajesh--app-store-reviews-scraper.apify.actor/mcp?token=<YOUR_APIFY_TOKEN>`; keep that URL private, as it carries your token. Through **Apify's MCP server** (`https://mcp.apify.com`, for Claude, ChatGPT, Cursor and other clients), add the tools with `https://mcp.apify.com?tools=akhil_rajesh/app-store-reviews-scraper` (they appear as `akhil_rajesh--app-store-reviews-scraper--get_reviews` and so on), then ask in plain words, for example *"what do the newest 1-star reviews of the Duolingo iPhone app complain about?"*. Add them that way rather than through Apify's generic `call-actor` tool, which returns the rows only as text and shows clients that read structured results a summary instead. Apify's MCP server doesn't offer Actors with a live endpoint to agents that pay per call with x402 or Skyfire: connect with an Apify account or API token.

| Tool | What it returns |
|---|---|
| `get_reviews` | App Store reviews newest first (or most helpful), with developer replies and filters on stars, dates, words, replies and length; a summary row per app |
| `get_app_details` | Ratings with their histogram, price, in-app purchases, privacy labels, version history |
| `get_keyword_rankings` | Where apps rank in App Store search for each keyword, your apps marked |
| `get_top_charts` | Top free, paid and grossing charts, overall or by category |
| `run_actor` | The Actor's whole input in one call: reviews, details, rankings and charts together |

**HTTP endpoints**, such as `GET https://akhil-rajesh--app-store-reviews-scraper.apify.actor/reviews?apps=324684580&max=50&stars=1` (defaults in brackets). The Actor's **Endpoints** tab in Apify Console lists them too, and lets you try them.

| Endpoint | Parameters |
|---|---|
| `GET /reviews` | `apps`, `countries` (us; reviews are per country), `max` (100), `sort` (newest, mostRelevant), `stars`, `since`, `contains`, `reply` (withReply, withoutReply), `minLength`, `summary` (true) |
| `GET /app` | `apps`, `countries` (us) |
| `GET /rankings` | `keywords`, `countries` (us), `positions` (25), `apps` (yours, marked) |
| `GET /charts` | `charts` (top-free, top-paid, top-grossing), `categories`, `countries` (us), `positions` (100) |
| `POST /run` | The Actor's whole input as the JSON body |

**Answers** carry the `rows`, `rowsByType`, `notFound` (apps the store doesn't know: free), `notLoaded` (what the store didn't answer), `notRead` (what a limit left out: not charged) and `notes`. A request that reads nothing gets an `error` and nothing is charged: HTTP 400 for an argument it can't read (a tool error over MCP), 503 when the store didn't answer or the run was busy (send it again, after the `Retry-After` seconds when the store asked for a pause), 402 when your spending limit for the run is reached (it lifts when the run ends, after 2 minutes without requests). A 503 can also carry rows, when the platform stopped the run while a request was being read: those were stored and charged, and `notRead` names the rest. Apify itself answers 429 when an account sends too many requests at once.

**Limits per request**: an MCP tool call reads up to 5 apps, 500 reviews per app and about 350 kB of rows (about 500 reviews) within 50 seconds, and asks for 50 reviews per app unless told otherwise (MCP clients stop waiting at 60 seconds, and Apify's MCP server drops answers over about 1 MB); an HTTP request reads up to 20 apps, 1,000 reviews per app and about 6 MB within 170 seconds. The App Store serves at most about 27 review pages (540 reviews) a minute and often asks Apify's servers to pause, so expect up to a few hundred reviews per tool call and about 400-700 per HTTP request. What a limit leaves out is named in `notRead` and isn't charged. **A request that has started runs to its end even if you stop waiting**: Apify's Standby proxy keeps it open, so its rows are read and charged (they stay in that Standby run's dataset). Ask for what you need. Tracking (Only new reviews, rank moves) and alerts belong to scheduled runs: the live endpoint answers each request on its own, so it ignores those fields. For more reviews, or tracking, run the Actor normally.

### How much does it cost?

You pay **$0.10 per 1,000 reviews** and **$1.00 per 1,000 other rows** (app details, review summaries, keyword ranks, chart rows), less on paid Apify plans, plus a start fee of $0.00005 per run. **Platform usage is included** in runs of the Actor: there is no compute charge on top. Not-found rows are free. The live endpoint (MCP server and HTTP API) charges rows at the same prices, plus the Standby run's platform usage while it serves you and until it has been idle for 2 minutes (a short session costs a fraction of a cent).

| Apify plan | Per 1,000 reviews | Per 1,000 other rows |
|---|---|---|
| Free | $0.10 | $1.00 |
| Starter | $0.09 | $0.90 |
| Scale | $0.08 | $0.80 |
| Business and above | $0.07 | $0.70 |

| Run | Rows | Cost (Free plan) |
|---|---|---|
| One app's 100 newest reviews with its details (the default input) | 100 reviews + 2 rows | about $0.01 |
| 10,000 reviews of one app | 10,000 reviews + 2 rows | about $1.00 |
| A daily schedule of 5 apps with Only new reviews (and alerts), 20 new reviews each | 100 reviews + 5 summaries | about $0.015 a day |
| 10 keywords, 25 positions each, in one country | 250 rank rows | $0.25 |
| Top free, paid and grossing, 100 each, in 3 countries | 900 chart rows | $0.90 |

Apify's free plan ($5 of monthly credit) covers about 50,000 reviews. A keyword's rows for your apps that don't rank (`notRanked`) count as rank rows. To cap spending, lower Max reviews per app or set a maximum cost per run in the run options; the Actor stops cleanly at the limit.

### Input

```json
{
  "apps": ["https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580", "duolingo"],
  "countries": ["us", "gb", "in"],
  "maxReviewsPerApp": 300,
  "reviewSort": "newest",
  "starRatings": ["1", "2"],
  "reviewsSince": "30 days",
  "reviewContains": ["crash", "login"],
  "developerReply": "withoutReply",
  "minReviewLength": 50,
  "onlyNewReviews": false,
  "includeReviewSummary": true,
  "includeAppDetails": true,
  "keywords": ["music streaming", "podcast app"],
  "rankPositions": 25,
  "charts": ["top-free", "top-grossing"],
  "chartCategories": ["Music"],
  "chartPositions": 100,
  "historyName": "spotify-daily"
}
```

Every field is optional; an input naming nothing reads the example app's 100 newest reviews and details.

For alerts on a schedule:

```json
{
  "apps": ["324684580", "570060128"],
  "countries": ["us", "gb"],
  "maxReviewsPerApp": 200,
  "alertWebhookUrl": "https://hooks.slack.com/services/...",
  "alertStars": ["1", "2"],
  "historyName": "my-apps-alerts"
}
```

### Good to know

- **Reviews and ratings are per country.** The App Store has a review list for each country. An app's `ratingCount` counts star ratings, most of them without text, so it is far larger than the reviews you can read.
- **No app version or helpful votes on App Store reviews.** Apple's review list doesn't carry them (its old RSS feed did, for at most 500 reviews, and it now mostly answers empty).
- **Pace.** Apple's review service allows each address about 30 requests a minute and refuses bursts. The Actor stays under that (2,000 reviews took about 4 minutes on Apify, without a refusal, on 2026-10-19), waits when Apple asks it to, and never switches addresses to get around it, so 10,000 reviews take about 20 minutes. Several countries share that pace.
- **Long runs.** A run stops cleanly about a minute before its timeout (1 hour by default, about 25,000 App Store reviews in all) and says so; resurrect it to read the rest (nothing is stored or charged twice), or give a bigger run a longer timeout in the run options.
- **"Most helpful" order** is Apple's own; Reviews since and Only new reviews stop early only with newest first.
- **Edited reviews** show the edit's date and `isEdited: true`; a reply written before the edit can be older than the review's date.

### FAQ

**How many reviews can I get?** As many as Apple keeps for the app and country: the review list still answered at 10,000 for Spotify in the US. Set Max reviews per app up to 100,000, and give runs past about 25,000 reviews a longer timeout.

**Can it post new reviews to Slack?** Yes: paste a Slack incoming webhook in Alert webhook URL and schedule the run. Discord, Microsoft Teams and any JSON webhook (Zapier, Make, n8n) work the same way. See Alerts above.

**Can I find reviews that mention a feature or a bug?** Yes: put the words in Reviews that mention (`crash`, `refund`, `dark mode`). Each review returned lists the ones it matched.

**Can I get Google Play reviews too?** Yes, with the [Google Play Reviews Scraper](https://apify.com/akhil_rajesh/google-play-reviews-scraper), built on the same code, with the same fields where the stores agree.

**Do I need a proxy?** No. Apple's App Store answers Apify's servers directly. Apify's datacenter proxy or your own proxies can be used; residential proxies are refused, as they're billed per GB on top of the result price.

**Why does a name match the wrong app?** A name is matched among the App Store's search results: every word you type must be in the title, and the closest, most-rated title wins. If that isn't the app you meant, use its link or id.

**Is it legal?** The Actor reads public App Store pages that anyone can open without an account. Reviews are written under display names; use them in line with Apple's terms and the privacy laws that apply to you.

### Other Actors by this developer

- [Google Play Reviews Scraper](https://apify.com/akhil_rajesh/google-play-reviews-scraper): Google Play reviews, app details, data safety, keyword rankings and charts
- [Amazon.ca Product & Trending Tracker](https://apify.com/akhil_rajesh/amazon-ca-product-trending-tracker): Amazon Best Sellers, prices, search positions and reviews on 23 marketplaces, with change tracking
- [AliExpress Price Tracker & Scraper](https://apify.com/akhil_rajesh/aliexpress-price-tracker): AliExpress search results with store prices, units sold and price history
- [Yahoo Finance Scraper, API & MCP](https://apify.com/akhil_rajesh/yahoo-finance-scraper): quotes, history, options, financials and more

### Disclaimer

This Actor is an independent tool. It is not affiliated with, endorsed by or sponsored by Apple. It reads publicly available App Store pages at a modest pace and stays under Apple's rate limits. Use the data in line with Apple's terms and the laws that apply to you.

# Actor input Schema

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

App Store links (apps.apple.com/us/app/.../id324684580), app ids (324684580), bundle ids (com.spotify.client) or app names (a name is looked up on the App Store's search and must hold every word you type; the row says which app it matched).

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

App Store countries to read. Reviews, ratings and prices are per country on the App Store: each app's reviews are read in each country picked (Max reviews per app applies to each). Empty: United States.

## `includeReviews` (type: `boolean`):

Read each app's reviews.

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

Reviews to read per app and country, after the filters. The App Store serves reviews 20 a page, at about 25 pages a minute: 1,000 reviews take about 2 minutes, 10,000 about 20 (runs stop cleanly before their timeout, 1 hour by default: give big runs a longer one). 0: no reviews.

## `reviewSort` (type: `string`):

Newest first, or the store's own ranking (most helpful). Reviews since and Only new reviews stop early only with newest first.

## `starRatings` (type: `array`):

Only reviews with these stars. Empty: all. 1 star alone or 5 stars alone is asked from the App Store directly (its critical and favorable lists, newest first); other mixes are filtered as read.

## `reviewsSince` (type: `string`):

Only reviews written on or after this date (UTC), or within this period (7 days, 3 months). With newest first, reading stops at the first older review.

## `reviewContains` (type: `array`):

Only reviews whose title or text mentions any of these words or phrases (crash, refund, dark mode), in any case and with or without accents. A word also matches the longer words it begins (crash: crashes, crashing). Each review lists the ones it matched (matchedTerms). Empty: every review. With this filter or the ones below, a run reads reviews until Max reviews per app match, or at most 10 times that number (at least 2,000) per app and country: only the reviews returned are charged.

## `developerReply` (type: `string`):

Only reviews the developer replied to, or only those without a reply (to find the ones still waiting). Empty: both.

## `minReviewLength` (type: `integer`):

Only reviews whose text has at least this many characters (the title not counted): 100 leaves out 'great app' and keeps reviews that explain. Empty or 0: any length.

## `onlyNewReviews` (type: `boolean`):

Return only reviews earlier runs with the same History name didn't return, and stop reading where those begin (newest first). For a daily schedule: each run delivers, and charges for, the new reviews only. The first run returns the newest up to Max reviews per app.

## `includeReviewSummary` (type: `boolean`):

One row per app (and country) with what its reviews said: average stars, share of 1-2 star reviews, developer reply rate, reviews per day, and the words most 1-2 star and 4-5 star reviews use.

## `alertWebhookUrl` (type: `string`):

A Slack incoming webhook (https://hooks.slack.com/services/...), a Discord channel webhook (https://discord.com/api/webhooks/...), a Microsoft Teams Workflows webhook, or any HTTPS URL that takes JSON (Zapier, Make, n8n, your server). Setting it turns on Only new reviews. Stored encrypted, and never shown in the log or the output.

## `alertStars` (type: `array`):

Which new reviews to post (up to 50 a run, newest first; the rest are counted). Empty: 1 and 2 stars. Every new review is returned in the dataset either way.

## `includeAppDetails` (type: `boolean`):

One row per app and country: ratings with their histogram, price, in-app purchases, version history, privacy labels, size, age rating, developer and seller.

## `keywords` (type: `array`):

Search terms (budget app, photo editor). One ranking per keyword and country.

## `rankPositions` (type: `integer`):

Ranks to read per keyword. The App Store's own search order covers about the first 11 apps; past those, positions come from Apple's Search API, whose order differs (marked rankSource: searchApi, an estimate). Up to 200.

## `charts` (type: `array`):

Charts to read, in each country.

## `chartCategories` (type: `array`):

Categories of each chart. Empty: all apps.

## `chartPositions` (type: `integer`):

Ranks to read per chart (the App Store's charts list 100).

## `compareWithLastRun` (type: `boolean`):

Add each app's previous rank and move, and mark new apps. The first run sets the baseline.

## `includeDroppedOut` (type: `boolean`):

Add a row for each app in the last run's ranking or chart that isn't in this one (on top of the positions asked for).

## `historyName` (type: `string`):

Name of the key-value store that keeps the tracking history (a-z, 0-9 and hyphens). Empty: app-store-reviews-history. Use a new name to start over; under limited permissions the Actor can only open stores it created itself.

## `proxy` (type: `object`):

App Store needs no proxy. Apify's datacenter proxy or your own proxies can be used; residential proxies are refused (billed per GB on top of the result price).

## Actor input object example

```json
{
  "apps": [
    "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580"
  ],
  "countries": [
    "us"
  ],
  "includeReviews": true,
  "maxReviewsPerApp": 100,
  "reviewSort": "newest",
  "onlyNewReviews": false,
  "includeReviewSummary": true,
  "includeAppDetails": true,
  "rankPositions": 25,
  "chartPositions": 100,
  "compareWithLastRun": true,
  "includeDroppedOut": true,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

## `reviewSummaries` (type: `string`):

No description

## `apps` (type: `string`):

No description

## `keywordRanks` (type: `string`):

No description

## `charts` (type: `string`):

No description

## `notFound` (type: `string`):

No description

## `allData` (type: `string`):

No description

## `runSummary` (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 = {
    "apps": [
        "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580"
    ],
    "countries": [
        "us"
    ],
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("akhil_rajesh/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": ["https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580"],
    "countries": ["us"],
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("akhil_rajesh/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": [
    "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580"
  ],
  "countries": [
    "us"
  ],
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call akhil_rajesh/app-store-reviews-scraper --silent --output-dataset

```

## MCP server setup

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