# Google Play Developer Scraper (`renzomacar/google-play-developer-scraper`) Actor

List every app a Google Play publisher has on their developer page, with rating, install band, category and price. Optional per-app enrichment with full store details.

- **URL**: https://apify.com/renzomacar/google-play-developer-scraper.md
- **Developed by:** [Renzo Madueno](https://apify.com/renzomacar) (community)
- **Categories:** E-commerce, Marketing
- **Stats:** 2 total users, 1 monthly users, 72.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 app listeds

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 Developer Portfolio Scraper - All Apps by Publisher

Give it a Google Play publisher and get back their app catalogue as structured data: every app on their developer page with package name, title, rating, install band, category, price and store URL - and optionally the full store record for each app, including review counts, real install numbers, ads flag, in-app purchase range, last update date, developer email and website.

No API key, no Google account, no Play Developer API, no proxy. It reads the public developer page, which answers `HTTP 200` anonymously.

### Straight answer about how many apps you get

The developer page renders a fixed number of app cards and this actor reads what the page renders. Measured live:

| Publisher | Page type | Apps returned | Is that the whole catalogue? |
|---|---|---|---|
| WhatsApp LLC | named | 2 | **Yes** - WhatsApp LLC ships 2 apps |
| King | named | 13 | **Yes** - complete |
| Microsoft Corporation | named | 20 | Page cap reached |
| Google LLC | named | 20 | Page cap reached |
| Google LLC | numeric `dev?id=` | 10 | Page cap reached |

So: for a small or mid-size publisher you get the complete portfolio. For a giant you get the first page, around 20 apps.

Every row carries a **`portfolioComplete`** boolean so you can tell the two cases apart instead of guessing. It is `true` when the page returned fewer apps than its own cap, which means nothing was cut off.

A tool that claims "all apps by any publisher" from this source is claiming something the source does not serve. The honest version is: complete for most publishers, first page for the giants, and the row tells you which.

**Named pages return more than numeric ones.** `developer?id=Google+LLC` gave 20 apps while `dev?id=5700313618786177705` gave 10 for the same publisher. Prefer the publisher's name when you have it.

### What you get per app

Base fields, present on every row - verified 25/25 in a live run:

| Field | What it holds |
|---|---|
| `developerQuery` | What you asked for, so mixed runs stay traceable |
| `developer` | Publisher name as Google spells it |
| `country` / `language` | The `gl` and `hl` used |
| `appId` | Package name, for example `com.king.candycrushsaga` |
| `title` | App name |
| `score` / `scoreText` | Rating as a number and as Google displays it |
| `genre` | Category |
| `installs` | Install band, for example `1,000,000,000+` |
| `price` / `currency` / `free` | Pricing. `price: 0` with `free: true` means free; `free` is `null` only when Google published no price block at all |
| `description` | Full store description |
| `iconUrl` / `appUrl` | Icon and store link |
| `portfolioComplete` | Whether the page cap was hit |
| `scrapedAt` | Collection timestamp |

With **`enrich: true`**, each app's own store page is loaded and these are merged in. Measured fill rates from a live 25-app run:

| Field | What it holds | Fill rate |
|---|---|---|
| `ratings` | Exact number of ratings | 25/25 |
| `reviews` | Exact number of written reviews | 25/25 |
| `realInstalls` / `minInstalls` | Numeric install figures, not the band | 25/25 |
| `contentRating` | Age rating | 25/25 |
| `containsAds` | Whether the listing declares ads | 25/25 |
| `updated` / `updatedTimestamp` | Last update date | 25/25 |
| `developerEmail` | Publisher support email | 25/25 |
| `developerWebsite` / `privacyPolicyUrl` | Publisher links | 25/25 |
| `recentChanges` | The "What's new" text | 25/25 |
| `inAppPurchaseRange` | Google's own localized display string | **16/25** |
| `inAppPurchaseMinPrice` / `inAppPurchaseMaxPrice` | The same range parsed into numbers, locale-aware | **16/25** |
| `offersInAppPurchases` | Boolean, derived from whether Google published a range | 25/25 |
| `version` | Version string | **15/25** |

Two of those need saying plainly.

**`inAppPurchaseRange` arrives on about 64% of apps** - the ones that actually sell in-app products. It is absent, correctly, on apps that do not.

That raw field is a localized display string and it is localized in every direction at once. The same app returns `$6.99 - $203.88 per item` in en/us, `6,99 € - 109,99 € bei Abrechnung über Google Play` in de/de, `R$ 18,90 - R$ 599,00 por item` in pt/br and `￥580～￥17,200/アイテム` in ja/jp - different separators, different decimal conventions, trailing prose. Sorting or filtering on that string is meaningless, so the numbers are extracted and parsed individually into `inAppPurchaseMinPrice` and `inAppPurchaseMaxPrice`, verified against all four of those formats. Use the parsed pair for analysis and keep the raw string for verification.

**`version` arrives on about 60% of apps.** Google shows "Varies with device" for a large share of big apps and publishes no version string at all for them. There is no setting that recovers it. If version tracking is what you need, the App Update Monitor handles this properly, including the date-based fallback for exactly this case.

### Input

```json
{
  "developers": ["King", "WhatsApp LLC", "5700313618786177705"],
  "countries": ["us", "gb"],
  "language": "en",
  "enrich": true,
  "maxItems": 200
}
```

Three identifier forms work and can be mixed in one run:

- Publisher name exactly as Google Play spells it: `King`, `WhatsApp LLC`
- Numeric developer ID: `5700313618786177705`
- Full developer page URL, either `/developer?id=` or `/dev?id=`

**Input aliases.** `developers` also accepts `developer`, `developerIds`, `developerId`, `publishers`, `devIds` and `urls`. `countries` also accepts `country` and `gl`. `language` also accepts `hl` and `lang`. `maxItems` also accepts `maxResults`, `limit` and `maxApps`. A comma separated string works anywhere a list does.

### Getting the publisher name right

The named developer page matches on the exact string Google Play uses, punctuation included. `WhatsApp LLC` works; `Whatsapp` does not. The reliable way to get it: open any app by that publisher on Google Play, click the developer name, and copy the `id=` value out of the URL.

If a page loads but carries no app cards, that is recorded in `FAILURES` with a note to check the spelling - it is almost always a name mismatch rather than a scraping problem.

### Competitor portfolio mapping

Most serious app companies do not ship one app - they ship a family. Mapping that family tells you things a single-app view cannot.

Run a competitor's publisher name with `enrich: true` and read the **Enriched details** view. Sorting by `realInstalls` shows you which app in their portfolio is actually the business and which are experiments. Sorting by `updated` shows which they are still investing in and which they have quietly abandoned. `containsAds` and `inAppPurchaseRange` across the set reveal their monetisation pattern - a studio that runs ads on twelve casual games and subscriptions on one premium app is telling you their whole strategy in one table.

### Finding a category's real owners

Take the top twenty apps in a Play category, look up each publisher here, and the concentration becomes visible. Categories that look like twenty independent apps are frequently five studios with four apps each. That changes how you assess the competition and, if you are looking to buy or partner, who you actually need to talk to.

### Building a publisher contact list

With `enrich: true`, `developerEmail` came back on 25 of 25 apps. Google Play requires a support contact on every listing, which makes the developer page an unusually reliable source for reaching app publishers - far better than guessing addresses from a website.

Combined with `realInstalls` and `score`, you can filter to publishers of a specific size and quality before you contact anyone. Please respect anti-spam law wherever you and the recipient are.

### Cross-store portfolio comparison

Pair this with the App Store side. Run a publisher here to get their Android catalogue, then look them up on Apple. Apps that exist on one store and not the other are either a platform strategy or a gap - and if a competitor is Android-only in a category you serve on iOS, that is a market position nobody is contesting.

### How this actor behaves when something goes wrong

1. **Errors never enter the dataset.** A developer page that does not exist, a name that does not match, or a page that loads with no app cards - each is recorded in a `FAILURES` key-value record with the exact reason. None becomes a dataset row, because a row that says "error" would bill you for receiving an error.
2. **A run that delivered nothing is marked FAILED**, not SUCCEEDED.
3. **A failed enrichment never loses the row.** If an individual app page cannot be read, the base portfolio row is still delivered, `enriched` stays `false`, and the enrichment event is not charged for it.
4. **The parser handles both developer page layouts.** Google renders the named page and the numeric page with different internal structures; this actor reads app cards structurally rather than assuming one layout, so both work and neither breaks when Google reshuffles the page.
5. **The free tier returns data.** Proxy is optional and off by default.

### Pricing

Pay per event.

- **$0.0008 per app listed** - $0.80 per 1,000 apps.
- **$0.002 per app enriched**, charged only when `enrich` is on and only for apps whose details actually came back.

No subscription, no charge for starting a run. Mapping 20 competitor publishers at roughly 15 apps each, fully enriched, is about 300 apps for **$0.84**. `maxItems` is a hard ceiling on both rows and spend.

### Output sample

```json
{
  "developerQuery": "King",
  "developer": "King",
  "country": "us",
  "language": "en",
  "appId": "com.king.candycrushsaga",
  "title": "Candy Crush Saga",
  "score": 4.6282,
  "scoreText": "4.6",
  "genre": "Casual",
  "installs": "1,000,000,000+",
  "realInstalls": 1289456331,
  "ratings": 32847112,
  "reviews": 1204883,
  "price": 0,
  "currency": "USD",
  "free": true,
  "containsAds": true,
  "inAppPurchaseRange": "$0.99 - $199.99 per item",
  "contentRating": "Everyone",
  "version": "1.302.0.1",
  "updated": "Aug 18, 2026",
  "updatedTimestamp": "2026-08-18T11:04:22.000Z",
  "recentChanges": "New levels and bug fixes.",
  "developerEmail": "candycrushsaga@king.com",
  "developerWebsite": "https://king.com/",
  "privacyPolicyUrl": "https://king.com/privacyPolicy",
  "iconUrl": "https://play-lh.googleusercontent.com/JvMhIxuwArVmcMReJQB8...",
  "appUrl": "https://play.google.com/store/apps/details?id=com.king.candycrushsaga",
  "portfolioComplete": true,
  "enriched": true,
  "scrapedAt": "2026-08-22T04:18:55.417Z"
}
```

### Dataset views

- **Portfolio** - developer, app, package, rating, installs, category, price. The catalogue.
- **Enriched details** - exact ratings and reviews, real installs, ads flag, IAP range, content rating, last update, email and website. Populated when `enrich` is on.

### Frequently asked questions

**Will I get every app a publisher has?** For small and mid-size publishers, yes - King returned 13 of 13, WhatsApp LLC 2 of 2. For very large publishers you get the first page, around 20 apps. `portfolioComplete` tells you which case you are in.

**Should I use the name or the numeric ID?** The name. Named pages returned 20 apps where the numeric page returned 10 for the same publisher.

**Do I need the Play Developer API?** No. That only covers apps you own. This works on any public publisher page.

**Why is `version` empty for some apps?** Google shows "Varies with device" for many large apps and publishes no version string. About 40% of a live sample. Use the App Update Monitor if version tracking is the goal.

**Do I need a proxy?** No. Verified: Google Play answers these pages anonymously with no proxy and no Cloudflare challenge.

**Can I run several publishers at once?** Yes, and across several countries. Availability differs per country, so the same publisher can return different portfolios in different markets.

### Related actors

- **Google Play Reviews Scraper** - reviews in any country and language, with developer replies.
- **App Update Monitor** - new versions and release notes across iOS and Android, with change detection.
- **App Store App Details Scraper** - the Apple-side equivalent, including in-app purchase names and prices.
- **App Store Top Charts Scraper** - Free, Paid and Grossing charts by country and category.

# Actor input Schema

## `developers` (type: `array`):

Publisher names exactly as Google Play spells them ("King", "WhatsApp LLC"), numeric developer IDs, or full developer page URLs. Aliases: developer, developerIds, publishers, devIds.

## `countries` (type: `array`):

Google Play country codes (gl). Portfolios differ per country because availability does. Aliases: country, gl.

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

Google Play language code (hl). Aliases: hl, lang.

## `enrich` (type: `boolean`):

Adds installs count, review count, content rating, last update date, release notes, developer email and website by loading each app page. Slower and costs one extra event per app.

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

Hard ceiling on apps delivered and therefore on what you are charged.

## `proxyConfiguration` (type: `object`):

Not required.

## Actor input object example

```json
{
  "developers": [
    "King",
    "WhatsApp LLC"
  ],
  "countries": [
    "us"
  ],
  "language": "en",
  "enrich": false,
  "maxItems": 200,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per app in the developer portfolio, with installs, rating, price and update date.

# 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 = {
    "developers": [
        "King",
        "WhatsApp LLC"
    ],
    "countries": [
        "us"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("renzomacar/google-play-developer-scraper").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 = {
    "developers": [
        "King",
        "WhatsApp LLC",
    ],
    "countries": ["us"],
}

# Run the Actor and wait for it to finish
run = client.actor("renzomacar/google-play-developer-scraper").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 '{
  "developers": [
    "King",
    "WhatsApp LLC"
  ],
  "countries": [
    "us"
  ]
}' |
apify call renzomacar/google-play-developer-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/eY8to60RZqh0jdNjc/builds/JZ1BGf63sW3rg89PY/openapi.json
