APP STORE REVIEW EXPORT TROUBLESHOOTING · UPDATED NOV 11, 2026
Correct counts.
Wrong evidence?
Before a review export becomes a product report, check more than its field names. A complaint example can be invented or copied from another storefront while the star counts and average still look right.
This guide covers the TanLabs App Store Review Insights JSON schema. It is not a universal validator for every scraper. All downloadable examples below are synthetic test fixtures.
Free · Python 3.10+ · Standard library only · No account, API key or data upload
A FAILURE YOU CAN REPRODUCE OFFLINE
Three reviews. Matching counts. One invented quote.
The fixture has one summary and three review rows for one app/country. Its star buckets contain one 1-star, one 4-star and one 5-star review. The fetched average is (1 + 4 + 5) / 3 = 3.333. One complaint example has been replaced with a sentence that appears in none of those reviews.
After extracting the ZIP, run both commands from that folder:
# Default mode allows partial / summary-only exports.
python3 validate_output.py demo-mismatched-evidence.json --json
# Exit 0: {"ok":true,"summaryRows":1,"reviewRows":3,"errors":[]}
# Complete mode can inspect the source review rows.
python3 validate_output.py demo-mismatched-evidence.json --json --require-reviews
# Exit 1: "summary #1: theme #1 example does not match a 1-2 star
# review in the same appId+country ..."
The difference is intentional: a summary-only export cannot prove where a quote came from. When all raw rows are available, complete mode checks that evidence comes from a 1–2 star review in the same app and country.
TanLabs builds each example as the first 280 characters of title + ". " + text. Preserve those original strings, including punctuation and Unicode. A missing title is treated as an empty string. A present title must be a string. A matching word or a paraphrase is insufficient.
Passing fixture · Malformed-rating fixture · Invented-evidence fixture · SHA-256 checksums
DIAGNOSIS BEFORE RETRYING
Fix the cause, then rerun the gate.
| Error contains | Likely cause | Next step |
|---|---|---|
weighted average | An overall store rating or another scope’s average was copied into the fetched sample. | Recompute from the five star buckets. Do not replace it with Apple’s lifetime rating. |
complete export requires | Review rows were filtered out, truncated or exported separately from their summary. | Export the entire dataset JSON, including summary and review rows. Use default mode only when the partial export is deliberate. |
review-row rating distribution | The total count looks right, but one or more row ratings disagree with the summary buckets. | Compare counts for each star within each app/country. Rebuild the summary from the same snapshot. |
example does not match | The quote was edited, copied across scopes, taken from a 3–5 star review, or invented. | Restore unmodified source title/text, then regenerate the summary from those rows. If the raw rows are missing, retrieve the full export before claiming provenance. |
negativeShare, negativeReviews or shareOfNegative | A reported count exceeds the negative sample, or a percentage uses the wrong denominator. | Use 1–2 star rows as the negative denominator. Rebuild the summary from the same snapshot. Themes may overlap; do not add them as disjoint groups. |
duplicate reviewId | Repeated pages or snapshots were concatenated. | Retain one row per app/country/review ID in the chosen snapshot, then rebuild its summary. Preserve the original file for audit. |
review scope without summary | A review belongs to an app/country absent from the summary rows. | Export matching scopes together. Do not attach an arbitrary summary to make the error disappear. |
zero reviews | An empty feed, invalid app ID or country without recent samples. | Check the chosen app/storefront. Report “no recent sample” rather than interpreting an empty dataset as zero complaints. |
Exit 2 means a file or JSON input problem. Confirm the path and use a JSON array, one summary object, or an {"items": [...]} wrapper. Exit 1 means parsed data failed validation. Neither error needs a paid Actor run to reproduce with these fixtures.
CHOOSE THE CLAIM YOU CAN ACTUALLY CHECK
Partial export or complete snapshot?
| Check | Default | --require-reviews |
|---|---|---|
| Field types, scope, duplicate IDs, bucket totals and fetched average | Yes | Yes |
| Reported negative shares and theme count bounds (when present) | Yes | Yes |
| Complaint name and nonempty example | Yes | Yes |
| All expected rows and matching star buckets per app/country | No | Yes |
| Example matches a same-scope negative review | No | Yes |
| Theme semantics, truth of a review, complete historical coverage | Human / separate checks | Human / separate checks |
Use default mode for an intentional summary-only or filtered export. Use complete mode for an unchanged mixed dataset expected to contain all rows. Correct global totals cannot hide missing reviews in one country and excess rows in another: comparisons are per scope.
A REPORTING ROUTINE YOU CAN KEEP
Save the snapshot before rewriting it.
- Keep the original exported JSON with its collection time, input app IDs and storefronts. Save subsequent transformed files separately.
- Run the validator before mapping fields or translating title/text. Keep its JSON output next to the original export.
- On failure, inspect the reported summary/theme or review index. Fix the export process and regenerate the report from the same scope.
- On PASS, read the actual complaint in context and check its assigned theme. Keep recent-sample findings separate from overall store ratings.
python3 validate_output.py your-export.json --json --require-reviews > validation.json
# Preserve this command's exit code in your pipeline.
# 0 = checks passed; 1 = data failed; 2 = file/JSON input error.
Do not append || true to a report gate. A scheduler should stop sharing a report when the validator returns a nonzero exit code. Test both the passing fixture and a failing fixture before trusting that gate.
INTERPRETATION STILL NEEDS CONTEXT
What a passing export cannot prove
A quote can match a negative review exactly and still be assigned the wrong theme. This check does not run semantic analysis, verify a review author’s claim or establish that a sampled complaint is representative.
The TanLabs Actor uses recent public Apple RSS samples, capped at roughly 500 reviews per app/country. Validation establishes consistency inside the exported snapshot; it cannot recover missing historical reviews or turn the fetched average into a lifetime rating.
Exports from other tools need an explicit schema mapping. These example commands do not claim compatibility with arbitrary App Store scraper output.
PUT THE GATE BEFORE THE REPORT
Try the three fixtures first.
Download the readable validator and reproduce both outcomes without credentials. If you also need recent review data, the optional Apify Actor is billed separately; check its current pricing before starting a run.
Common questions
Why does default mode pass the invented-evidence fixture?
Default mode permits summary-only and filtered exports. It checks that evidence is present, but source review rows may be absent. Complete mode adds literal same-scope negative-review matching.
Can I translate review text before validation?
Run the evidence check on the original export first. Translated or paraphrased text will not match the Actor’s original 280-character example. Keep transformed files separate.
Does complete mode prove the theme is correct?
No. It checks that the example matches a 1–2 star source review in the same app/country. A human still needs to check the theme, context and representativeness.