All posts
GuideJul 8, 2026 · 8 min

How to Scrape Google Play Reviews With Python (and When Not To)

Working google-play-scraper code with pagination and rate-limit tips — plus the honest ToS caution and why scraping gets you data, not a reply workflow.

RA

The Argus Team

Reply Argus

The fastest way to scrape Google Play reviews in Python is the `google-play-scraper` package: `pip install google-play-scraper`, call `reviews()` with a package name, and page through the results with the continuation token it hands back. Copy-paste code is below, and it works. But before you wire a pipeline on top of it, two things are worth knowing up front.

First, it's an unofficial scraper — it reads Google Play's internal web endpoints, so it can break the week Google changes them, and automated scraping runs against Google's Terms of Service. Second, and this is the part people learn the hard way: it gives you a pile of read-only data, not a way to actually reply. If your goal is competitor research or a one-off dataset, scraping is the right tool. If the reviews are on your own app and you need to answer them, you want a different door entirely. Here's both.

Which Python library, and what it gives you

There are a few options, but the one people actually reach for is `google-play-scraper` (the JoMingyu package on PyPI). No API key, no OAuth, no Play Console access — you hand it a package name and it returns a list of review dicts. That zero-friction setup is exactly why it's fragile and why it isn't an official supported interface: it's reading the same JSON payloads the Play website loads, not a documented API surface with a stability contract.

The `app_id` it wants is the `?id=` value from a Play Store URL. For `play.google.com/store/apps/details?id=com.spotify.music`, the id is `com.spotify.music`. Every review is scoped to a language and a storefront, so the same app returns different reviews for `country="us", lang="en"` than for `country="br", lang="pt"`. There's no single global firehose — you scrape one storefront-language pair at a time.

python
# pip install google-play-scraper
from google_play_scraper import reviews, Sort

# app_id is the ?id= value from the Play Store URL:
# play.google.com/store/apps/details?id=com.spotify.music
result, token = reviews(
    "com.spotify.music",
    lang="en",              # language of the reviews to return
    country="us",           # storefront to read from
    sort=Sort.NEWEST,       # NEWEST | MOST_RELEVANT | RATING
    count=200,              # ~200 is the practical max per call
    filter_score_with=None, # or 1..5 to pull a single star rating
)

for r in result[:3]:
    print(r["score"], r["at"], r["content"][:70])
The basic fetch. reviews() returns a (list, continuation_token) tuple — the token is how you get the next page.

How pagination actually works

`reviews()` returns a tuple: the batch of reviews plus a continuation token. To get the next page, you pass that token back in. The token encodes the whole query — sort, filters, storefront — so on continuation calls you don't repeat those params; the token carries them. Loop until a call comes back empty, and add a small `sleep` between requests so you're not hammering the endpoint from a single IP.

There's a shortcut for "just get everything": `reviews_all()` handles the paging internally. It's convenient, but it can be slow and memory-heavy on a popular app with hundreds of thousands of reviews, and it gives you less control over when to stop. For anything beyond a quick pull, the explicit token loop is the one to keep.

python
from google_play_scraper import reviews, Sort
import time

app_id = "com.spotify.music"
all_reviews, token = [], None

while True:
    batch, token = reviews(
        app_id,
        lang="en",
        country="us",
        sort=Sort.NEWEST,
        count=200,
        continuation_token=token,  # None on the first call
    )
    all_reviews.extend(batch)
    if not batch:                  # storefront exhausted
        break
    time.sleep(1)                  # be gentle with the endpoint

print(f"pulled {len(all_reviews)} reviews")
The controlled pagination loop. Break when a batch comes back empty; sleep between calls to avoid rate-limit blocks.
python
from google_play_scraper import reviews_all, Sort

# Handles pagination for you. Convenient, but heavy on big apps.
result = reviews_all(
    "com.spotify.music",
    sleep_milliseconds=200,   # pause between internal requests
    lang="en",
    country="us",
    sort=Sort.MOST_RELEVANT,
    filter_score_with=1,      # e.g. only 1-star reviews
)
reviews_all() is the one-liner when you want the whole storefront and don't need to manage the loop yourself.

What's inside each review

Each item in the list is a plain dict. The fields you'll actually use:

  • `reviewId` — stable unique id; use it to dedupe across runs so you don't re-ingest the same review.
  • `score` — the star rating, an integer 1 to 5.
  • `content` — the review text itself (can be empty; plenty of ratings carry no words).
  • `at` — a Python `datetime` of when the review was posted. Sort or window on this.
  • `userName` — the public display name. That's the only user identifier you get; there's no email, no PII.
  • `thumbsUpCount` — how many people found the review helpful, a rough proxy for how loud a complaint is.
  • `reviewCreatedVersion` — the app version the reviewer was on, gold for triaging a regression.
  • `replyContent` and `repliedAt` — the developer's existing reply and its timestamp, or `None` if nobody has answered yet.

Is scraping Google Play reviews against the Terms of Service?

Honestly: automated scraping runs against Google's Terms of Service, which prohibit accessing the service through automated means outside their published APIs. `google-play-scraper` doesn't use a published API — it reads the site's internal endpoints. That doesn't mean your machine bursts into flames when you run it; a modest, well-behaved pull for research is a very different risk profile from a commercial product built on continuous scraping. But be clear-eyed that you're relying on undocumented behavior with no stability promise and no support channel when it breaks.

The practical failure mode isn't a lawyer — it's the endpoint. Scrape too fast from one IP and Google starts returning empty results or throttling you. There's no published rate limit to code against, so you treat it like any polite crawler: pace your requests, cache aggressively, and never re-fetch what you already have.

Scrape like a good citizen, or get soft-blocked

Add a real delay between calls (start at ~1s, back off if results go empty). Dedupe on reviewId so a re-run isn't a re-scrape. Scope to the storefront-language pairs you actually need instead of looping every country. And pin the package version — an unofficial scraper breaks when the site changes, so a working build today is worth locking down.

When NOT to scrape: your own app has an official door

Here's the when-not-to. If the reviews you want are on an app you own, do not scrape them. Google publishes a real, supported interface — the Google Play Developer Reviews API (`reviews.list`, `reviews.get`, `reviews.reply`) — that authenticates with a service account, returns the reviews on your own apps, and, unlike any scraper, lets you post a reply back. It's ToS-compliant by definition, it doesn't break when the website's markup shifts, and it's the only path that can actually answer a customer. We break down its exact params and quirks in the [Google Play Reviews API reference](/blog/google-play-reviews-api-reference).

One hard number to design around: a Google Play developer reply is capped at 350 characters — that's a firm limit in both the console and the API, and it's tighter than the App Store's, where Apple publishes no official ceiling at all. Any reply tooling you build has to respect it. The scraper, of course, can't reply at all; the `replyContent` field just tells you whether someone already did. If replying is the goal — and for your own app it usually is — a read-only scrape is the wrong shape entirely. The two stores behave differently enough that it's worth reading [how App Store and Google Play review replies compare](/blog/app-store-vs-google-play-review-replies) before you commit to either.

Scraping gets you data. It doesn't get you a workflow.

Say you scrape 40,000 reviews and load them into a notebook. Now what? You have a CSV. You still have to cluster the complaints, decide which ones need a human, write a reply that sounds like your brand, translate it into whatever language the reviewer used, keep it under 350 characters, and — for your own app — push it back through the official API without letting anything lapse during a busy week. The scrape was the easy 10%. The workflow is the other 90%, and it's the part that actually moves your rating: Google said at I/O 2019 that developers who respond see about +0.7 stars on average. A dataset sitting in a notebook moves nothing.

That gap is the whole reason [ReplyArgus](/features) exists. It connects to your Play Console (and App Store Connect) through the official supported path — no scraping your own store — watches both stores in one inbox, and drafts a reply grounded in your past approved replies plus an auto-ingested knowledge base of your listing and marketing pages. It writes in the reviewer's own language, both directions, and keeps Play replies inside the 350-character limit for you. You approve each one, or set rules to auto-publish the easy cases by rating or keyword. It's the workflow the scraper was never going to give you.

Latest update logs me out every few hours and my downloaded playlists disappear. Basically unusable on my commute now.

Reply

That log-out loop is on us and it's fixed in 8.9.2, rolling out this week. Your downloads shouldn't clear on sign-in — if they still do after updating, tap Settings > Storage > Repair. Sorry for the rough commute; we want it back to one tap.

The agent-native version: reviews as structured input

If you're comfortable in Python, you're probably comfortable in Claude or Cursor. ReplyArgus ships an [MCP connector](/agentic-tools) that hands your agent structured reviews and drafted replies directly — pull the unanswered 1-stars, cluster them by theme, draft grounded responses, queue them for approval — no scraper, no brittle HTML parsing, no ToS gray zone. It's the same data a scrape would give you, except it's live, official, and reply-capable. The [app reviews MCP guide](/blog/app-reviews-mcp) walks through every tool it exposes.

Start free — skip the scraper for your own app

Connect your Play Console and ReplyArgus drafts your first grounded reply in minutes — on the official API, not a scrape. Free plan, no card required. [Start free](/signup).

Frequently asked

What's the best Python library to scrape Google Play reviews?
google-play-scraper (the JoMingyu package on PyPI). Install it with pip install google-play-scraper, then call reviews() with the app's package name to get a list of review dicts plus a continuation token for paging. It needs no API key, but it's an unofficial scraper that reads Google's internal endpoints, so it can break without notice.
Is scraping Google Play reviews legal or against the ToS?
Automated scraping runs against Google's Terms of Service, which restrict accessing the service through automated means outside its published APIs. A small research pull is low-risk in practice, but building a commercial product on continuous scraping is a real ToS and reliability liability. For apps you own, use the official Google Play Developer Reviews API instead.
How do I get all the reviews, not just the first page?
reviews() returns a continuation token; pass it back on the next call and loop until a batch comes back empty, sleeping ~1 second between calls. Or use reviews_all(), which handles pagination for you — convenient, but slow and memory-heavy on apps with hundreds of thousands of reviews. Reviews are scoped per storefront and language, so there's no single global list.
How many reviews can I scrape before getting blocked?
There's no published rate limit because it isn't an official API. Scrape too aggressively from one IP and Google starts returning empty results or throttling you. Pace your requests, dedupe on reviewId so re-runs aren't re-scrapes, and scope to only the storefront-language pairs you need.
Can I reply to reviews with a scraper?
No. google-play-scraper is read-only — it can tell you whether a review already has a developer reply (the replyContent field), but it can't post one. To reply programmatically you need the official Google Play Developer Reviews API, which authenticates with a service account and enforces the 350-character reply limit. Tools like ReplyArgus wrap that official path and add drafting on top.
What's the difference between scraping and the official Reviews API?
Scraping reads public review data for any app with no auth, but it's unofficial, breakable, read-only, and against Google's ToS. The official Google Play Developer Reviews API covers only apps you own, requires a service account, is stable and supported, and can post replies. Scrape for competitor research; use the official API for your own apps.

Try it

Let Argus draft your next reply.

Watch it answer a real review in your voice. 10-day trial, no card to begin.

See the features or pricing.

Keep reading