# Google Play Rating & Review Tracker (`northbell/google-play-rating-tracker`) Actor

Track any Google Play app's rating and review count over time. Because Play reports the average to full precision, this Actor recovers the average of the reviews that arrived since your last run — and warns you when new reviews run well below the app's norm. No login, no cookies.

- **URL**: https://apify.com/northbell/google-play-rating-tracker.md
- **Developed by:** [Northbell](https://apify.com/northbell) (community)
- **Categories:** Developer tools, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Google Play Rating & Review Tracker

Track any Google Play app's rating and review count **over time**, and get the thing a one-off scrape cannot give you: **the average of the reviews that arrived since you last looked**, and a warning when new reviews run well below the app's norm. No login, no cookies.

### The number that goes stale the moment you read it

An app showing `4.3 stars from 36 million ratings` tells you where it *has been*. It says nothing about which way it is moving right now. A wave of 1-star reviews after a bad update barely dents a 36-million average — the headline number keeps saying `4.3` while users are furious.

**A rating cannot be back-filled.** There is no endpoint that tells you what an app's rating was last Tuesday, or what the reviews that came in yesterday averaged. If you did not record it, that day is gone. This Actor records it and keeps the series:

```
com.example.app   —   4.31 → 4.29 → 4.24 over three days
   day 3:  +812 new ratings, averaging 2.1  ⚠  well below the app's 4.24 norm
```

### The trick Google Play makes possible

Play reports an app's average to **full precision** — `4.343131065368652`, not a rounded `4.3`. Combined with the exact rating count, two observations are enough to recover the average of everything that landed between them:

> new-reviews average = (count×avg *now* − count×avg *last time*) ÷ (new ratings)

So without reading a single review body, you learn that the 812 ratings added since yesterday averaged 2.1 — and that is a fire alarm a static `4.24` would never trip.

**It refuses to guess when it can't.** On a 36-million-rating app, three new ratings move the average by less than the precision allows, so the recovered figure would be noise. When that happens `newRatingsAverageReliable` is `false` and the Actor does not pretend. A number without that flag is a number that will eventually lie to you.

### What you get

Every run appends to your dataset. Rows are tagged by `type`.

**`app`** — one row per app:

| field | meaning |
|---|---|
| `averageRating`, `ratingCount` | the app's overall rating and how many ratings, right now |
| `installs`, `category`, `price`, `developer` | the listing |
| `ratingsAddedSinceLastRun` | how many ratings arrived since you last ran |
| `newRatingsAverage` | the average of just those new ratings |
| `newRatingsAverageReliable`, `newRatingsAverageErrorBound` | whether that figure can be trusted, and its margin |
| `ratingDropAlert`, `ratingDropGap` | set when new reviews run a full star or more below the app's norm — even after the error margin is subtracted |
| `firstSeenAt`, `observations`, `hoursSinceLastRun` | your own series |
| `removed` | the app is gone from that country's store — recorded, not treated as an error |

### Runs daily

Point it at your app (and your competitors' apps) and run it once a day. The first run is a baseline; from the second run on you get velocity and alerts. History lives in a named key-value store, so it survives between runs.

### No login. Not as a policy — as a property of the code.

This Actor reads only the public Play Store page an anonymous visitor sees. It never signs in and never sends a cookie; the input schema refuses any field that looks like `cookie`, `token`, `session` or `password`. Unit tests assert the no-login behaviour and the recovery maths.

### Two things it gets right

**A removed app is data, not a failure.** When an app 404s, the Actor records `removed: true` with the last rating it saw — that is the end of the app's life in that store, which is exactly what you were watching. It does not fail the run.

**It never ends green and empty.** If every app fails to load, the run is marked failed with an `error` row you will actually see — because a silent empty result is the worst outcome for something you check once a day.

### Input

```json
{
  "appIds": ["com.spotify.music", "com.duolingo"],
  "country": "US",
  "language": "en"
}
```

Paste a full Play Store URL instead of a package name and the id is taken from it. Ratings differ by country store, so set `country` to the market you care about.

### Sizing and cost

One request per app. Pay per event:

| event | when |
|---|---|
| Actor start | once per run |
| App checked | one app's rating recorded (a removed or errored app is not charged for the check) |

### On data and privacy

This Actor records **an app's public numbers** — rating, review count, installs. It does not read, store or return reviewer names, profiles or review text. The persistent history holds counts and dates only.

### Running locally

```bash
npm install
npm test          # 22 unit tests, no network, including the no-login guarantee and the recovery maths
```

### For AI agents

This Actor works well as an agent tool: the input schema is small and fully described, every run returns structured rows, and failures come back as data rather than silent gaps. Use it when you need to:

- track a Google Play app's rating and review count over time
- get the average rating of new Google Play reviews since the last run
- detect when new reviews of an Android app run well below its normal rating

***

### More no-login scrapers by northbell

Every one of these reads only public pages — **no login, no cookies** — and most of them record the numbers that cannot be back-filled if you don't capture them today.

**LinkedIn jobs**

- [LinkedIn Jobs Scraper with Applicant Counts](https://apify.com/northbell/linkedin-jobs-applicants-scraper) — jobs plus how fast applicants are arriving
- [LinkedIn Jobs Scraper — Filters That Actually Work](https://apify.com/northbell/linkedin-jobs-filter-scraper) — the experience/workplace filters LinkedIn silently ignores, applied for real
- [LinkedIn Jobs Salary Data — Filter by Pay](https://apify.com/northbell/linkedin-jobs-salary-scraper) — salary parsed into numbers so you can filter by yearly pay
- [Fast LinkedIn Jobs Scraper](https://apify.com/northbell/linkedin-jobs-fast-scraper) — bulk job listings, cheap and quick
- [LinkedIn Company Jobs Scraper](https://apify.com/northbell/linkedin-company-jobs-scraper) — every open role at a company you name

**LinkedIn companies**

- [LinkedIn Company Scraper with Headcount Growth](https://apify.com/northbell/linkedin-company-growth-scraper) — the real headcount and how fast it's growing
- [LinkedIn Company Posts + Engagement](https://apify.com/northbell/linkedin-company-posts-scraper) — a company's posts with exact reaction and comment counts

**App stores**

- [App Store Rank & Rating Scraper](https://apify.com/northbell/app-store-rank-and-review-watch) — iOS keyword rank and rating changes over time
- [Shopify App Reviews Scraper — Filter & Sort by Rating](https://apify.com/northbell/shopify-app-reviews-scraper) — exact per-star review counts, filter and sort
- [Google Play Rating & Review Tracker](https://apify.com/northbell/google-play-rating-tracker) — an Android app's rating tracked day by day

# Actor input Schema

## `appIds` (type: `array`):

The apps to track, by package name (com.spotify.music) — or paste the full Play Store URL and the id is taken from it. Run daily to build the rating history.

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

Two-letter country code (US, GB, JP). Ratings differ by country store.

## `language` (type: `string`):

Two-letter language code for the store page (en, ja).

## `maxRequestsPerMinute` (type: `integer`):

Kept polite by default. The budget is shared across your runs of this Actor.

## Actor input object example

```json
{
  "appIds": [
    "com.spotify.music",
    "com.duolingo"
  ],
  "country": "US",
  "language": "en",
  "maxRequestsPerMinute": 30
}
```

# Actor output Schema

## `apps` (type: `string`):

Current rating, review count, installs, category and price for each app.

## `velocity` (type: `string`):

How many ratings arrived since last run, their average, and whether new reviews are running below the app's norm.

# 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 = {
    "appIds": [
        "com.spotify.music",
        "com.duolingo"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("northbell/google-play-rating-tracker").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 = { "appIds": [
        "com.spotify.music",
        "com.duolingo",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("northbell/google-play-rating-tracker").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 '{
  "appIds": [
    "com.spotify.music",
    "com.duolingo"
  ]
}' |
apify call northbell/google-play-rating-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,northbell/google-play-rating-tracker"
        }
    }
}

```

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/wg4OEBnQqkKqVoXIj/builds/psjbpf8SjszzUQoS8/openapi.json
