     [Blog](https://scrapfly.io/blog)   /  [hidden-api](https://scrapfly.io/blog/tag/hidden-api)   /  [How to Scrape Google Play App Reviews and Data](https://scrapfly.io/blog/posts/how-to-scrape-google-play-app-reviews-and-data)   # How to Scrape Google Play App Reviews and Data

 by [Hisham Medhat](https://scrapfly.io/blog/author/hisham) Aug 03, 2026 15 min read [\#hidden-api](https://scrapfly.io/blog/tag/hidden-api) [\#python](https://scrapfly.io/blog/tag/python) [\#scrapeguide](https://scrapfly.io/blog/tag/scrapeguide) 

 [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-google-play-app-reviews-and-data "Share on LinkedIn") [  ](https://x.com/intent/tweet?url=https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-google-play-app-reviews-and-data&text=How%20to%20Scrape%20Google%20Play%20App%20Reviews%20and%20Data "Share on X") [  ](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-google-play-app-reviews-and-data "Share on Facebook")    

 

 

Summarize this article with

 [  ](https://chat.openai.com/?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-google-play-app-reviews-and-data) [  ](https://claude.ai/new?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-google-play-app-reviews-and-data) [  ](https://x.com/i/grok?text=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-google-play-app-reviews-and-data) [  ](https://www.perplexity.ai/search/new?q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-google-play-app-reviews-and-data) [  ](https://www.google.com/search?udm=50&aep=11&q=Summarize%20this%20article%20and%20explain%20how%20Scrapfly%20helps%20me%20scrape%20any%20website%20at%20scale%20and%20bypass%20anti-bot%20systems%20for%20my%20use%20case%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-google-play-app-reviews-and-data) 



         

   **Web Scraping API**Scrape any website with anti-bot bypass, proxy rotation, and JS rendering.

 

 [ Learn More  ](https://scrapfly.io/products/web-scraping-api) [  Docs ](https://scrapfly.io/docs/scrape-api/getting-started) 

 

 

You `pip install google-play-scraper`, call `reviews_all()`, and get a few hundred reviews for an app with hundreds of thousands. The library isn't broken. Google Play won't hand the full set over easily, and firing it harder from one IP only gets you throttled.

Getting every review is a pagination and anti-bot problem, not a parsing one. Metadata comes back in a single request, and the reviews page cleanly with Google Play's own continuation tokens. What decides whether you finish is what Google does to your IP a few hundred requests in.

[How to Scrape Infinite Scroll, Load More &amp; Paginated PagesLearn to scrape infinite scroll, load more, and paginated pages in 2026 by reverse-engineering the request first and using a browser only when you must.](https://scrapfly.io/blog/posts/how-to-scrape-infinite-scroll-load-more-and-paginated-pages)



[**Latest Google Play Scraper Code**github.com/scrapfly/scrapfly-scrapers/tree/main/google-play-scraper](https://github.com/scrapfly/scrapfly-scrapers/tree/main/google-play-scraper)

## Key Takeaways

- **Ratings are not reviews.** Spotify shows 36M star taps against 1.8M text reviews.
- **App data is server-rendered.** One request returns metadata and the ratings histogram.
- **Reviews sit behind `batchexecute`.** A continuation token walks them batch by batch.
- **The ceiling is your IP, not your code.** The free library pages from one address.
- **Rotation is the fix.** The [Web Scraping API](https://scrapfly.io/products/web-scraping-api) gives every request a fresh IP.
- **Search fills the queue.** `store/search?q=...&c=apps` resolves app IDs you don't have.
- **Reviews land analysis-ready.** A DataFrame per app, or the Extraction API across many.

**Get web scraping tips in your inbox**Trusted by 100K+ developers and 30K+ enterprises. Unsubscribe anytime.







## What Data Can You Scrape From Google Play?

Google Play exposes four kinds of public data: app metadata, the full ratings histogram, user reviews, and search or category listings. All of it comes from the store's own web responses, so you skip any login or official developer account.

Metadata and the histogram support competitive monitoring and app store optimization (ASO). Reviews feed sentiment analysis and feature mining. Search and category listings build the list of apps to track in the first place.

The fields below use the same names the community `google-play-scraper` library returns, so they line up with output you may already have seen:

| Data type | Key fields | Typical use |
|---|---|---|
| App metadata | `title`, `developer`, `genre`, `installs`, `realInstalls`, `version`, `released` | Competitive monitoring, ASO |
| Ratings | `score`, `ratings`, `reviews`, `histogram` | Trend tracking, benchmarking |
| Reviews | `userName`, `score`, `content`, `at`, `appVersion`, `thumbsUpCount` | Sentiment analysis, feature requests |
| Search / category | `appId`, `title`, `score`, `developer`, `installs` | Discovering apps to track |

An app's `ratings` count (star taps) is far larger than its `reviews` count (written text). Mixing the two up makes your numbers look wrong.

A live Spotify pull on 2026-07-30 showed roughly 36 million ratings against 1.8 million text reviews. The library's PyPI example shows the same gap for Pokemon GO, about 15.2 million ratings versus 970,000 reviews.

You paginate the smaller text-review set. At 1.8 million entries it is still far more than one IP will be allowed to fetch.

Fetching the app page is where the work starts.



## How to Fetch Google Play App Data With the Web Scraping API

Fetch the app page through the [Web Scraping API](https://scrapfly.io/products/web-scraping-api) with `asp=True` and parse the JSON embedded in the HTML. The app data is server-rendered, so you don't need a headless browser.

Google Play is not shielded like a Cloudflare or DataDome site. A plain request returns the page at low cost, and the only real barrier appears later, when you pull reviews at volume.

Install the Scrapfly SDK before the first snippet:

bash```bash
pip install scrapfly-sdk
```



### Fetch the app page and parse its embedded JSON

The app ID is the reverse-DNS package name from the Play URL's `?id=` parameter, such as `com.spotify.music`. You request `store/apps/details?id=<appId>&hl=<lang>&gl=<country>` and get back HTML that carries the data in `AF_initDataCallback` arrays.

python```python
from scrapfly import ScrapflyClient, ScrapeConfig

client = ScrapflyClient(key="YOUR_SCRAPFLY_KEY")

app_id = "com.spotify.music"
result = client.scrape(ScrapeConfig(
    url=f"https://play.google.com/store/apps/details?id={app_id}&hl=en&gl=us",
    asp=True,
    country="US",
))
print(result.status_code)  # 200
print("batchexecute" in result.content)  # False -> reviews are not on this page
```



The request returns `200` with `asp=True` on the default datacenter pool, and `batchexecute` never appears in the page. Access is easy, and the reviews live somewhere else.

The app details sit inside `AF_initDataCallback` script blocks as nested arrays. You pull the `ds:` datasets out with a small regex, then read fields by their index path.

python```python
import re, json
from html import unescape
from urllib.parse import parse_qs, urlparse

_SCRIPT_RE = re.compile(r"AF_initDataCallback[\s\S]*?</script")
_KEY_RE = re.compile(r"(ds:.*?)'")
_VALUE_RE = re.compile(r"data:([\s\S]*?), sideChannel: {}}\);<\/")


def parse_af_init_data(html):
    dataset = {}
    for match in _SCRIPT_RE.findall(html):
        keys, values = _KEY_RE.findall(match), _VALUE_RE.findall(match)
        if keys and values:
            try:
                dataset[keys[0]] = json.loads(values[0])
            except json.JSONDecodeError:
                continue
    return dataset


def get(obj, path, default=None):
    for i in path:
        try:
            obj = obj[i]
        except (IndexError, KeyError, TypeError):
            return default
    return obj


def parse_app(html, url):
    data = parse_af_init_data(html)
    app = get(data, ["ds:5", 1, 2]) or []
    histogram = get(app, [51, 1]) or []
    return {
        "title": get(app, [0, 0]),
        "developer": get(app, [68, 0]),
        "genre": get(app, [79, 0, 0, 0]),
        "installs": get(app, [13, 0]),
        "realInstalls": get(app, [13, 2]),
        "score": get(app, [51, 0, 1]),
        "ratings": get(app, [51, 2, 1]),
        "reviews": get(app, [51, 3, 1]),
        "histogram": [histogram[i][1] for i in range(1, 6)] if len(histogram) > 5 else [0] * 5,
        "version": get(app, [140, 0, 0, 0]) or "Varies with device",
        "released": get(app, [10, 0]),
        "appId": parse_qs(urlparse(url).query).get("id", [None])[0],
    }


print(json.dumps(parse_app(result.content, result.config["url"]), indent=2))
```



Those index paths look cryptic, but they're stable because they mirror the maintained `scrapfly-scrapers/google-play-scraper` module rather than a guess. Running it against Spotify returns real values:

json```json
{
  "title": "Spotify: Music and Podcasts",
  "developer": "Spotify AB",
  "genre": "Music & Audio",
  "installs": "1,000,000,000+",
  "realInstalls": 3069449940,
  "score": 4.340622,
  "ratings": 36025299,
  "reviews": 1846090,
  "histogram": [3700189, 1076931, 1326492, 3069724, 26851946],
  "version": "Varies with device",
  "released": "May 27, 2014",
  "appId": "com.spotify.music"
}
```



The `histogram` array reads one-star through five-star counts left to right. And `ratings` (36M) against `reviews` (1.8M) shows the earlier gap in live data.

### Where the open-source library fits (and where it stops)

The community `google-play-scraper` library wraps these same internal endpoints. It's by JoMingyu ([PyPI](https://pypi.org/project/google-play-scraper/) v1.2.7, June 2024, MIT, no dependencies), a fine way to start a quick one-off pull and a useful reverse-engineering reference.

Two limits are worth knowing before you lean on it. There has been no release since mid-2024. And every request leaves from your single IP, which is what caps it out and gets it throttled on big apps.



## Why You Can't Get All the Reviews (and How to Fix It)

Reviews come from Google Play's internal `batchexecute` RPC endpoint, paginated by a continuation token. The free library stalls because it fires that whole loop from one IP.

The app page confirmed it. `batchexecute` appears zero times in the HTML, so Google Play fetches the reviews separately after the page loads.

Finding that endpoint is a background-request capture exercise, the same technique that works on any hidden JSON API.

[Web Scraping Background Requests with Headless BrowsersIn this tutorial we'll be taking a look at a rather new and popular web scraping technique - capturing background requests using headless browsers.](https://scrapfly.io/blog/posts/web-scraping-background-requests-with-headless-browsers-and-python)

### Continuation tokens and how Google Play paginates reviews

A continuation token is a pointer Google Play returns with each batch that marks where the next batch begins.

You send a `POST` to `_/PlayStoreUi/data/batchexecute` and read the reviews plus the token from the response. Then you pass that token into the next request and repeat until it comes back empty.

The shape is the same token-based paging you'd meet on any infinite-scroll page. So the [endless paging](https://scrapfly.io/scrapeground/paging/endless) lesson and the broader [How to Scrape Hidden APIs](https://scrapfly.io/blog/posts/how-to-scrape-hidden-apis) pattern both apply here.

The one Google Play twist is the RPC envelope, which you mirror from the maintained module rather than hand-write.

python```python
import json
from urllib.parse import quote
from scrapfly import ScrapflyClient, ScrapeConfig

client = ScrapflyClient(key="YOUR_SCRAPFLY_KEY")
_XSSI = re.compile(r"\)]}'\n\n([\s\S]+)")


def parse_reviews(content):
    match = _XSSI.findall(content)
    if not match:
        return [], None
    payload = json.loads(json.loads(match[0])[0][2])
    reviews = []
    for item in payload[0] or []:
        if not item or not item[0]:
            continue
        reviews.append({
            "reviewId": item[0],
            "userName": get(item, [1, 0]),
            "content": get(item, [4]),
            "score": get(item, [2]),
            "thumbsUpCount": get(item, [6]),
            "at": get(item, [5, 0]),
            "appVersion": get(item, [10]),
        })
    token = payload[-2][-1] if len(payload) >= 2 and isinstance(payload[-2], list) and payload[-2] else None
    return reviews, None if isinstance(token, list) else token


def scrape_reviews(app_id, max_reviews=200, sort=2):
    url = "https://play.google.com/_/PlayStoreUi/data/batchexecute?hl=en&gl=us"
    reviews, seen, token = [], set(), None
    while len(reviews) < max_reviews:
        count = min(max_reviews - len(reviews), 4500)
        pagination = [count, None, token] if token is not None else [count]
        filters = [None, None, None, None, None, None, None, None, None]
        inner = json.dumps([None, [2, sort, pagination, None, filters], [app_id, 7]], separators=(",", ":"))
        body = "f.req=" + quote(json.dumps([[["oCPfdb", inner, None, "generic"]]], separators=(",", ":")) + "\n")
        resp = client.scrape(ScrapeConfig(
            url=url, method="POST",
            headers={"content-type": "application/x-www-form-urlencoded"},
            body=body, asp=True, country="US",
        ))
        page, token = parse_reviews(resp.content)
        for r in page:
            if r["reviewId"] not in seen:
                seen.add(r["reviewId"])
                reviews.append(r)
        if token is None or not page:
            break
    return reviews


reviews = scrape_reviews("com.spotify.music", max_reviews=200)
print(f"got {len(reviews)} reviews")
print(json.dumps(reviews[0], indent=2, ensure_ascii=False))
```



The loop de-duplicates on `reviewId` and stops when the token is empty or a batch returns nothing. Against Spotify it walks multiple batches and returns the requested set:

json```json
got 200 reviews
{
  "reviewId": "e2fbd3d5-5226-4b07-80de-cc456f15839b",
  "userName": "Covo Studios",
  "content": "I pay for premium to avoid ads and ive started to get ads again but still am paying for premium",
  "score": 1,
  "thumbsUpCount": 0,
  "at": 1785307648,
  "appVersion": null
}
```



The `at` field is a Unix timestamp, `appVersion` is null when the reviewer didn't attach a version, and `sort=2` requests newest first (use `1` for most relevant or `3` for rating).

### Why the open-source library stalls or gets throttled on big apps

The free library caps out because every request in that loop leaves from your single IP, and Google Play rate-limits by IP and identity.

Community reports line up here. One developer on r/learnpython (January 2025) ran the library against an app and got only a fraction of its reviews back before it stopped.

What developers see instead:

- Only a few hundred to a few thousand reviews come back, then nothing.
- The loop stops early even though the app has far more reviews.
- Requests get throttled or blocked after a burst from one address.
- A `503` with a CAPTCHA appears, and Google cools the IP off for a while.

A cleverer loop won't help. The same continuation-token loop survives once it runs through a request layer that rotates identity.

## How to Scrape Google Play Reliably at Scale

The loop itself is simple; surviving tens of thousands of paginated requests without getting rate-limited is the actual work. Since Google Play throttles by IP, the answer is pacing plus rotation.

A few habits keep a large review pull healthy:

- Pace requests gently and back off when you see a `429` or `503`.
- Checkpoint the continuation token to disk so a failed run resumes instead of restarting.
- Rotate identity per request so no single IP absorbs the whole job.

You get the rotation by routing the same `batchexecute` loop through the Web Scraping API with `asp=True`, exactly as the earlier review code already does.

Every request then presents a fresh browser fingerprint and a different IP, so the loop that stalled on a single address keeps running to completion.

That rotation is what the maintained `scrapfly-scrapers/google-play-scraper` module does, and it's why the code above scales while the local library does not.

The same fetch layer covers the rest of an app's data, and the apps you haven't found yet.



Scrapfly

#### Scale your web scraping effortlessly

Scrapfly handles proxies, browsers, and anti-bot bypass — so you can focus on data.

[Try Free →](https://scrapfly.io/register)## How to Scrape App Metadata and Search Results

Batch a list of app IDs through the Web Scraping API to pull metadata, then walk Google Play search pages to discover new app IDs.

Metadata fills in the apps you already track. Search finds the ones you should be tracking.

Search uses `store/search?q=<term>&c=apps`, and its results embed the same kind of JSON as the app page. You parse the result cards to get each app's ID, then feed those IDs into `parse_app` from earlier.

python```python
from urllib.parse import urlencode


def parse_search(html):
    data = parse_af_init_data(html)
    sections = get(data, ["ds:4", 0, 1]) or []
    cards = None
    for idx in range(len(sections)):
        cards = get(sections, [idx, 22, 0])
        if isinstance(cards, list) and cards:
            break
    results = []
    for entry in cards or []:
        card = entry[0] if entry else None
        if not card:
            continue
        results.append({
            "appId": card[0][0],
            "title": get(card, [3]),
            "score": get(card, [4, 1]),
            "developer": get(card, [14]),
            "installs": get(card, [15]),
        })
    return results


params = urlencode({"q": "podcast", "c": "apps", "hl": "en", "gl": "us"})
res = client.scrape(ScrapeConfig(f"https://play.google.com/store/search?{params}", asp=True, country="US"))
found = parse_search(res.content)
print(f"got {len(found)} apps")
print(json.dumps(found[:3], indent=2, ensure_ascii=False))
```



Searching for "podcast" returns a list of matching apps with the IDs you need for a metadata pull:

json```json
got 20 apps
[
  {
    "appId": "com.podcast.podcasts",
    "title": "Podcast Player",
    "score": 4.779305,
    "developer": "Castbox.FM - Radio & Podcast & AudioBooks",
    "installs": "10,000,000+"
  },
  {
    "appId": "com.bambuna.podcastaddict",
    "title": "Podcast Addict: Podcast player",
    "score": 4.592667,
    "developer": "Xavier Guillemane - Podcast & Radio Addict",
    "installs": "10,000,000+"
  }
]
```



From here the workflow is CSV in, CSV out. Read app IDs or search terms from a file, fetch each app, de-duplicate on `appId`, and write the rows back out. Category listings work the same way when you want to walk a whole genre instead of a search term.

Raw review objects still need shaping before anything can analyze them.

## How to Structure Google Play Reviews for Analysis

Load the raw review objects straight into a pandas DataFrame for one app. Or send them through the [Extraction API](https://scrapfly.io/docs/extraction-api/getting-started) when you want a consistent schema across many apps.

The first path is fast and local. The second keeps fields normalized when you combine reviews from dozens of apps at once.

For a single app, a DataFrame is enough. Install pandas with `pip install pandas`, convert the Unix `at` timestamp to a real date, and drop straight to CSV.

python```python
import pandas as pd

df = pd.DataFrame(reviews)
df["at"] = pd.to_datetime(df["at"], unit="s")
df = df[["reviewId", "userName", "score", "content", "at", "appVersion"]]
df.to_csv("spotify_reviews.csv", index=False)
print(df[["score", "content", "at"]].head(3).to_string(index=False, max_colwidth=60))
```



The result is a clean table ready for grouping by `score` or `appVersion`:

```
 score                        content                  at
     5 Obsessed with this aap ✨️🪷🫠😍❤️ 2026-07-29 06:41:47
     5                      very good 2026-07-29 06:39:23
     2                      nice work 2026-07-29 06:38:24
```



[Ultimate Guide to JSON Parsing in PythonLearn JSON parsing in Python with this ultimate guide. Explore basic and advanced techniques using json, and tools like ijson and nested-lookup](https://scrapfly.io/blog/posts/how-to-use-python-to-parse-json)

From here you can run sentiment scoring, mine `content` for ASO keywords, or track review trends by `appVersion`. Scaling across many apps, the Extraction API gives you one schema instead of per-app parsing.

How far you can take that reuse is where Google's terms start to matter.



## Is It Legal to Scrape Google Play?

Scraping public Google Play metadata and reviews for analysis is common, but Google's Terms restrict certain reuse. This is a practical note, not legal advice. The line developers care about is reading public data versus republishing it.

Reading public app data for internal analysis (sentiment, ASO, competitive tracking) is the low-risk case. Redistributing scraped reviews, or embedding them in a shipped Play Store app, is riskier.

The recurring fear is account action against their own Play developer account. If you plan to reuse the data commercially, read Google's Terms and check with counsel.

Standard hygiene keeps you on the safe side: scrape only public data and pace your requests instead of hammering the target.

## Powering Google Play Scraping With Scrapfly



ScrapFly's [Web Scraping API](https://scrapfly.io/products/web-scraping-api) is a single HTTP endpoint for collecting web data at scale, with a **98% success rate** against major anti-bot vendors, over residential and datacenter proxies in **190+ countries**.

- [Anti-Scraping Protection bypass](https://scrapfly.io/docs/scrape-api/anti-scraping-protection) - automatically defeats Cloudflare, DataDome, Akamai, and 17 other anti-bot vendors.
- [Smart proxy rotation](https://scrapfly.io/docs/scrape-api/proxy) - residential and datacenter pools with country and ASN level geo-targeting.
- [JavaScript rendering](https://scrapfly.io/docs/scrape-api/javascript-rendering) - render SPAs and dynamic pages through real cloud browsers.
- [Browser automation scenarios](https://scrapfly.io/docs/scrape-api/javascript-scenario) - scroll, click, fill forms, and wait for elements without managing a browser fleet.
- [Format conversion](https://scrapfly.io/docs/scrape-api/getting-started#api_param_format) - return pages as HTML, JSON, clean text, or LLM ready Markdown.
- [Session management](https://scrapfly.io/docs/scrape-api/session) - keep cookies, headers, and IPs consistent across multi step flows.
- [Smart caching](https://scrapfly.io/docs/scrape-api/getting-started#api_param_cache) - cache successful responses to cut cost on repeat scraping jobs.
- [Python](https://scrapfly.io/docs/sdk/python), [TypeScript](https://scrapfly.io/docs/sdk/typescript), [Scrapy](https://scrapfly.io/docs/sdk/scrapy), and [no-code integrations](https://scrapfly.io/docs/integration/getting-started) including [Make](https://scrapfly.io/integration/make), [n8n](https://scrapfly.io/integration/n8n), [Zapier](https://scrapfly.io/integration/zapier), [LangChain](https://scrapfly.io/integration/langchain), and [LlamaIndex](https://scrapfly.io/integration/llamaindex).

For Google Play, `asp=True` turns the review loop that stalls on one IP into one that runs to completion. Every request rotates its fingerprint and address.



### Web Scraping API

Scrape any website with our powerful API. Anti-bot bypass, JavaScript rendering, and rotating proxies built-in.



[Try Web Scraping API](https://scrapfly.io/docs/scrape-api/getting-started)



## FAQ

How many reviews can google-play-scraper return?In practice far fewer than an app has, since users report it stalling after a few hundred to a few thousand and then getting throttled. The full set needs a continuation-token loop routed through a layer that rotates identity.







What is a continuation token in Google Play review scraping?It's a value returned with each batch of reviews that points to the next batch. You pass it into the next request and loop until it comes back empty, which pages through the full review set.







Do I need a headless browser to scrape Google Play?Usually not, because the app data is server-rendered JSON and reviews come from a JSON endpoint you can call directly. A full browser is a fallback, not a requirement.







Does Google block Google Play scraping?Yes, at volume, because Google Play rate-limits by IP and identity. Large review pulls from a single address get throttled, so rotating identity through an anti-bot-aware layer is what keeps a big job running.







Is it legal to scrape Google Play reviews?Scraping public reviews for analysis is common, but Google's Terms restrict certain reuse and embedding scraped data in a shipped app risks account action. Read public data only and check the Terms for commercial use.









## Summary

The free `google-play-scraper` library is a genuine starting point, and for a small one-off pull it's all you need. It falls short on big apps for one reason: getting every review is a pagination and anti-bot problem, not a parsing one.

The app page hands over metadata and the ratings histogram in one request. Reviews sit behind a `batchexecute` endpoint you page with continuation tokens, and that loop only survives at scale when identity rotates.

Route it through the Web Scraping API with `asp=True` and the same loop that capped out at a few hundred reviews runs to the end. The Extraction API is worth adding once you are pulling enough apps that per-app parsing becomes the annoying part.



Legal Disclaimer and PrecautionsThis tutorial covers popular web scraping techniques for education. Interacting with public servers requires diligence and respect:

- Do not scrape at rates that could damage the website.
- Do not scrape data that's not available publicly.
- Do not store PII of EU citizens protected by GDPR.
- Do not repurpose *entire* public datasets which can be illegal in some countries.

Scrapfly does not offer legal advice but these are good general rules to follow. For more you should consult a lawyer.

 

   [  Add as a preferred source ](https://google.com/preferences/source?q=scrapfly.io) Table of Contents















 

  Table of Contents- [Key Takeaways](#key-takeaways)
- [What Data Can You Scrape From Google Play?](#what-data-can-you-scrape-from-google-play)
- [How to Fetch Google Play App Data With the Web Scraping API](#how-to-fetch-google-play-app-data-with-the-web-scraping-api)
- [Fetch the app page and parse its embedded JSON](#fetch-the-app-page-and-parse-its-embedded-json)
- [Where the open-source library fits (and where it stops)](#where-the-open-source-library-fits-and-where-it-stops)
- [Why You Can't Get All the Reviews (and How to Fix It)](#why-you-can-t-get-all-the-reviews-and-how-to-fix-it)
- [Continuation tokens and how Google Play paginates reviews](#continuation-tokens-and-how-google-play-paginates-reviews)
- [Why the open-source library stalls or gets throttled on big apps](#why-the-open-source-library-stalls-or-gets-throttled-on-big-apps)
- [How to Scrape Google Play Reliably at Scale](#how-to-scrape-google-play-reliably-at-scale)
- [How to Scrape App Metadata and Search Results](#how-to-scrape-app-metadata-and-search-results)
- [How to Structure Google Play Reviews for Analysis](#how-to-structure-google-play-reviews-for-analysis)
- [Is It Legal to Scrape Google Play?](#is-it-legal-to-scrape-google-play)
- [Powering Google Play Scraping With Scrapfly](#powering-google-play-scraping-with-scrapfly)
- [FAQ](#faq)
- [Summary](#summary)
 
    Join the Newsletter  Get monthly web scraping insights 

 

  



Scale Your Web Scraping

Anti-bot bypass, browser rendering, and rotating proxies, all in one API. Start with 1,000 free credits.

  No credit card required  1,000 free API credits  Anti-bot bypass included 

 [Start Free](https://scrapfly.io/register) [View Docs](https://scrapfly.io/docs/onboarding) 

 Not ready? Get our newsletter instead. 

 

 ## Related Articles

 [  

 python playwright 

### How to Scrape Google Maps

We'll take a look at to find businesses through Google Maps search system and how to scrape their details using either S...

 

 ](https://scrapfly.io/blog/posts/how-to-scrape-google-maps) [  

 python scrapeguide 

### How to Scrape Amazon.com Product Data and Reviews

This scrape guide covers the biggest e-commerce platform in US - Amazon.com. We'll take a look how to scrape product dat...

 

 ](https://scrapfly.io/blog/posts/how-to-scrape-amazon) [  

 python scrapeguide 

### How to Scrape Google Search Results in 2026

In this scrape guide we'll be taking a look at how to scrape Google Search - the biggest index of public web. We'll cov...

 

 ](https://scrapfly.io/blog/posts/how-to-scrape-google) 

  ## Related Questions

- [ Q How to Set cURL Authentication - Full Examples Guide ](https://scrapfly.io/blog/answers/how-to-set-authorization-with-curl-full-examples-guide)
 
  



   



 Scale your web scraping effortlessly, **1,000 free credits** [Start Free](https://scrapfly.io/register)