# Apple App Store Reviews Scraper — any iOS app, no login (`dropin-apis/app-store-reviews`) Actor

Scrape Apple App Store reviews and ratings for any iOS app, in any country, using Apple's public review feed (JSON with XML fallback) — no App Store Connect key needed. Returns review text, star rating, author, app version and app details as structured JSON. $0.20 per 1,000 rows.

- **URL**: https://apify.com/dropin-apis/app-store-reviews.md
- **Developed by:** [drop-in apis](https://apify.com/dropin-apis) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.20 / 1,000 item scrapeds

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 Reviews Scraper — any iOS app, no login

**Apple App Store reviews scraper** that reads Apple's public customer-reviews feed for any iOS app and country: review text, rating, version and date, plus app details. No App Store Connect key. Up to 500 reviews per app per country. $0.20 per 1,000 rows.

Last updated: 2026-10-02 · **Guide:** https://alidaram99.github.io/api-alternatives/app-store-reviews-scraper/

Built on Apple's own public endpoints (the review feed in JSON, with an automatic XML fallback, and the iTunes lookup API). No login and no CAPTCHA bypass.

### Use cases

- **ASO (App Store Optimization):** track rating trends, keyword mentions and sentiment in
  reviews across storefronts and competitor apps.
- **Product feedback:** pull every recent review for your own app into your own database or
  spreadsheet for triage.
- **Competitor monitoring:** watch a competitor's rating, version-release cadence and review
  volume over time.

### Input

| Field | Type | Description |
|---|---|---|
| `apps` | array (required) | App Store URLs (e.g. `https://apps.apple.com/us/app/duolingo-language-lessons/id570060128`) or bare numeric app ids (e.g. `570060128`). Both are accepted. |
| `countries` | array | 2-letter storefront codes, e.g. `["us", "gb", "de"]`. Default `["us"]`. Each app is fetched once per country — ratings, prices and review volume genuinely differ by storefront. |
| `maxReviewsPerApp` | integer | Stop after this many reviews per app per country. Default 100, max 500 (Apple's feed itself caps at 500 — see Limits). |
| `sinceDate` | string (optional) | ISO date. Reviews are newest-first, so the scraper stops paging for an app/country as soon as it reaches an older review. |
| `includeAppDetails` | boolean | Also output one app-details row per app × country. Default `true`. |

Example input:

```json
{
  "apps": ["570060128", "https://apps.apple.com/gb/app/duolingo-language-lessons/id570060128"],
  "countries": ["us", "gb"],
  "maxReviewsPerApp": 200,
  "includeAppDetails": true
}
```

### Output

One dataset row per review, plus (if `includeAppDetails`) one row per app × country. Both
shapes share one dataset with a `type` field (`"review"` or `"app"`) — use the **Reviews** or
**App details** dataset view to see just the relevant columns. A third, rare row shape,
`type:"warning"` (`{ type: "warning", appId, country, message }`, see the **Warnings** view),
only appears when Apple's feed stayed empty across every retry for an app/country that
demonstrably has reviews — see the FAQ below.

**Review row:**

```json
{
  "type": "review",
  "appId": "570060128",
  "appName": "Duolingo: Language Lessons",
  "country": "us",
  "reviewId": "14612250135",
  "title": "Fun",
  "text": "Very fun and get one month free for unlimited power",
  "rating": 5,
  "version": "7.142.0",
  "date": "2026-09-30T13:01:34-07:00",
  "userName": "Hi it is a fun game",
  "voteCount": 0,
  "voteSum": 0,
  "developerResponse": null,
  "source": "rss-json"
}
```

**App-details row:**

```json
{
  "type": "app",
  "appId": "570060128",
  "country": "us",
  "name": "Duolingo: Language Lessons",
  "developer": "Duolingo, Inc",
  "price": 0,
  "currency": "USD",
  "averageRating": 4.72,
  "ratingCount": 5480861,
  "version": "7.142.0",
  "releaseDate": "2012-11-13T08:00:00Z",
  "currentVersionReleaseDate": "2026-09-28T17:42:01Z",
  "genres": ["Education", "Social Networking"],
  "contentRating": "4+",
  "size": "515190784",
  "minimumOsVersion": "17.0",
  "description": "Learn a new language, chess & more...",
  "url": "https://apps.apple.com/us/app/duolingo-language-lessons/id570060128?uo=4"
}
```

### How it compares

| Option | Any app, any country? | Price | Notes |
|---|---|---|---|
| **This Actor** | Yes | $0.20 per 1,000 rows | Public feed (JSON with XML fallback), retries when Apple's feed is flaky, app details included |
| App Store Connect API | No: only apps your team owns | Free | Needs an API key; includes developer responses |
| Other App Store review Actors on Apify | Usually yes | Some are cheaper (from about $0.10 per 1,000) | Compare fields, success rate and how they handle empty feeds |

### Pricing

**$0.0002 per item** ($0.20 per 1,000 rows), pay-per-event — you're billed per review or
app-details row actually pushed, nothing else.

### FAQ

#### How do I export App Store reviews without App Store Connect?

Run this Actor with the app id (or App Store URL) and country codes. App Store Connect's API only covers apps your team owns; this Actor reads Apple's public feed for any app.

#### Does this scrape Apple App Store reviews, or Google Play?

Apple App Store only — iOS, iPadOS and macOS apps distributed through `apps.apple.com`. It does not touch Google Play; that's a different feed entirely.

#### How many iOS reviews can I get per app?

Up to 500 per app per country: Apple's public feed stops after 10 pages of 50. Add more `countries` for more coverage; reviews differ by storefront.

#### Why would a run return no reviews?

Apple's feed is sometimes empty for a while. The Actor retries and falls back from the JSON feed to the XML feed. If both stay empty for an app that has ratings, it adds a `type: "warning"` row for that app and country instead of failing silently. That warning row is a dataset row like any other ($0.0002).

#### What does it cost?

$0.0002 per dataset row ($0.20 per 1,000). Review rows and app-details rows both count as rows.

#### Does it include the developer's reply to a review?

No. Developer responses are not part of Apple's public feed, so `developerResponse` is always `null`.

#### Can I track a competitor's ratings and reviews?

Yes. Pass their app id. You get their public reviews and the public rating summary in the app-details row.

#### Why does `source` say rss-json for some reviews and rss-xml for others?

It records which of Apple's two equivalent feed formats answered. Both carry the same review fields; the Actor uses the second as a fallback when the first comes back empty.

#### Does it use Apple's authenticated web API?

No. That endpoint needs a per-session bearer token (it returns HTTP 401 without one), so this Actor only uses Apple's public, unauthenticated endpoints.

### Limits

- Up to 500 reviews per app per country (Apple's own cap, not an Actor limit).
- No developer-response text (not present in the source feed).
- Review text language follows the storefront's dominant language, not a `language` input.
- Apple's feed has been observed to stay empty, for a single app/country, well past this
  Actor's own retries (see the FAQ above) — rare, but possible. Querying more than one
  app/country at once (the default prefill does this) makes a run far more likely to come back
  with real reviews even if one specific app/country is having a bad moment.

### Verified on Apify

On 2026-10-02 the Actor ran on Apify's own infrastructure: the nightly health check (Duolingo and Spotify, US and GB, up to 5 reviews each) returned reviews and passed. Remaining caveats are listed in `VERIFY.md`. In particular, Apify stops a run when your maximum charge is reached; the Actor does not stop itself earlier.

# Actor input Schema

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

App Store URLs (e.g. https://apps.apple.com/us/app/duolingo-language-lessons/id570060128) or bare numeric app ids (e.g. 570060128). Both are accepted and parsed the same way.

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

2-letter App Store storefront codes (e.g. us, gb, de). Each app is fetched once per country.

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

Stop paginating once this many reviews have been collected for one app in one country. Apple's public reviews feed itself caps at 500 (10 pages x 50) per app per country.

## `sinceDate` (type: `string`):

ISO date (e.g. 2026-01-01). The feed is sorted most-recent-first, so pagination for an app/country stops as soon as an older review is seen.

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

Also push one type:"app" item per app x country (name, developer, price, ratings, version, description, ...).

## Actor input object example

```json
{
  "apps": [
    "570060128",
    "324684580"
  ],
  "countries": [
    "us",
    "gb"
  ],
  "maxReviewsPerApp": 5,
  "includeAppDetails": true
}
```

# Actor output Schema

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

All items in the run's 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 = {
    "apps": [
        "570060128",
        "324684580"
    ],
    "countries": [
        "us",
        "gb"
    ],
    "maxReviewsPerApp": 5,
    "includeAppDetails": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("dropin-apis/app-store-reviews").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": [
        "570060128",
        "324684580",
    ],
    "countries": [
        "us",
        "gb",
    ],
    "maxReviewsPerApp": 5,
    "includeAppDetails": False,
}

# Run the Actor and wait for it to finish
run = client.actor("dropin-apis/app-store-reviews").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": [
    "570060128",
    "324684580"
  ],
  "countries": [
    "us",
    "gb"
  ],
  "maxReviewsPerApp": 5,
  "includeAppDetails": false
}' |
apify call dropin-apis/app-store-reviews --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dropin-apis/app-store-reviews"
        }
    }
}
```

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/OWWnxItgT3r6cCqVt/builds/HM8wBDb3YDmzARBGG/openapi.json
