ToolzerHubAnswer

Google Play Store API: any app's rating and installs

Google's Play Developer API manages your own apps only. Our API returns any public app's rating, ratings count, installs and last update, 1 credit a call.

5 min read

Short answer

  • Google's Play Developer API publishes and manages your own apps, purchases and reviews, and documents no call for another developer's app or a store search.
  • Star ratings cluster high, so the ratings count, installs and update date tell apps apart better than the score.
  • Our Google Play API searches the store and returns any public app's details, 1 credit a call, from a package name or a Play Store link.
On this page

Google's Play Store API is for your own apps. The Google Play Developer API publishes releases, edits store listings, checks purchases and answers reviews for apps in your developer account, and it documents no call for anyone else's app. For any public app's rating, installs and last update, our Google Play API reads the store's public pages.

What the Play Developer API is for

The Play Developer API is a set of publishing and app-management tools. Its Publishing API mirrors what the Play Console does: upload a build, release it to a track, edit the listing. The purchases API manages your in-app products and subscriptions, the reporting API returns Android vitals for your app, and a separate API reads and replies to your app's reviews. Nothing in it searches the store or reads a competitor's listing.

App data with ToolzerHub

We make ToolzerHub. Our Google Play API returns public Play Store data as JSON with one API key. These routes do the job here, each 1 credit a call:

  • /v1/google-play/search: up to 30 apps for a search term
  • /v1/google-play/app: one app's details from its package name or Play Store link
  • /v1/google-play/charts: top free, paid or grossing apps for a category and country
bash
export TOOLZERHUB_API_KEY=your_key
curl -H "x-api-key: $TOOLZERHUB_API_KEY" \
  "https://api.toolzerhub.com/v1/google-play/app?package_id_or_url=https://play.google.com/store/apps/details?id=com.duolingo"

Duolingo's details in data, trimmed:

json
{
  "package_id": "com.duolingo",
  "title": "Duolingo: Learn Languages",
  "developer": {"name": "Duolingo", "id": "6957685454452609502"},
  "rating": 4.7441278,
  "ratings_count": 48837193,
  "installs": "500,000,000+",
  "content_rating": "Everyone",
  "released": "May 29, 2013",
  "updated": "Nov 3, 2026",
  "contains_ads": true,
  "in_app_purchases": "$0.99 - $239.99 per item"
}

installs is the store's bucket, such as 500,000,000+, not an exact count. rating is unrounded, and ratings_count is exact. updated is the last release date the listing shows.

Compare a category's top apps

The script searches the store for each term, reads the details of the top apps and writes one row per app with its rating, ratings count, installs, release and update dates, ads and in-app purchases. For each term it prints the median rating and how many apps have ads, in-app purchases or no update in 180 days. Install requests (pip install requests) and save it as google_play_apps.py.

python
import csv
import os
import statistics
import sys
import time
from datetime import date, datetime

import requests

API = "https://api.toolzerhub.com/v1/google-play"
HEADERS = {"x-api-key": os.environ.get("TOOLZERHUB_API_KEY", "")}
FIELDS = ["query", "rank", "package_id", "title", "developer", "rating", "ratings_count", "installs",
          "released", "updated", "days_since_update", "contains_ads", "in_app_purchases", "url"]


def get(op, params, tries=3):
    # Retry rate limits, server errors and dropped connections.
    for attempt in range(tries):
        last = attempt == tries - 1
        try:
            r = requests.get(f"{API}/{op}", headers=HEADERS, params=params, timeout=120)
        except requests.RequestException:
            if last:
                raise
            time.sleep(5 * (attempt + 1))
            continue
        if r.status_code in (429, 500, 502, 503, 504) and not last:
            time.sleep(5 * (attempt + 1))
            continue
        r.raise_for_status()
        return r.json()["data"]


def days_since(text):
    # The store shows dates such as "Nov 2, 2026".
    try:
        return (date.today() - datetime.strptime(text, "%b %d, %Y").date()).days
    except (TypeError, ValueError):
        return None


def main(queries, top="10", out="google_play_apps.csv"):
    with open(out, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=FIELDS)
        writer.writeheader()
        for query in filter(None, (q.strip() for q in queries.split(","))):
            results = get("search", {"q": query})["results"][: int(top)]
            apps, failed = [], 0
            for rank, r in enumerate(results, 1):
                try:
                    a = get("app", {"package_id_or_url": r["package_id"]})
                except requests.HTTPError as e:
                    # Skip an app whose page fails; stop on key or credit errors.
                    if e.response.status_code < 500:
                        raise
                    failed += 1
                    continue
                apps.append(a)
                writer.writerow({
                    "query": query, "rank": rank, "package_id": a["package_id"], "title": a["title"],
                    "developer": (a.get("developer") or {}).get("name"), "rating": a.get("rating"),
                    "ratings_count": a.get("ratings_count"), "installs": a.get("installs"),
                    "released": a.get("released"), "updated": a.get("updated"),
                    "days_since_update": days_since(a.get("updated")), "contains_ads": a.get("contains_ads"),
                    "in_app_purchases": a.get("in_app_purchases"),
                    "url": f"https://play.google.com/store/apps/details?id={a['package_id']}",
                })
            ratings = [a["rating"] for a in apps if a.get("rating")]
            stale = sum((days_since(a.get("updated")) or 0) > 180 for a in apps)
            print(f"{query}: top {len(apps)} apps, median rating {statistics.median(ratings or [0]):.2f}, "
                  f"{sum(bool(a.get('contains_ads')) for a in apps)} with ads, "
                  f"{sum(bool(a.get('in_app_purchases')) for a in apps)} with in-app purchases, "
                  f"{stale} not updated in 180 days" + (f"; {failed} skipped" if failed else ""))


if __name__ == "__main__":
    if len(sys.argv) < 2:
        sys.exit('usage: python google_play_apps.py "habit tracker,expense tracker" [top] [out.csv]')
    if not HEADERS["x-api-key"]:
        sys.exit("set TOOLZERHUB_API_KEY first")
    main(*sys.argv[1:])

What two categories showed

python google_play_apps.py "habit tracker,expense tracker" 10 made 24 calls in 54 seconds and saved 19 apps; one habit tracker's details did not come back, and the script skipped it.

Search term Apps Rating range Ratings count range With ads With in-app purchases Median days since update
habit tracker 9 4.31 to 4.75 309 to 133,635 2 8 30
expense tracker 10 4.44 to 4.83 4,329 to 484,605 5 8 20

Every app rated between 4.31 and 4.83, while ratings counts ran from 309 to 484,605, so for these apps the count says more about reach than the score. The first habit tracker in search, Loop Habit Tracker, shows an update date 415 days old and no ads or in-app purchases. More expense trackers carry ads: 5 of 10, against 2 of 9 habit trackers.

What it costs

A search term is 11 credits at the top 10: one search and ten app lookups. The 100 free credits a month cover nine categories at that depth; $19 buys 10,000 credits that never expire, and plans for higher volume cover weekly checks on more apps. Set your key and the first category is a CSV in under a minute.

For what users write about those apps, see the Google Play reviews API. For reviews of places on Google Maps, see the Google Maps reviews API.

We are not affiliated with Google.

Get this data from your own code

The Google Play API returns it as JSON with one x-api-key header. 100 free credits monthly.