# Google Play App Intelligence - Ratings, Updates & Prices (`maydit/google-play-app-intelligence`) Actor

Monitor supplied Google Play apps for ratings, published updates, prices and install-band changes. Public detail pages and country-aware saved comparisons. No API key; no reviews or search scraping.

- **URL**: https://apify.com/maydit/google-play-app-intelligence.md
- **Developed by:** [Brandt May](https://apify.com/maydit) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 app observations

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

![App listings, observed over time — illustrative workflow](https://api.apify.com/v2/key-value-stores/YGxD9JRpduom8Q5Zd/records/google-play-app-intelligence-670b869c3cc9.png?signature=6qN3Zg6qHf4rVDs8FkTm)

### App listings, observed over time

Build a competitor-app or product watchlist from public Google Play detail pages. Each saved row records one app in a requested country and language, with available listing metadata and optional saved comparisons.

[Open this Actor in Console](https://console.apify.com/actors/h9wXg9DQ8niR59IKD/input) · [First run](#try-this-actor) · [Results](#result-preview) · [Cost](#usage-and-pricing) · [Full guide](#full-guide)

### Try this Actor

1. **Choose a small scope.** Use the **US app watchlist** below for Duolingo, Spotify and Todoist, with US country context, English listing text and at most three saved observations. The guide also includes a single-app UK example.
2. **Run and review.** Open the dataset and inspect country/language context and `fieldWarnings`. The run's key-value-store `SUMMARY` explains failed sources, partial coverage and saved baselines.
3. **Use the results.** Export CSV for the overview or JSON for offers, warnings and comparisons. Keep the source URL with each app observation.

**Read this before using the data:** An install band is not an exact download count, and rating counts are not written-review counts. Differences between saved listings do not prove a release or new user activity. The Actor does not search apps or scrape reviews.

**US App Watchlist - Duolingo, Spotify & Todoist** — copy this input into the JSON editor in Console.

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

### Result preview

The dataset view highlights these columns:

- **App ID** · `appId`
- **App title** · `title`
- **Country context** · `country`
- **Language** · `language`
- **Rating** · `rating`
- **Ratings count** · `ratingCount`

Use the original source links and the field definitions below when interpreting the results. CSV works well for flat columns; JSON preserves nested values.

### Usage and pricing

Base result rate on the FREE tier: **$2.5 per 1,000 app observations**. The [Pricing tab](https://apify.com/maydit/google-play-app-intelligence/pricing) shows your plan's result rate and any Actor Start charge. Set a small result limit for the first run; the requested limit is not a guarantee of that many results.

***

### Full guide

Monitor a supplied watchlist of Android apps from their public Google Play detail pages. Each saved row contains the app identity, requested country and language, rating and rating count, published price and currency, and available developer/listing fields. English listings also expose the published install band, update date, release notes, and developer-declared data safety summary.

Useful for competitor watchlists, release monitoring, changes to published monetization labels, and rating trends between saved observations. No Google account, owner credentials, API key, browser or proxy is required. This Actor does not fetch reviews, search results, charts, or the separate data safety endpoint.

#### Quick start

Run with `{}` for one current Duolingo observation. Or supply `appIds`, `appUrls`, or both. The fallback is used only when both source lists are empty. There is no catalog discovery: use known package IDs or Google Play detail URLs.

##### US App Watchlist - Duolingo, Spotify & Todoist

Inspect three public app listings for ratings, prices, install bands and published updates.

Use the [copyable first-run input](#try-this-actor) above.

##### Todoist UK - Country-Specific App Snapshot

Read one exact app URL with its UK country context and English public metadata.

```json
{
  "appUrls": [
    "https://play.google.com/store/apps/details?id=com.todoist&hl=en&gl=GB"
  ],
  "maxResults": 1
}
```

##### Todoist - Ratings & Published Update History

Compare Todoist with its last saved US observation. First run establishes history; unchanged observations remain visible.

```json
{
  "appIds": [
    "com.todoist"
  ],
  "country": "US",
  "language": "en",
  "comparePrevious": true,
  "snapshotName": "example-todoist-us",
  "maxResults": 5
}
```

#### Inputs

| Input | Default | Meaning |
| --- | --- | --- |
| appIds | Empty; fallback com.duolingo | Android package IDs; up to 100 combined distinct app/country/language sources. |
| appUrls | Empty | Public HTTPS Google Play detail URLs. URL gl/hl override global settings. |
| country | US | Requested country context. |
| language | en | Requested language; English provides the additional visible-label fields. |
| maxResults | 20 | Maximum confirmed saved observations. A selected cap does not mean an operational failure. |
| comparePrevious | false | Save and compare named history. |
| onlyChanges | false | Enable comparison and omit unchanged observations. Baselines still emit. |
| snapshotName | default | 1–40 letters, digits, hyphens or underscores, starting with a letter or digit. |
| maxRunSeconds | 240 | 30–3600 seconds, also bounded by the platform deadline with a 25-second reserve. |

#### Output and interpretation

- **Identity:** `appId`, `title`, `country`, `language`, `sourceUrl`, `finalUrl`, `observedAt`.
- **Published structured fields:** `rating`, `ratingCount`, `price`, `currency`, `offers`, `category`, `contentRating`, `operatingSystem`, `iconUrl`, `description`, `developerName`, `developerWebsite`. The developer website is the publisher-linked website or support URL, not a verified company homepage.
- **English visible-label fields:** `installBand`, `updatedOnText`, `updatedDate`, `releaseNotes`, `developerPrivacyPolicyUrl`, `declaredDataSafetySummary`, `containsAdsLabel`, `inAppPurchasesLabel`. Boolean labels record label presence; absent labels do not prove a business model.
- **Comparison:** `comparisonStatus` is `not_requested`, `baseline`, `unchanged` or `changed`; `changedFields`, `changeTypes`, and `previous` explain the last saved comparison. Text hashes cover description, release notes and declarations; previous snapshots retain their hashes, not the previous long text.
- **Diagnostics:** `fieldWarnings` explains unsupported enrichment or truncation. Missing source fields are null. Long description/release/declaration text is bounded to 30,000/20,000/10,000 characters respectively; changes outside those bounds are not observed.

Prices are exact decimal strings in the source currency; zero is a published free price. A price direction is reported only when both amounts have the same known currency. Multiple distinct offers remain in `offers` and leave the single price/currency fields null. Offer availability is the publisher's structured offer label, not a verified device-installation or regional purchase check.

An install band such as `10M+` remains a band, not an exact download count. `ratingCount` counts ratings, not written reviews. `updatedDate` is a published calendar date in YYYY-MM-DD form; it is not an invented release timestamp. The Actor does not promise version numbers, exact installs, ranking, download eligibility, review text, or a security grade.

The data safety summary is the developer's public declaration. It is not independently verified. Only the existing app detail page is read; no data safety expansion endpoint or support page is fetched. Public support emails, addresses and phone numbers are not extracted into dedicated fields.

Google can vary published ratings and counts by country, serving cache, or update timing. Change flags describe differences between saved public observations; they do not prove new user activity or a release event.

#### Saved history and repeat runs

With comparison enabled, history lives in the named key-value store `google-play-apps-{snapshotName}`, scoped by package ID, requested country, and language. Only a confirmed saved observation advances its baseline. Failed or unaffordable output does not replace history. Unchanged rows skipped with `onlyChanges` retain their prior saved baseline. No missing/deleted app inference is made.

Use the same namespace for sequential scheduled runs and different namespaces for independent workflows. A pre-write reread detects known overlap, but it is not an atomic lock; avoid concurrent runs sharing a snapshot name. History storage remains until you delete the named store. The first comparison run emits baseline rows. A successful changes-only repeat may emit zero rows and zero result charges.

#### Coverage, access and billing

The Actor makes bounded GET requests to public app detail pages and obeys robots.txt. It validates app identity before emitting a row and refuses private network destinations and unsafe redirects. Google Play's public HTML is not a supported data API and can change; robots rules, rate limits, missing apps, regional differences, or consent pages may prevent collection. Such failures appear in the `SUMMARY` key-value-store record, not in paid error rows. If every source fails, the run fails. A mixed run preserves successful rows and reports partial coverage.

SUMMARY reports confirmed `rowsSaved`, `rowsObserved`, `unchangedSkipped`, `failedSources`, per-source coverage and baseline writes, and whether a result, spending, or time limit stopped the run. Selected result caps are distinguished from operational failures. Country is requested context, not a claim that Google returned personalized account/device data.

Proposed Store pricing is **$0.0025 per saved app observation**, plus a **$0.00005 run start**; the current Store pricing panel is authoritative. Unchanged observations are paid rows unless `onlyChanges` skips them. Failed fetches, invalid source data and skipped unchanged records are not billable result rows. Account storage or platform costs can depend on your Apify plan.

#### Local development

Node.js 20.18.1 or newer. Run `npm ci`, `npm test`, then `npm start` with local Apify INPUT storage. The lock pins Apify SDK 3.7.2 and a patched basic-ftp override. No API token is required for local public-source collection.

### Help with your run

Open the **Issues** tab on this Actor with the run URL, the input field that caused trouble and what you expected to receive. Remove API keys and private information before posting.

[Explore more Mayd-It Actors](https://apify.com/maydit)

### Understand your run

Open **Run report** in the run’s Output tab for saved-record counts, reported source issues and limits, and suggested next steps. Use **CSV export** to take the saved results into a spreadsheet. The existing JSON results and detailed machine-readable summary remain available.

The report reflects this run’s recorded coverage. A successful run or a saved result does not establish that every possible source record was collected.

# Actor input Schema

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

Up to 100 package IDs, for example com.duolingo. Combined with appUrls; no demo app is added when either source list is populated.

## `appUrls` (type: `array`):

HTTPS play.google.com/store/apps/details URLs. A URL’s gl and hl parameters override country and language for that source. Other parameters are discarded.

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

Two-letter country context (gl). This is a requested listing context, not a claim of device or purchase eligibility.

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

Language context (hl). Use en for full detail enrichment. Other languages return localized JSON-LD core fields; English-label enrichment is omitted with a warning.

## `maxResults` (type: `integer`):

Stop after this many saved rows. Unchanged rows skipped by onlyChanges do not count. At most 100 distinct source combinations are accepted.

## `comparePrevious` (type: `boolean`):

Use a named key-value store. First observations are baseline rows; later rows include previous values and change flags. Run the same snapshot name sequentially.

## `onlyChanges` (type: `boolean`):

Also enables comparison. Repeats can legitimately save zero rows. The first observation still emits a baseline row.

## `snapshotName` (type: `string`):

History store: google-play-apps-{snapshotName}; each app/country/language has independent history. Use a dedicated name per workflow and avoid concurrent runs sharing it.

## `maxRunSeconds` (type: `integer`):

The Actor also reserves 25 seconds before a platform timeout. Requests and retries are bounded by the remaining time.

## Actor input object example

```json
{
  "appIds": [
    "com.duolingo"
  ],
  "country": "US",
  "language": "en",
  "maxResults": 20,
  "comparePrevious": false,
  "onlyChanges": false,
  "snapshotName": "default",
  "maxRunSeconds": 240
}
```

# Actor output Schema

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

Confirmed public app observations. Failed fetches and parse errors are not dataset rows.

## `runReport` (type: `string`):

Readable summary of saved records, reported source coverage, limits and next steps. Available when this run saves its SUMMARY.

## `csvExport` (type: `string`):

Download saved dataset records as a CSV file for spreadsheets and other tools.

## `summary` (type: `string`):

Per-source coverage, confirmed saved rows, failed sources, selected cap, time and spending limits.

# 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.duolingo"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maydit/google-play-app-intelligence").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.duolingo"] }

# Run the Actor and wait for it to finish
run = client.actor("maydit/google-play-app-intelligence").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.duolingo"
  ]
}' |
apify call maydit/google-play-app-intelligence --silent --output-dataset

```

## MCP server setup

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

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/h9wXg9DQ8niR59IKD/builds/PakBZPdZn0VG6EtV3/openapi.json
