I built this actor; it's a paid tool on Apify with a free trial credit.
The star rating on a store page is a lifetime average over tens of millions of ratings. It barely moves, so it can't tell you whether this week's release went badly, or whether Android users are having a worse time than iPhone users right now. The newest reviews can.
This post pulls the newest reviews for the same app from both stores with my App Store & Google Play Reviews Scraper, then puts three numbers side by side per platform: lifetime rating, recent average, and share of 1-2 star reviews. My earlier post built a Slack alert for negative reviews; this one is a comparison report.
What a real run showed
On 23 September 2026 I pulled the 30 newest US reviews per app. Thirty is a small sample, so read these as a demo of the method, not a verdict on the apps:
| App | Store | Lifetime rating | Newest 30, average | 1-2 star share |
|---|---|---|---|---|
| Uber | App Store | 4.90 (16.9M ratings) | 3.77 | 30% |
| Uber | Google Play | 4.74 (19.9M ratings) | 3.00 | 50% |
| Spotify | App Store | 4.77 (42.2M ratings) | 3.93 | 20% |
| Spotify | Google Play | 4.35 (36.4M ratings) | 4.03 | 20% |
Two things stand out. First, recent written reviews run well below the lifetime number everywhere. That's normal: most lifetime ratings are a quick star tap with no text, and people who bother to write are more often unhappy. So compare recent to recent, not recent to lifetime. Second, on that basis Spotify looked the same on both platforms, while Uber's Android reviews were clearly worse than its iOS ones that day.
Google Play rows also carry the app version the reviewer had installed. In the Uber sample, 21 of the 27 reviews with a version were on 4.648.10003. For Spotify, 13 of 22 were on 9.1.84.2231. When low ratings pile onto one version that isn't simply the most installed one, you've found your regression.
The code
pip install apify-client
from collections import Counter, defaultdict
from apify_client import ApifyClient
# label -> (App Store numeric ID, Google Play package name)
APPS = {
"Uber": ("368677368", "com.ubercab"),
"Spotify": ("324684580", "com.spotify.music"),
}
PER_APP = 500
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("rel8ble/app-reviews-scraper").call(run_input={
"apps": [app_id for pair in APPS.values() for app_id in pair],
"country": "us",
"sort": "newest",
"maxReviewsPerApp": PER_APP,
})
label_of = {app_id: label for label, pair in APPS.items() for app_id in pair}
groups = defaultdict(list)
for r in client.dataset(run["defaultDatasetId"]).iterate_items():
groups[(label_of.get(r["appId"], r["appName"]), r["store"])].append(r)
print(f'{"app":<10}{"store":<12}{"lifetime":>9}{"recent":>8}{"1-2 star":>10}{"n":>6}')
for (label, store), reviews in sorted(groups.items()):
n = len(reviews)
recent = sum(r["rating"] for r in reviews) / n
low = sum(1 for r in reviews if r["rating"] <= 2) / n
print(f'{label:<10}{store:<12}{reviews[0]["appRating"]:>9.2f}{recent:>8.2f}{low:>10.0%}{n:>6}')
# Google Play only: which versions are the low ratings on?
if store == "googlePlay":
all_versions = Counter(r["version"] for r in reviews if r.get("version"))
low_versions = Counter(r["version"] for r in reviews if r.get("version") and r["rating"] <= 2)
for version, bad in low_versions.most_common(3):
print(f' v{version}: {bad} of {all_versions[version]} reviews are 1-2 star')
appId is the numeric ID on App Store rows and the package name on Play rows, which is why one lookup table handles both. The store names differ (Uber - Rides, Eats, Hotels on iOS, Uber: Rides, eats, hotels on Android), so don't group by appName.
Reading the output
- Recent vs recent across platforms is the comparison that means something. A 0.3+ gap on a few hundred reviews is worth a look at the release notes for the worse platform.
-
Per-version share, not per-version count. The newest version always has the most reviews. What matters is the
bad of totalratio per version, which the last loop prints. - Run it on a competitor. The same script with a rival's two IDs tells you which platform they're weakest on.
Things to keep in mind
- Use a few hundred reviews per app. My table above used 30 per app to keep the example readable; at that size one angry afternoon moves the average.
- App Store reviews have no app version. Apple doesn't publish it, so the version breakdown is Android only.
-
Reviews are per country.
usandgbare different sets. Run each country separately if you care about more than one. -
Google Play returns one language per run (
language, defaulten). - Reviewer names are personal data. The script doesn't need them; drop the column if you store the rows.
Cost
$0.25 per 1,000 reviews, no start fee. The script above (2 apps, 2 stores, 500 each = 2,000 reviews) costs about $0.50 per run. Apify's free plan includes $5 of monthly credit.
App Store & Google Play Reviews Scraper on Apify ยท Python examples: app-reviews-scraper-python on GitHub
This article was drafted with AI and published by me.
Top comments (0)