App Store Review Insights – Topics & Version Regressions avatar

App Store Review Insights – Topics & Version Regressions

Pricing

from $0.20 / 1,000 review scrapeds

Go to Apify Store
App Store Review Insights – Topics & Version Regressions

App Store Review Insights – Topics & Version Regressions

Pull recent iOS App Store reviews for any app and country, tagged by topic, plus a per-app report: rating by version with regression flags, complaint topics, top negative phrases and quotes. Deterministic rules, no AI.

Pricing

from $0.20 / 1,000 review scrapeds

Rating

0.0

(0)

Developer

skuang

skuang

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

App Store Review Insights

Pull the most recent iOS App Store reviews for any app, in any App Store country, and get a per-app report of what users complain about: rating by app version (with regression flags), complaint topics, the most common phrases in 1–2★ reviews, and short quotes. Everything is computed with fixed keyword rules and counts, so the same reviews always give the same report. No AI model is involved.

What it does

  1. For every app and country you list, it reads Apple's public customer-review feed (newest first, up to 500 reviews per app and country) and looks up the app's name.
  2. It tags each review with topics such as crash_bug, ads or login_account using keyword rules.
  3. For each app it builds one insights report across all countries, with a per-country breakdown.
  4. It saves the reviews and/or reports to the dataset and writes a run summary (OUTPUT) to the key-value store.

Who it is for

  • App product managers checking how a release landed: did the average rating drop on the new version, and what do 1–2★ reviewers mention?
  • ASO and app-marketing agencies producing recurring review reports for clients across countries.
  • Competitor research: compare complaint topics and ratings of several apps side by side.

Input

FieldTypeDefaultDescription
appsarray of stringsrequiredUp to 50 App Store URLs (https://apps.apple.com/us/app/instagram/id389801252) or numeric IDs (389801252).
countriesarray of strings["us"]Up to 30 two-letter App Store country codes. uk is accepted as gb.
maxReviewsPerCountryinteger5001–500. Apple's feed returns at most 500 reviews per app and country.
sinceDatestringemptyOptional YYYY-MM-DD. Keeps only reviews from that date (UTC) on and stops paging once older reviews appear.
outputModestringreviews_and_insightsreviews_and_insights, insights_only, or reviews_only.
includeAuthorNamesbooleanfalseAdd the reviewer's App Store nickname to each review. Off by default to keep personal data out of your dataset.

Example:

{
"apps": ["https://apps.apple.com/us/app/instagram/id389801252", "310633997"],
"countries": ["us", "gb"],
"maxReviewsPerCountry": 500,
"outputMode": "reviews_and_insights"
}

An entry that is not an App Store URL or ID, or a country code that is not two letters or that Apple does not recognize, is recorded as failed in OUTPUT; the rest of the run continues.

Output

The dataset holds two kinds of items, told apart by type. The Reviews and Insights views in the Output tab show one kind each (rows of the other kind appear with empty columns; filter by type when exporting).

Review item (type: "review")

{
"type": "review",
"appId": "389801252",
"appName": "Instagram",
"country": "gb",
"reviewId": "14649988546",
"rating": 1,
"sentiment": "negative",
"title": "Rubbish",
"text": "The latest update is terrible. If I want to pause a reel I have to hold the screen. ...",
"version": "450.1.0",
"date": "2026-10-10T14:26:36.000Z",
"topics": ["crash_bug"],
"appUrl": "https://apps.apple.com/us/app/instagram/id389801252"
}
  • sentiment comes from the star rating only: 1–2★ negative, 3★ neutral, 4–5★ positive. The review text is not analyzed for sentiment.
  • date is the review's timestamp from the feed, in UTC.
  • authorName is present only when includeAuthorNames is on.

Insights item (type: "insights", one per app)

Trimmed example from a run on Instagram, us + gb, 100 reviews each (2026-10-12):

{
"type": "insights",
"appId": "389801252",
"appName": "Instagram",
"appUrl": "https://apps.apple.com/us/app/instagram/id389801252",
"countries": ["us", "gb"],
"reviewsAnalyzed": 200,
"summary": "Instagram: 200 reviews analyzed (US, GB) from 2026-10-01 to 2026-10-10. Average rating 2.46/5; 63% are 1–2★ and 33% are 4–5★. Most frequent topics in 1–2★ reviews: UI & usability (18, 14%), Crashes & bugs (16, 13%), Login & account (8, 6%). Rating drops of 0.5★ or more between versions: 450.1.0 averages 2.16★ over 160 reviews vs 3.57★ on 449.0.0. Most common phrase in 1–2★ reviews: \"full screen\" (11 reviews).",
"dateRange": { "from": "2026-10-01T15:06:53.000Z", "to": "2026-10-10T16:26:18.000Z" },
"averageRating": 2.46,
"ratingDistribution": { "1": 109, "2": 16, "3": 10, "4": 5, "5": 60 },
"sentimentCounts": { "negative": 125, "neutral": 10, "positive": 65 },
"averageRatingByVersion": [
{
"version": "449.0.0",
"reviews": 21,
"averageRating": 3.57,
"regression": false,
"previousVersion": "448.0.0",
"changeFromPrevious": -0.23
},
{ "version": "450.0.0", "reviews": 4, "averageRating": 3.25, "regression": false, "lowSample": true },
{
"version": "450.1.0",
"reviews": 160,
"averageRating": 2.16,
"regression": true,
"previousVersion": "449.0.0",
"changeFromPrevious": -1.41
}
],
"topicCounts": { "crash_bug": "...", "...": "reviews per topic, all ratings" },
"negativeTopicCounts": {
"crash_bug": 16,
"login_account": 8,
"subscription_pricing": 1,
"ads": 7,
"performance_battery": 1,
"ui_ux": 18,
"feature_request": 3,
"customer_support": 3,
"privacy_data": 0,
"sync_data_loss": 1,
"notifications": 1
},
"topNegativePhrases": [
{ "phrase": "full screen", "words": 2, "count": 11, "exampleReviewId": "14649966281" },
{ "phrase": "new update", "words": 2, "count": 11, "exampleReviewId": "14650404979" },
{ "phrase": "latest update", "words": 2, "count": 10, "exampleReviewId": "14649988546" }
],
"sampleQuotes": [
{
"topic": "ui_ux",
"label": "UI & usability",
"negativeReviews": 18,
"quotes": [
{
"reviewId": "14650333233",
"country": "us",
"rating": 1,
"version": "450.1.0",
"quote": "The new ‘Shop the Look’ button is ruining Reels."
}
]
}
],
"perCountry": [
{
"country": "us",
"reviewsAnalyzed": 100,
"averageRating": 2.07,
"...": "same rating and topic fields per country"
},
{ "country": "gb", "reviewsAnalyzed": 100, "averageRating": 2.84, "...": "..." }
]
}

The report is computed from every review fetched, also in insights_only mode.

Run summary (OUTPUT in the key-value store)

For every app and country: status (ok, empty, failed, or skipped), reviews collected and saved, pages fetched, why paging stopped, and any error. Also totals, and whether the run stopped at your spending limit.

  • ok: at least one review collected (partial: true if a later page failed after retries).
  • empty: the app exists but has no reviews in that country (or none since sinceDate).
  • failed: invalid input, unknown country, app not available in that country, or the feed could not be read.
  • skipped: not processed because the run reached its spending limit or was aborted.

The run fails only when every app and country failed.

How the insights are computed

  • Topics. Each review's title and text are lowercased and matched against regular-expression rules for 11 topics: crash_bug, login_account, subscription_pricing, ads, performance_battery, ui_ux, feature_request, customer_support, privacy_data, sync_data_loss, notifications. A review can have several topics or none. The rules are English keyword rules kept in one file (src/topic-rules.js); they are tested against a hand-written set of example reviews, which is not a measure of accuracy on real reviews. Expect some misses and some wrong tags, especially for sarcasm, misspellings, and non-English text.
  • Topic counts. topicCounts counts reviews per topic across all ratings; negativeTopicCounts only within 1–2★ reviews.
  • Rating by version. Reviews are grouped by the app version the reviewer was on, sorted by version number. A version is flagged regression: true when it has at least 5 reviews and its average is at least 0.5★ below the closest earlier version that also has at least 5 reviews. Versions with fewer than 5 reviews are listed with lowSample: true and are neither flagged nor used for comparison.
  • Top negative phrases. From 1–2★ reviews: text is split at punctuation, common English stopwords, numbers and the app's own name into runs of adjacent words, and the 2- and 3-word sequences inside each run are counted. Words that were not next to each other in the review are never joined ("banned for no reason" gives "no reason", not "banned no"). count is the number of reviews that contain the phrase (each review counts once); phrases need at least 2 reviews. A shorter phrase is dropped when a longer listed phrase containing it has the same count. Negations such as "can't" and "not" are kept.
  • Sample quotes. For the 3 most frequent topics in 1–2★ reviews, up to 3 of the most recent matching reviews, quoting the first sentence that matches the topic, cut to at most 200 characters.
  • Summary. A sentence template filled with the numbers above.

Pricing

Pay per event:

EventWhen it is chargedIntended price
review-scrapedEach review item saved to the dataset$0.0002 (= $0.20 per 1,000 reviews)
insights-reportEach insights item saved to the dataset, once per country it covers (countries with at least one review)$0.02 per app per country

The Pricing tab shows the current prices. Items are saved and charged together: the Actor only saves as many items as your spending limit allows and charges exactly for those. When the limit is reached it stops fetching, saves the OUTPUT summary, and says so in the run status. An insights report is saved only if all of its per-country events fit. Insights are saved before the reviews of the same app.

Example: 2 apps × 2 countries × 500 reviews with reviews_and_insights = 2,000 reviews + 2 reports covering 2 countries each = $0.40 + 4 × $0.02 = $0.48. A country where the app has no reviews is not charged.

Limitations

  • Apple's feed returns at most the 500 most recent reviews per app and country (10 pages of 50). For busy apps that may cover only a few days; check dateRange in the report. Older reviews are not available from this source.
  • Ratings without a written review are not in the feed, so averages here are averages of written reviews and differ from the star rating shown on the App Store.
  • Recent reviews are dominated by the latest version, so older versions often have few reviews in the sample. Use lowSample and the review counts when reading version comparisons.
  • Topic rules and stopwords are English. Reviews in other languages are still collected and counted, but will mostly get no topics and less useful phrases.
  • Reviews are fetched politely (at most 3 app and country pairs at a time, requests at least 0.5 s apart, up to 3 retries on rate limits, server errors and timeouts), so large runs take a while: roughly 6 s per app and country at 500 reviews.
  • This Actor reads a public Apple feed that Apple can change or limit at any time.

FAQ

Can I get more than 500 reviews per country? Not from this feed. Run the Actor on a schedule and keep the datasets to build a longer history.

Why is a country marked failed? Either the code is not a valid App Store country (Apple answers HTTP 400), or the app is not available in that country. The error in OUTPUT says which.

Is the sentiment from AI? No. It is derived from the star rating only.

Can I add or change topics? Yes, if you run your own copy: edit src/topic-rules.js (one entry per topic with a list of regular expressions) and add example reviews to test/tagger.test.js.

Does it store reviewer names? Only when includeAuthorNames is on.

What happens if the run is moved to another server? The Actor records each delivered insights report and each country's reviews in a PROGRESS record as soon as they are saved and charged. When Apify restarts the run elsewhere, it skips what was already delivered, so you are not charged twice. PROGRESS is deleted when the run finishes.