# Google Play Review Pain Miner (`creative_maitake/google-play-review-pain-miner`) Actor

Mine low-star public Google Play reviews into scored product pain points and grouped app opportunity ideas.

- **URL**: https://apify.com/creative\_maitake/google-play-review-pain-miner.md
- **Developed by:** [Brian Murray](https://apify.com/creative_maitake) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Review Pain Miner

Find product pain points and app ideas by mining low-star public Google Play reviews.

This Actor searches public Google Play results for a keyword/category, fetches recent public reviews for matching apps, filters to low-star reviews, classifies complaints with transparent deterministic rules, and outputs both review-level rows and grouped opportunity summaries.

### What you can use it for

- Android app idea research
- Competitor complaint mining on Google Play
- Cross-platform niche validation alongside the App Store version
- Product backlog discovery
- Pricing/UX/support/reliability pain scans
- Lightweight market research before building or buying an app business

Low-star reviews often reveal paid-pain patterns: subscription resentment, unreliable sync, confusing workflows, missing integrations, poor support, or privacy concerns.

### Why this Actor is useful

Most app research starts with top-line ratings and category rankings, but those hide the reasons users churn or refuse to pay. This Actor helps you quickly answer:

- Which competitors are frustrating users the most?
- Are complaints mostly about pricing, reliability, UX, support, or missing features?
- Are multiple apps in a niche failing in the same way?
- Is there a focused wedge for a simpler Android alternative?

Use it as a triage tool to spot candidate niches, then read the source reviews before making product decisions.

### Example input

```json
{
  "query": "habit tracker",
  "country": "us",
  "language": "en",
  "maxApps": 5,
  "maxReviewsPerApp": 40,
  "maxReviewRating": 3,
  "includeUnknown": false
}
````

### Input fields

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `query` | string | required | Google Play keyword/category to search, e.g. `habit tracker`, `budget app`, `invoice maker`. |
| `country` | string | `us` | Two-letter Google Play country code. Invalid values fall back to `us`. |
| `language` | string | `en` | Language code used for Google Play search/reviews, e.g. `en`, `es`, `de`. |
| `maxApps` | integer | `5` | Number of search results to inspect. Capped at 25. |
| `maxReviewsPerApp` | integer | `25` | Number of recent reviews per app to inspect. Capped at 100. |
| `maxReviewRating` | integer | `3` | Only include reviews at or below this star rating. |
| `includeUnknown` | boolean | `false` | Include low-star reviews that do not match a known pain category. |

### Output

#### Dataset: review-level pain points

Each dataset row is one public Google Play review with classification metadata:

```json
{
  "reviewKey": "com.example.app:gp-review-123",
  "appId": "com.example.app",
  "appName": "Habit Hero",
  "developer": "Acme Apps",
  "appRating": 4.6,
  "appUrl": "https://play.google.com/store/apps/details?id=com.example.app",
  "reviewTitle": null,
  "reviewText": "Costs too much for a simple habit tracker...",
  "reviewRating": 1,
  "painCategory": "pricing",
  "confidence": 0.75,
  "severity": 1.0,
  "opportunityScore": 0.88,
  "matchedTerms": ["expensive", "subscription"],
  "painSummary": "Pricing pain: Costs too much for a simple habit tracker...",
  "opportunity": "Offer a clearer, cheaper, or one-time-purchase alternative with fewer ads and transparent limits."
}
```

#### Key-value output: grouped opportunities

The Actor also writes `OPPORTUNITIES`, a grouped list by app and pain category. This is usually the best starting point for research triage:

```json
{
  "appName": "Strong Workout Tracker Gym Log",
  "painCategory": "reliability",
  "reviewCount": 7,
  "averageConfidence": 0.81,
  "averageSeverity": 0.87,
  "opportunityScore": 0.84,
  "matchedTerms": ["crashes", "sync", "won't connect"],
  "topPainSummaries": ["Reliability pain: ..."],
  "opportunity": "Differentiate on stability, fast bug fixes, dependable sync, and trustworthy data handling."
}
```

The `SUMMARY` key includes run metadata and the top 10 opportunity groups.

### Pain categories

| Category | Detects | Opportunity angle |
| --- | --- | --- |
| `pricing` | subscriptions, expensive plans, paywalls, ads | clearer pricing, cheaper tiers, one-time purchase, fewer ads |
| `reliability` | crashes, bugs, broken sync, connection failures, lost data | stable sync, data safety, fast bug fixes |
| `ux` | confusing UI, clunky flows, too many steps | simpler workflow and opinionated defaults |
| `features` | missing features, imports/exports/integrations | focused workflow or integration gap |
| `support` | customer support, refunds, no response | responsive support and visible changelogs |
| `privacy` | privacy/tracking/permissions/personal data | privacy-first positioning and local-data options |
| `unknown` | unmatched low-star reviews | manual review when `includeUnknown` is enabled |

### How to read the scores

- `confidence`: how specifically the review matched the category keywords.
- `severity`: rating-derived pain score; 1-star reviews score highest.
- `opportunityScore`: average of confidence and severity, useful for sorting.

Scores are triage signals, not proof of market demand. Always read the source `reviewText` before making product decisions.

### Dogfood results from MVP validation

The Actor found useful opportunity clusters in real Google Play scans, including:

- `budget app`: sync failures, deceptive trial/pricing language, support frustration.
- `invoice maker`: subscription creep, paywalls, business-impacting reliability problems.
- `receipt scanner`: annual-price complaints, feature/export gaps, simplified workflow opportunities.
- `calendar`: sync issues, ads/subscription resentment, import/missing-feature complaints.
- `workout tracker`: import/export gaps and repeated reliability/login issues.

Classifier pass #2 reduced several noisy false positives:

- generic `need` no longer implies a feature request
- generic `tracking` no longer implies a privacy complaint
- weak `premium` mentions lose to stronger reliability evidence
- generic `wish` phrasing no longer becomes a features complaint by itself

These results are promising enough for private beta, with the caveat that classification remains deterministic and should be used for triage.

### Notes and limitations

- Uses public Google Play metadata and reviews via `google-play-scraper`.
- Does not log in to Google, bypass access controls, or collect private data.
- Classification is deterministic keyword/pattern matching, not LLM analysis. This keeps runs cheap and explainable.
- Broad search queries can still pull in adjacent apps.
- Some review text is ambiguous; always read the underlying review before making product decisions.
- Results are best for triage and pattern-finding, not as a standalone market-size estimate.

### Suggested workflow

1. Start with a niche query such as `habit tracker`, `invoice maker`, or `receipt scanner`.
2. Review `OPPORTUNITIES` first to see which apps and pain categories cluster together.
3. Open the highest-scoring review rows in the dataset to verify whether the complaint is real and repeated.
4. Compare the same niche against the App Store Review Pain Miner to see whether the pain is Android-specific or cross-platform.
5. Convert repeated complaints into hypotheses for product positioning, pricing, or feature scope.

### Local development

```bash
PYTHONPATH=. python -m pytest tests/test_pain_miner.py -q
apify validate-schema
apify run --purge
```

### Deployment

```bash
apify push
```

### Status

This is a strong private-beta candidate derived from the published App Store Review Pain Miner pattern. It is not published yet.

# Actor input Schema

## `query` (type: `string`):

Keyword or app category to search in public Google Play results, e.g. habit tracker, budget app, invoice maker.

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

Two-letter Google Play country code.

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

Language code used for Google Play search and reviews, e.g. en, es, de.

## `maxApps` (type: `integer`):

Number of Google Play search results to inspect. Capped at 25.

## `maxReviewsPerApp` (type: `integer`):

Number of recent reviews to inspect for each app. Capped at 100.

## `maxReviewRating` (type: `integer`):

Only include reviews at or below this star rating, because low reviews are best for pain mining.

## `includeUnknown` (type: `boolean`):

If enabled, include low-star reviews that do not match a known pain category.

## Actor input object example

```json
{
  "query": "habit tracker",
  "country": "us",
  "language": "en",
  "maxApps": 5,
  "maxReviewsPerApp": 25,
  "maxReviewRating": 3,
  "includeUnknown": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `opportunities` (type: `string`):

No description

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

No description

# 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 = {
    "query": "habit tracker",
    "country": "us",
    "language": "en"
};

// Run the Actor and wait for it to finish
const run = await client.actor("creative_maitake/google-play-review-pain-miner").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 = {
    "query": "habit tracker",
    "country": "us",
    "language": "en",
}

# Run the Actor and wait for it to finish
run = client.actor("creative_maitake/google-play-review-pain-miner").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "query": "habit tracker",
  "country": "us",
  "language": "en"
}' |
apify call creative_maitake/google-play-review-pain-miner --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=creative_maitake/google-play-review-pain-miner",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Play Review Pain Miner",
        "description": "Mine low-star public Google Play reviews into scored product pain points and grouped app opportunity ideas.",
        "version": "0.2",
        "x-build-id": "g7fepYdROvEOFviSU"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/creative_maitake~google-play-review-pain-miner/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-creative_maitake-google-play-review-pain-miner",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/creative_maitake~google-play-review-pain-miner/runs": {
            "post": {
                "operationId": "runs-sync-creative_maitake-google-play-review-pain-miner",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/creative_maitake~google-play-review-pain-miner/run-sync": {
            "post": {
                "operationId": "run-sync-creative_maitake-google-play-review-pain-miner",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "query"
                ],
                "properties": {
                    "query": {
                        "title": "Google Play search query",
                        "type": "string",
                        "description": "Keyword or app category to search in public Google Play results, e.g. habit tracker, budget app, invoice maker."
                    },
                    "country": {
                        "title": "Country code",
                        "type": "string",
                        "description": "Two-letter Google Play country code.",
                        "default": "us"
                    },
                    "language": {
                        "title": "Language code",
                        "type": "string",
                        "description": "Language code used for Google Play search and reviews, e.g. en, es, de.",
                        "default": "en"
                    },
                    "maxApps": {
                        "title": "Maximum apps to inspect",
                        "minimum": 1,
                        "maximum": 25,
                        "type": "integer",
                        "description": "Number of Google Play search results to inspect. Capped at 25.",
                        "default": 5
                    },
                    "maxReviewsPerApp": {
                        "title": "Maximum recent reviews per app",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Number of recent reviews to inspect for each app. Capped at 100.",
                        "default": 25
                    },
                    "maxReviewRating": {
                        "title": "Maximum review rating",
                        "minimum": 1,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Only include reviews at or below this star rating, because low reviews are best for pain mining.",
                        "default": 3
                    },
                    "includeUnknown": {
                        "title": "Include unclassified reviews",
                        "type": "boolean",
                        "description": "If enabled, include low-star reviews that do not match a known pain category.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
