How can I reliably fetch and export my app reviews?

I’m trying to fetch all user reviews for my mobile app from different app stores so I can analyze feedback and track ratings over time, but I’m running into issues with missing reviews and inconsistent data. What tools, APIs, or workflows are you using to reliably pull, organize, and export app reviews for reporting and monitoring purposes?

Had to solve this crap for our apps too, here is what worked and what broke.

  1. Know the official sources

Google Play

  • Use the Google Play Developer API, Reviews resource.
  • Paginate with pageToken until it stops returning data.
  • Store reviewId, userComment.text, starRating, lastModified, reviewerLanguage.
  • Watch quota and rate limits or you lose pages.
  • Example flow: daily cron pulls new reviews since lastModified, writes to DB, never overwrites old rows, only append.

Apple App Store

  • Use the App Store Connect API, /v1/apps/{id}/customerReviews.
  • It returns only published reviews, not star-only ratings.
  • Sort by ‘recent’ and paginate with next links until empty.
  • Country segmentation matters. You need to hit each storefront you care about if you track per region.
  1. Handle missing reviews and gaps

Typical causes of “missing” stuff:

  • Language or country filters. You query US / en-US and miss DE / FR, etc.
  • Storefront differences. App Store Connect UI shows aggregated data that the API does not mirror one-to-one.
  • Deleted or edited reviews. Users edit text, rating changes, or Apple removes spam.
  • Time windows. If you pull with a date filter, you sometimes skip because of timezone mismatch.

Fixes:

  • Do one historical backfill per store without date filters. Save everything you get.
  • After that, run incremental syncs using lastModified or createdDate.
  • Regularly re-scan the last 7–30 days to catch edits and removals. Overwrite existing rows by reviewId when you see newer timestamps.
  1. If you want ready tools instead of rolling your own

Productboard, AppFollow, Appfigures, Appbot, AppTweak, etc.

  • They aggregate app store reviews into one UI and export to CSV, Excel, or API.
  • Most handle Google Play, iOS, maybe Amazon, Huawei.
  • Check if they preserve historical data when you disconnect, some do not.
  • Downsides: subscription cost, rate limits, and sometimes partial coverage for smaller stores.

For an in-house pipeline, these are stable:

Backend

  • Write small workers in Node, Python, or Go.
  • Store in Postgres or BigQuery with a simple schema:
    • store (google_play, app_store)
    • app_id
    • review_id
    • user_id or anonymous hash if available
    • rating
    • title
    • body
    • locale
    • country
    • created_at
    • updated_at
  • Add an index on app_id, store, created_at for analytics.

Export

  • For manual export, run SQL queries and dump CSV:
    • All-time reviews for NLP.
    • Daily aggregates of avg rating and count.
  • If you prefer a UI, connect Data Studio, Metabase, or Superset to the DB and schedule CSV exports.
  1. Keep data consistent
  • Normalize ratings to 1–5 numeric across stores.
  • Map countries and languages to standard codes.
  • Deduplicate by (store, app_id, review_id).
  • Convert timestamps to UTC on ingest.
  • When Apple or Google edits a review, keep previous version if you care about history, or store only latest if you focus on current status.
  1. Handling multiple stores
  • Google Play. Use API.
  • iOS. Use App Store Connect API.
  • Amazon Appstore. No great official API. People scrape or use 3rd-party aggregators.
  • Huawei or others. Often scraping or external services again.

If scraping, expect:

  • Breakage when HTML changes.
  • Harder pagination and locale handling.
  • Potential ToS issues.
  • Need for backoff and IP rotation for higher volumes.
  1. Tracking rating over time

Do not rely only on app store rating shown in the UI.
Use your stored reviews to compute:

  • Daily average rating.
  • Daily number of reviews.
  • Rolling 7-day and 30-day averages.
  • Breakdown by version, if you parse appVersion from reviews.

Basic SQL example idea for daily rating:

  • Group by date_trunc(‘day’, created_at), then avg(rating), count(*).
    Plot that in any BI tool to see effects after each release.
  1. Practical minimal setup if you want it simple
  • One small script per store, run via cron or GitHub Actions.
  • Writes to a single Postgres table with normalized fields.
  • Scheduled export to CSV once per day to S3 or GDrive.
  • Simple dashboard in Metabase for charts and filters.

That gets you reliable review history, consistent schema, and easy exports without depending fully on a vendor.

You’re not crazy, the “missing reviews” thing happens a lot even when using the official APIs correctly like @kakeru described.

A few extra angles that helped us clean things up:

  1. Treat reviews as an event stream, not just a snapshot
    Instead of just storing “current state,” append every change:
  • Raw table: one row per fetch per review (store, review_id, rating, text, fetched_at, raw_json).
  • Derived table: latest version per review_id, materialized from the raw table.
    This way if Google or Apple edits/removes something, you can still reconstruct what the user originally said and when. Super handy when your rating suddenly shifts and you want to know why.
  1. Don’t trust just lastModified / createdDate
    The incremental-sync idea is right, but both stores have occasional clock weirdness:
  • Keep a “lookback window” that is longer than you think you need.
    • Example: each run, fetch “since X days ago” instead of “since last run” and re‑merge.
  • Use (store, app_id, review_id) as your primary key and let the DB upsert on conflict.
    This covers late-arriving reviews and time zone drift without you manually debugging date ranges forever.
  1. Build a small reconciliation job
    Once a week, for each store:
  • Compute counts per day from your DB vs counts from the stores’ summary analytics (where available).
  • Flag days where the gap is > N percent (we use 5 to 10).
    On those days, do a “targeted re-pull” for just that date range. It’s ugly, but it catches a lot of edge-case missing reviews that normal incremental syncs miss.
  1. Standardize before analytics / export
    One thing I’d push harder on than @kakeru is schema normalization early:
  • Normalize:
    • rating to float (1.0–5.0)
    • locale to language + country split (language_code, country_code)
    • platform-specific fields into generic ones (e.g. version instead of appVersion / versionName).
  • Then expose one unified view / table for your BI tool or exports.
    If you skip this, you’ll spend way more time fixing CSVs in Excel than actually analyzing anything.
  1. Use a message queue if you’re hitting rate limits
    If you have a popular app or a lot of locales:
  • Put “fetch jobs” into a queue (RabbitMQ, SQS, whatever).
  • Workers respect rate limits and exponential backoff.
  • Retries are scheduled instead of hammered in a loop.
    That keeps you from getting temporarily blocked or silently cut off mid-pagination, which is where “inexplicable” gaps often come from.
  1. Version-aware analysis
    Most people compute daily averages, but then they mix reviews from 10 app versions together and get confused. If the store API gives you the app version:
  • Materialize daily metrics by date x version x platform x country.
  • Then create a view that aggregates as needed.
    This lets you do things like:
    “Show the 7‑day rolling rating for version 5.3 on Android vs iOS in US only.”
    A lot of “inconsistent data” feelings go away once you compare like with like.
  1. For tools, think “failover” strategy
    3rd-party tools are nice until:
  • Their API is down,
  • They silently change how they aggregate,
  • Or you switch vendors and lose history.

So instead of relying on a single tool:

  • Use a vendor plus your own pipeline.
  • Let the vendor feed your product / support teams with nice UI.
  • Let your own DB be the “source of truth” and archive.
    If the vendor dies or gets too expensive, you still have everything.
  1. For exports that humans actually use
    Tech folks love giant CSVs, but non-tech people don’t:
  • Create two layers of exports:
    1. Raw export: all reviews with full text for NLP.
    2. Curated export: daily/weekly summaries (avg rating, count, top 20 most recent negative reviews) per platform and country.
      Automate both. Ship to a shared drive or S3 with a predictable filename pattern so nobody has to ask “can you re-run that query” every week.

TL;DR pattern that’s worked well:

  • Fetch aggressively with a lookback window.
  • Store everything raw + deduped “latest” view.
  • Normalize fields early.
  • Reconcile periodically against store-level aggregates.
  • Use tools as a convenience layer, not your only source.

Once you set this up, the “missing / inconsistent” noise mostly turns into “oh, that’s just Apple yanking spam” instead of you wondering if your code dropped half of Germany.