App Store Reviews Scraper — Every Country, Not Just US avatar

App Store Reviews Scraper — Every Country, Not Just US

Pricing

from $0.05 / 1,000 review returneds

Go to Apify Store
App Store Reviews Scraper — Every Country, Not Just US

App Store Reviews Scraper — Every Country, Not Just US

Scrape Apple App Store reviews for any app, in any country store. Get rating, title, body, author, app version and date as JSON or CSV. Apple's feed is per-country and most tools return only US reviews — this one reports every market you ask for, including the ones with none.

Pricing

from $0.05 / 1,000 review returneds

Rating

0.0

(0)

Developer

Yaniv van der Stigchel

Yaniv van der Stigchel

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

19 hours ago

Last modified

Share

App Store Reviews Scraper — verify it fetched the right app

Every row names the app as Apple returns it for the id you passed — name, developer, bundle id and store URL. Ask for Spotify, see Spotify in row one. See something else and you know the run is wrong immediately, rather than after loading five thousand rows into a spreadsheet.

That sounds unremarkable until you read this category's reviews. "Keeps scraping the example app (candycrush) even if I update the app ID" (1.2 stars, 527 users). "kept spewing out the same incorrect reviews". "defaults to retrieving snapchat and facebook reviews". Five Actors across four publishers return the wrong app's reviews, and it goes unnoticed because review text never says which app it belongs to.

What it does

  • Scrape App Store reviews for any app, in any country store
  • Prove which app the reviews belong to, from Apple, on every row
  • Group complaints by release: appVersion, latestVersion and isLatestVersion
  • Filter stale feedback with reviewAgeDays — no date arithmetic
  • Compare markets, and see which country stores had no reviews at all
  • Export to JSON or CSV, or run it on a schedule

Three things this category gets wrong

Wrong app, confidently. Fixed by resolving identity from Apple's lookup and stamping it on every row, success or failure. If appName is not your app, the run is wrong, and you can see it in row one.

Silent truncation. Apple's public feed serves at most 500 reviews per app per country store, newest first. That number is printed in the log before any work starts, a warning names every app and country that reaches it, and SUMMARY carries pairsTruncatedByAppleCap with the pairs listed. When nothing was truncated the summary says so too, so a complete result is confirmed rather than assumed.

Missing markets. There is no country allow-list and no curated dropdown. Any two-letter ISO code goes straight to Apple — cn, hk, tw, kz, is, whatever you need. No store can be absent because we did not think of it.

No duplicate reviews

Apple's pages shift while a run is in progress, which is how duplicates get into other tools. Every review is deduplicated on Apple's own reviewId, which is stable across runs — so it also works as a primary key for merging today's run into yesterday's without double-counting.

Why per-country matters

Ask for us, gb and de for the same app and you routinely get three different pictures: different star averages, different top complaints, and sometimes an empty store. A single-country tool cannot show you that, and worse, it cannot tell you it did not look.

Every row carries its country, so the split is checkable rather than trusted.

You only pay for reviews

errorCodeMeaningCharged
— (success: true)A review rowYes
no-reviews-in-countryApp exists, nobody reviewed it in that storeNo
app-not-foundNo such app id, or Apple refusedNo
unparseable-app-idInput was not an App Store id or URLNo
unparseable-countryCountry was not a two-letter codeNo

An empty country store is a real answer and one of the more useful ones. It is reported as a row and never billed.

Input

FieldRequiredDescription
appsyesNumeric ids (324684580) or any apps.apple.com URL
countriesnoTwo-letter codes. Default ["us"]
maxReviewsPerAppnoPer app and country. Default 500, which is Apple's cap
{
"apps": ["324684580", "https://apps.apple.com/us/app/duolingo/id570060128"],
"countries": ["us", "gb", "de", "jp"],
"maxReviewsPerApp": 200
}

Output

Every row has the same fields whether it succeeded or failed, so you can select columns without branching.

FieldTypeDescription
successbooleanTrue when the row carries a review
appIdstringApp Store numeric id, as you asked for it
appNamestringThe app's name as Apple has it — your check that the run returned the right app
developerstringPublisher, from the store
storeRatingnumberOverall rating in this country store
storeRatingCountintegerHow many ratings that average covers
bundleIdstringReverse-DNS id (com.spotify.client) — the join key to Google Play and analytics
appUrlstringThe store page, to confirm the app by eye in one click
countrystringCountry store this review came from
reviewIdstringApple's stable id — deduplicates within and across runs
ratinginteger1 to 5
titlestringReview headline
bodystringFull review text
authorNamestringApp Store nickname; Apple publishes no real name
appVersionstringThe build the review was written against
latestVersionstringThe build shipping now, from Apple
isLatestVersionbooleanWhether the review is about the current release. Null when either version is unknown
updatedAtstringISO 8601 timestamp
reviewAgeDaysintegerWhole days old at run time
voteSumintegerNet helpfulness votes
voteCountintegerTotal helpfulness votes
errorCodestringNull on success
errorMessagestringHuman-readable explanation
{
"success": true,
"appId": "324684580",
"appName": "Spotify: Music and Podcasts",
"developer": "Spotify",
"storeRating": 4.77467,
"storeRatingCount": 41883904,
"bundleId": "com.spotify.client",
"appUrl": "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580?uo=4",
"country": "us",
"reviewId": "14504656715",
"rating": 1,
"title": "Ads are getting insane",
"body": "It got to the point where after 2 songs, 2 one-minute ads would play.",
"authorName": "Amber10122012333",
"appVersion": "9.1.78",
"latestVersion": "9.1.78",
"isLatestVersion": true,
"updatedAt": "2026-09-03T00:01:34-07:00",
"reviewAgeDays": 1,
"voteSum": 0,
"voteCount": 0,
"errorCode": null,
"errorMessage": null
}

The run summary

SUMMARY in the key-value store answers "what did this run achieve", per app and per country store — not just in total:

{
"requestedApps": 1,
"requestedCountries": 2,
"pairs": 2,
"delivered": 500,
"emptyCountries": 1,
"notFound": 0,
"maxReviewsPerAppPerCountry": 500,
"appleFeedCapPerAppPerCountry": 500,
"pairsTruncatedByAppleCap": 1,
"truncationNote": "1 app/country pair(s) reached Apple's cap of 500 reviews per country store, newest first: 324684580/us. Older reviews exist but the public feed does not serve them.",
"byAppAndCountry": [
{
"appId": "324684580",
"appName": "Spotify: Music and Podcasts",
"developer": "Spotify",
"country": "us",
"reviewsDelivered": 500,
"appleCapHit": true,
"storeRating": 4.77467,
"sampleAverageRating": 2.31,
"ratingDrift": -2.46,
"ratingBreakdown": { "1": 231, "2": 47, "3": 38, "4": 41, "5": 143 },
"newestReview": "2026-09-04T05:12:03-07:00",
"oldestReview": "2026-08-27T11:40:19-07:00",
"versionsCovered": ["9.1.76", "9.1.78"],
"latestVersion": "9.1.78",
"errorCode": null
}
]
}

ratingDrift is the sampled average minus the lifetime store rating. Negative means the newest reviews are worse than the app's history — the reading a star rating on its own cannot give you.

Use it from an AI agent (MCP)

This Actor is callable as a tool through the Apify MCP server, so Claude, ChatGPT, Cursor and VS Code can run it directly.

Add the server to your MCP client:

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com",
"headers": {
"Authorization": "Bearer <YOUR_APIFY_TOKEN>"
}
}
}
}

Then ask for what you want in plain language — for example “get the App Store reviews for this app in the UK and German stores” — and the agent calls cleanfeed/app-store-reviews-scraper with the right input. Every output field is described in the dataset schema, so the agent knows what it is getting back before it runs anything.

Call it from code

Python

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("cleanfeed/app-store-reviews-scraper").call(run_input={
"apps": ["324684580"],
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
if item["success"]:
print(item)

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('cleanfeed/app-store-reviews-scraper').call({
apps: ["324684580"],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.success));

cURL

curl -X POST "https://api.apify.com/v2/acts/cleanfeed~app-store-reviews-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
-H 'Content-Type: application/json' \
-d '{"apps": ["324684580"]}'
If you needUse
Comments on a product's YouTube videosYouTube Comments Scraper
Contact details for the company behind an appVerified Website Contacts

Limitations

  • Apple caps the public feed at 500 reviews per app per country, newest first — ten pages of fifty, with no way to page beyond it. The cap is printed in the run log before any work starts, warned about per app and country when it is reached, and reported in SUMMARY as pairsTruncatedByAppleCap with the pairs named. When it is not reached, SUMMARY says so too, which means a full result is confirmed rather than assumed. Anything promising an app's complete review history is not using this source.
  • Reviews are per-country, not per-language. A German-language review left from a US account appears in the us store. An app with no reviews in a country returns errorCode: no-reviews-in-country, which is a real answer and never charged.
  • Newest first is the only order. Apple's public feed offers no most-helpful or most-critical sort, so maxReviewsPerApp always trims the oldest reviews, never a random sample.
  • No developer responses. Apple's public feed carries the review only.
  • Author names are App Store nicknames, not real names, and should not be treated as identifying a person.
  • A star rating with no text is a real review and returns with a null title and body.
  • isLatestVersion is null when either version is unknown. An unknown comparison is reported as unknown rather than guessed as false.

FAQ

How do I know it fetched the right app?

Because every row carries appName, developer, bundleId and appUrl as Apple returns them for the id you passed, never echoed from your input. Ask for Spotify and see Spotify in row one. See something else and the run is wrong, visibly, in the first row. This is the category's most common failure — competing Actors have reviews reading "Keeps scraping the example app (candycrush) even if I update the app ID" — and it is invisible in a plain review dump because review text never names the app it belongs to.

Will I silently get fewer reviews than I asked for?

No. Apple's feed stops at 500 per app per country store. That number is printed in the log before the run starts, a warning names every app and country that reached it, and SUMMARY carries pairsTruncatedByAppleCap plus a plain-English truncationNote. If nothing was truncated the note says that as well, so you know the result is complete rather than hoping it is.

Are there duplicate reviews?

No. Apple's pages shift while a run is in progress, which is how duplicates get into other tools. Every review is deduplicated on Apple's own reviewId, which is stable across runs — so you can also use it as a primary key to merge today's run into yesterday's without double-counting.

Which country codes can I use?

Any two-letter ISO code Apple runs a store in — us, gb, de, fr, jp, br, in, cn, hk, tw. There is no allow-list in the code and no dropdown of curated markets, so no store can be missing because we forgot it. A code Apple does not run returns errorCode: unparseable-country or no-reviews-in-country rather than being silently dropped.

How do I group complaints by release?

Each row carries appVersion (the build the review was written against), latestVersion (what is shipping now, from Apple) and isLatestVersion. Filter to isLatestVersion: true for feedback on what you just released, or group by appVersion to see which build a complaint arrived with. SUMMARY lists versionsCovered per app and country.

What does the run summary tell me?

Per app and country: reviews delivered, the app Apple resolved, the star breakdown, the newest and oldest review in the sample, the versions covered, whether Apple's cap was hit, and ratingDrift — the sampled average minus the lifetime store rating. A negative drift means the newest reviews are worse than the app's history, which a star rating on its own cannot tell you.

How do I find an app's id?

It is the number after /id in any App Store URL. You can paste the whole URL instead and the id is extracted for you.

Why did a country return no reviews?

Because nobody has reviewed the app in that store. This is common for apps with one strong home market, and it is exactly the finding per-country reporting exists to surface. You are not charged for it.

Why not just query the US store?

Because ratings and complaints genuinely differ by market. Ask for us, gb and de for the same app and you routinely get three different pictures. A single-country tool cannot show you that, and cannot tell you it did not look.

Can I get Google Play reviews too?

Not from this Actor. Play is a separate source with a different shape, and merging them behind one schema would hide which store a row came from.

Do I need an Apple developer account?

No. This reads Apple's public customer-reviews feed, which needs no key and no login.

Notes

Only Apple's public customer-reviews feed is read — the same data any visitor sees on an app's App Store page. No developer account, no key, no login, and nothing that is not already published.