If you ship an iOS app, you probably read your reviews in App Store Connect or on the public store page for one country. That hides a lot. A crash that only shows up on a German locale, a pricing complaint from Brazil, a translation bug in Japan: those reviews live in their own storefronts and never show up in the US list.

This post shows two ways to get them:

  1. The free, do-it-yourself way using Apple's public review RSS feed (fine for one or two countries).
  2. Sweeping every storefront in one call with an Apify Actor I built, then filtering to the reviews that matter (1–2 stars, recent, mentioning "crash" or "subscription").

How Apple exposes reviews

Apple publishes a public JSON feed of customer reviews per app, per country:

https://itunes.apple.com/{country}/rss/customerreviews/page={1-10}/id={appId}/sortby=mostrecent/json 

Each page holds up to 50 reviews and there are 10 pages, so you get at most 500 reviews per country per sort order. No key, no login.

A minimal DIY version for one country:

import requests APP_ID = "570060128" # Duolingo, the number after "id" in the App Store URL COUNTRY = "de" reviews = [] for page in range(1, 11): url = f"https://itunes.apple.com/{COUNTRY}/rss/customerreviews/page={page}/id={APP_ID}/sortby=mostrecent/json" entries = requests.get(url, timeout=20).json().get("feed", {}).get("entry", []) if isinstance(entries, dict): # a single entry comes back as an object, not a list  entries = [entries] if not entries: break for e in entries: if "im:rating" not in e: # older feeds put the app itself in the first entry  continue reviews.append({ "rating": int(e["im:rating"]["label"]), "title": e["title"]["label"], "text": e["content"]["label"], "version": e.get("im:version", {}).get("label"), }) print(len(reviews), "reviews from", COUNTRY.upper()) 

That works. The pain starts when you want every country: 155 storefronts × 10 pages is 1,550 requests, with throttling, empty storefronts, the dict-vs-list quirk, retries, and de-duplication to handle. That part is what I packaged up.

Sweep all 155 storefronts in one call

App Store Reviews Scraper – All Countries runs the loop above across every storefront in parallel and gives you one clean dataset. Install the client:

pip install apify-client export APIFY_TOKEN=... # from Apify Console > Settings > API & Integrations 

Then ask for the negative, recent reviews from everywhere:

import os from collections import Counter from apify_client import ApifyClient client = ApifyClient(os.environ["APIFY_TOKEN"]) run = client.actor("olsols4/app-store-reviews-all-countries").call(run_input={ "apps": ["https://apps.apple.com/us/app/duolingo/id570060128"], "countries": ["ALL"], # or a list like ["us", "gb", "de", "br", "jp"]  "maxReviewsPerCountry": 500, "sortBy": "mostrecent", "minRating": 1, "maxRating": 2, # only 1- and 2-star reviews  "reviewsSince": "2026-09-01", # e.g. the date of your last release  "keywords": ["crash", "subscription", "refund", "login"], "includeAppDetails": True, }) items = list(client.dataset(run["defaultDatasetId"]).iterate_items()) reviews = [i for i in items if i["type"] == "review"] apps = [i for i in items if i["type"] == "app"] print(apps[0]["name"], apps[0]["averageRating"], "stars") print(len(reviews), "matching reviews") # Which countries are complaining the most? for country, n in Counter(r["country"] for r in reviews).most_common(10): print(country, n) # Which app version are the complaints about? for version, n in Counter(r["appVersion"] for r in reviews).most_common(5): print(version, n) 

You can also pass app names instead of URLs with "searchTerms": ["duolingo"] (it takes the top store match), which is handy for competitor research.

What a row looks like

One row per review, plus one type: "app" summary row per app. Here is a real one from a test run today (author removed):

{ "type": "review", "appId": "570060128", "country": "DE", "reviewId": "14665011333", "rating": 1, "title": "Nicht mehr was es war", "text": "Leider richtig schade, das war mal eine gute App aber mittlerweile ...", "appVersion": "7.144.0", "voteCount": 0, "voteSum": 0 } 

Note the keyword filter matches words as they appear, so for non-English storefronts add the local words too ("absturz" for German crashes, "assinatura" for Portuguese subscriptions), or drop keywords and filter afterwards with a translation step or an LLM.

Turn it into a weekly report

The useful version of this is a recurring job, not a one-off:

  1. In Apify Console, open the Actor, set the input above, and Save as a task.
  2. Add a Schedule (e.g. every Monday 08:00) for that task.
  3. Pick the latest results up from your own code:
run = client.actor("olsols4/app-store-reviews-all-countries").last_run(status="SUCCEEDED") items = run.dataset().list_items().items 

Or skip code entirely and use Apify's built-in integrations to push each run to Google Sheets, Slack, a webhook, n8n, Make or Zapier.

Set reviewsSince to roughly a week back each time (or just de-duplicate on reviewId on your side) so you only look at what's new.

Ideas for what to do with the data

  • Release QA: after every release, run with maxRating: 2 and reviewsSince = release day. A cluster of 1-star reviews from one country on the new version is usually a localisation or regional-payment bug.
  • Competitor research: run the same query on two or three rival apps and compare what users in each market dislike.
  • ASO copy: pull 4–5 star reviews (minRating: 4) and mine the phrases real users use for your store description.
  • Feed an LLM: the text field is clean, so it drops straight into a sentiment or topic-clustering prompt.

Cost and limits (being upfront)

  • It's pay-per-result: $0.25 per 1,000 reviews, plus $0.002 per app summary row. Countries with no reviews cost nothing. One app, all countries, newest 50 per country is typically a few thousand reviews, so around a dollar or two.
  • The 500-per-country ceiling is Apple's, not the Actor's. If you need a full historical archive of a huge app, this won't give it to you; for "what are people saying right now, everywhere", it's plenty.
  • It's App Store only, no Google Play.
  • Reviews include public nicknames; handle them in line with GDPR and your local rules.

If you try it and a field is missing or something breaks, open an issue on the Actor's Issues tab and I'll take a look.

👉 App Store Reviews Scraper – All Countries on Apify