# Review Gap Finder — Apps Losing Rating Points, Ranked (`alaudinburki/review-gap-finder`) Actor

For a list of apps, get recent reviews, find the ones dragging the rating down, and rank every app by its review gap — the negative reviews with nobody answering. Built for reputation agencies and app teams.

- **URL**: https://apify.com/alaudinburki/review-gap-finder.md
- **Developed by:** [alaudin burki](https://apify.com/alaudinburki) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Review Gap Finder — Apps Losing Rating Points, Ranked for Outreach

Give it a list of apps and get back **which ones are losing rating points and have nobody
answering** — ranked worst-first, ready to work through.

The point is the *gap*, not the rating. An app sitting at 4.7 lifetime but averaging **2.9 in its
most recent reviews** is in trouble right now and its team may not have noticed. That difference is
the whole product.

### What you get

**Dataset `gaps` — one row per app, worst first. This is the deliverable.**

| Field | Description |
|---|---|
| `app`, `developer`, `appId` | Which app |
| `reviewsSampled` | How many recent reviews were read |
| `negative` / `positive` | Counts of 1–2★ and 4–5★ |
| `negativeShare` | Percentage of the sample that is negative |
| `recentAvgRating` | Average of the sampled reviews |
| `storeAvgRating` | The app's lifetime average |
| **`ratingGap`** | **`storeAvgRating` − `recentAvgRating`** — positive means it is slipping |
| `gap` | `negative` count — the ranking number, because volume matters |
| `lowestRatedReview` | The worst recent review, quoted |
| `url` | App Store link |

**Default dataset — one row per review**

`id`, `appId`, `store`, `rating`, `title`, `body`, `author`, `version`, `updatedAt`, `voteCount`,
`voteSum`, `scrapedAt`.

### Sample output

```json
{
  "app": "Instagram",
  "developer": "Instagram, Inc.",
  "reviewsSampled": 100,
  "negative": 49,
  "positive": 40,
  "negativeShare": 49,
  "recentAvgRating": 2.94,
  "storeAvgRating": 4.69067,
  "ratingGap": 1.75,
  "gap": 49
}
```

Read that row: half the most recent reviews are one or two stars, the recent average is **2.94**, and
the app's public rating still says **4.69**. That is a 1.75-point gap — and a conversation.

### Default input

Runs with no editing: `["WhatsApp Messenger", "Instagram", "Spotify"]`, US storefront, 3 pages
(150 most recent reviews) per app.

### Limitations — read this before you buy

- **Apple App Store only, right now.** That is the one store with a clean public review feed.
- **Google Play is NOT implemented.** Its app page is a ~1.1 MB JavaScript blob and reviews load from
  a signed internal call. Not faked, not estimated — absent.
- **Google Maps, Trustpilot and Yelp return HTTP 403** or a JavaScript shell with no data. The
  **local-business** version of this idea — the big one — **needs a real browser runtime** and is
  recorded as blocked rather than shipped broken.
- **Apple's feed has no developer replies**, so `unanswered` cannot be computed there. The gap score is
  used instead, which is a different and defensible signal: negative volume plus a recent-vs-lifetime
  divergence.
- **This samples the most recent reviews**, not all of them. A long-established app with millions of
  reviews will show a small sample. Treat it as "what people are saying now", not a full audit.
- **No sentiment model.** 1–2★ is negative, 4–5★ is positive, 3★ is neither. That is deliberate: it
  is explainable, and it cannot hallucinate.

### Notes

- Two datasets on purpose. The ranked prospect list would be buried under thousands of review rows if
  they shared one dataset.
- The app's own entry is the first item in Apple's feed and carries no rating — it is skipped by that
  field rather than by index, so a change in feed order cannot corrupt the sample.

# Actor input Schema

## `apps` (type: `array`):

Apps to check — a name, or a numeric App Store id. Names are looked up automatically. e.g. \['WhatsApp Messenger', 'Instagram', 389801252].

## `country` (type: `string`):

Two-letter storefront, e.g. us, gb, de, pk. Reviews differ per storefront.

## `reviewPages` (type: `integer`):

Apple returns 50 reviews per page, newest first. 3 pages samples the most recent 150 reviews.

## `minNegativeReviews` (type: `integer`):

Only include an app in the ranked gap list if it has at least this many 1–2 star reviews. Use 1 to see everything.

## `maxItems` (type: `integer`):

Cap on the number of individual review rows.

## Actor input object example

```json
{
  "apps": [
    "WhatsApp Messenger",
    "Instagram",
    "Spotify"
  ],
  "country": "us",
  "reviewPages": 3,
  "minNegativeReviews": 1,
  "maxItems": 5000
}
```

# Actor output Schema

## `results` (type: `string`):

One row per item, with the 13 fields listed under Views.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "apps": [
        "WhatsApp Messenger",
        "Instagram",
        "Spotify"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("alaudinburki/review-gap-finder").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "apps": [
        "WhatsApp Messenger",
        "Instagram",
        "Spotify",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("alaudinburki/review-gap-finder").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "apps": [
    "WhatsApp Messenger",
    "Instagram",
    "Spotify"
  ]
}' |
apify call alaudinburki/review-gap-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alaudinburki/review-gap-finder"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/nAldWVOfqeYOfiHIh/builds/f1jGU3VVzMpcziCFu/openapi.json
