DEV Community

Gio Rich
Gio Rich

Posted on

iOS vs Android: compare an app's recent reviews against its lifetime rating in Python

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
Enter fullscreen mode Exit fullscreen mode
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')
Enter fullscreen mode Exit fullscreen mode

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 total ratio 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. us and gb are different sets. Run each country separately if you care about more than one.
  • Google Play returns one language per run (language, default en).
  • 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)