# Google Play Store Scraper - Apps & Ratings (`s-r/google-play`) Actor

Read Google Play apps by package name or search: title, developer, category, rating, install band, description and icon. Returns all three of Play's differing review counts under names that say what they are.

- **URL**: https://apify.com/s-r/google-play.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Other, Business
- **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 Store Scraper - Apps & Ratings

Read apps from the Google Play store as structured data: title, developer,
category, rating, install band, description and icon.

Search Play, or give package names directly. No API key, no browser.

### Three review counts, because Play publishes three

This is the thing to know before you compare two apps on "reviews".

For Spotify, Play's page displays **25,202,278 reviews**. Its own data carries
**36,266,585** and **27,087,213** as well. Three numbers, all real, all
different:

| field | Spotify |
|---|---|
| `reviews_shown` | 25,202,278 |
| `ratings_total` | 36,266,585 |
| `rating_histogram_total` | 27,087,213 |

They count different things: written reviews, every rating including the silent
ones, and the total behind the star breakdown. Pick one and call it "reviews"
and any comparison between two apps quietly stops meaning anything, because you
have no way of knowing whether the other app's number came from the same place.

All three are returned, named for what they are. Use `reviews_shown` to quote
what a visitor sees, and `ratings_total` when you need a number you can sum.

### The developer field that is not the developer

Play carries a field that reads like the developer and is the **merchant of
record**. In the United States it happens to hold the developer's name, so it
looks correct. In the United Kingdom it reads **"Google Commerce Ltd" for every
single app**.

A column that is right in one market and uniformly wrong in every other is worse
than no column, because nothing about it looks broken. So `developer` is the
actual developer (Spotify AB, Calm.com Inc.) in every market, and `seller` holds
the merchant of record separately.

### Search or package names

**Search** uses Play's own store search, so the order you get is Play's ranking.
`vpn` returned Proton VPN, Secure VPN, Turbo VPN and the rest in the order Play
put them.

**Package names** (`com.spotify.music`) or Play links skip the search and read
those apps directly. Use both together and the named apps come first.

### Play is a per-country store, and this says which one it read

Availability, pricing, ranking and, as above, even the developer field differ by
market. **Country storefront** sets both the storefront and where the request
appears to come from, and `market` is recorded on every row, so two runs are
comparable rather than accidentally different.

### What you get per app

- `title`, `developer`, `seller`, `genre`
- `rating` out of 5, plus the three counts above
- `installs_text` (`1,000,000,000+`) and `installs` as a number
- `description`, `icon_url`, `updated_at` as a UTC timestamp
- `app_id`, `url`, `market`

### When Google moves something, you will know

Play does not label its data. Every field is addressed by its **position** in
nested arrays, which means a path can start returning the wrong thing, or
nothing, without any error at any point. That is how scrapers of this store
quietly rot.

Two things guard against it. Every field is checked against what it should look
like before it is published: a rating has to be a number between 0 and 5, so a
path that starts returning a developer name is dropped rather than published.
And the run summary reports `fieldsThatDidNotResolve` with a count per field.

A healthy run reports nothing there. A run reporting `{"updated_at": 3}` tells
you three apps did not publish an update date, which is normal. A run reporting
most fields at once tells you Google changed the page and the paths need
revisiting, on the day it happens rather than months later.

### Scale

Each app is one request, and a search is one more. Four apps took **ten seconds**
and eight search results took **seventeen**. **Maximum apps** caps both time and
cost.

### What people use this for

**App store optimisation.** Rank across a search term, with rating and install
band beside each result, is the whole competitive picture for a keyword.

**Competitor tracking.** Run a set of package names on a schedule and keep the
rows. Rating and install band move slowly, which is exactly why the movement is
worth catching.

**Market comparison.** The same app across several country storefronts, with
`market` on every row, shows where it is promoted and where it is not.

**Portfolio monitoring.** Your own apps and your rivals' in one table, refreshed
whenever you like, at one request each.

### Notes

Only public store listings are readable. An app that is unpublished or not
available in the chosen country is reported by name rather than returned as an
empty row.

Ratings and install bands move, so a run is a snapshot. `updated_at` is the
app's own last update, not the time of the run.

Reviews are counted but not fetched: the counts are here, the review texts are a
separate surface and are not part of this Actor.

# Actor input Schema

## `search` (type: `string`):

A search term. Play's own store search is used, so the order is Play's ranking. Combine with package names or use either on its own.

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

Package names such as com.spotify.music, or Play links. Read directly, without a search.

## `max_apps` (type: `integer`):

Stop after this many apps. Each app is one request, so this is also the cost ceiling.

## `region` (type: `string`):

Two-letter country code. Play is a per-country store: availability, price and even the developer field differ by market, so this sets both the storefront and the exit country.

## `attempts` (type: `integer`):

How often to retry a page that comes back without Play's data. Every page measured succeeded on the first try.

## Actor input object example

```json
{
  "search": "vpn",
  "apps": [
    "com.spotify.music"
  ],
  "max_apps": 25,
  "region": "gb",
  "attempts": 4
}
```

# Actor output Schema

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

One row per app.

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

Market, apps returned, how many carried a rating, and any positional fields that stopped resolving.

## `errors` (type: `string`):

Apps that could not be read.

# 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 = {
    "search": "meditation",
    "apps": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/google-play").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 = {
    "search": "meditation",
    "apps": [],
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/google-play").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 '{
  "search": "meditation",
  "apps": []
}' |
apify call s-r/google-play --silent --output-dataset

```

## MCP server setup

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

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/xwFQPkcWqljk3TbTa/builds/juEzvtzGQb8bvt821/openapi.json
