Google Play App Metadata — Prices, Ratings & Categories
Pricing
from $1.00 / 1,000 app-country snapshot returneds
Google Play App Metadata — Prices, Ratings & Categories
Get Google Play app snapshots for US, Singapore and Germany in English: titles, upfront prices, currencies, Google-reported ratings, rating counts and category codes. Up to 100 app-country pairs. No review text or contacts; unsuccessful records have no result fee.
Pricing
from $1.00 / 1,000 app-country snapshot returneds
Rating
0.0
(0)
Developer
Heim AI
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Give this Actor a list of known Android package IDs. For each app and requested country (US, Singapore or Germany, in English) it returns one snapshot from the public Google Play web listing:
- the app title;
- the current upfront price as decimal text, with its ISO currency;
- the purchase-control text actually shown on the page (for example
Installor$3.49); - the rating, rating count and category code that Google declares in the listing's structured data;
- the rating and abbreviated count text shown in the listing header, where present.
Use it to compare regional upfront prices of paid apps, or to keep a small, repeatable catalogue snapshot. It does not search Google Play or discover apps. It does not collect review texts, reviewer or developer details, descriptions, screenshots, versions, install counts or permissions.
Quick start
{"appIds":["net.dinglisch.android.taskerm","com.mojang.minecraftpe"],"countries":["us","sg","de"],"maxResults":6}
This asks for Tasker and Minecraft in three countries: 6 app-country pairs, so at most 6 paid records.
appIds: package IDs such asorg.videolan.vlc, or exacthttps://play.google.com/store/apps/details?id=…URLs. Capitalisation is kept, socom.Slackstayscom.Slack. Duplicates are removed, and invalid entries are reported for free next to the valid ones.- URLs are never fetched as given. Only their
idparameter is read. Anygl,hlor other parameter in a pasted URL is ignored; thecountriesfield decides which listing is requested, always withhl=en. countries: any ofus,sg,de(defaultus).maxResults: 1–100 paid records (default 100).
A run accepts at most 100 unique app-country pairs. A larger input is rejected before any request is made; it is not silently truncated.
Price
$0.001 per returned app-country snapshot ($1 per 1,000), plus the platform's $0.00005 Actor-start event. Six returned pairs cost $0.00605. Current prices are shown on the Actor's pricing tab.
The result fee applies only to validated, returned snapshots. Invalid entries, listings Google did not return, missing offers, mismatched or unsupported data, source errors and pairs not attempted have no result fee; the platform start fee still applies. Set maxResults and a maximum charge per run. Once the next result can no longer be paid for, the Actor makes no further requests. Every new run is a new snapshot and is charged again; there is no change-only monitor.
For upfront-price comparisons of free apps, extra countries can return the same zero price. Use one country when you do not need regional listing observations. Each additional requested country is separately billed; do not assume the reported metrics describe distinct regional populations.
Output
The results dataset holds one flat row per validated app-country pair:
| Field | Meaning |
|---|---|
recordId | Stable key play/<country>/en/<packageId> |
appId | Package ID, capitalisation preserved |
title | Listing title. The structured-data name must equal the visible title heading. |
requestedCountry, requestedLanguage | The gl (us/sg/de) and hl (en) that were requested |
price | Current upfront price returned as decimal text (e.g. "0", "4.99") and compared as decimal text. Numeric source values use standard JSON parsing; no floating-point price arithmetic is performed. |
currency | ISO 4217 code declared with the offer |
observedOfferText | The visible purchase control the price was checked against |
priceScope | Plain-language scope of the price (see below) |
sourceRatingValue | aggregateRating.ratingValue as Google declared it, e.g. 4.044929504394531; null if not declared |
sourceRatingCount | aggregateRating.ratingCount as Google declared it, e.g. 2004769; null if not declared, 0 only if declared as zero |
sourceCategoryCode | applicationCategory code, e.g. VIDEO_PLAYERS; null if not declared |
headerRatingText, headerRatingStatus | Rating the listing header displayed (e.g. "4.0"), and how it relates to the source value (see below) |
headerReviewCountText, headerReviewCountStatus | Count text the header displayed, kept as shown (e.g. "2M reviews"), and its relation to the source count |
metricsScope | Plain-language provenance and limits of the rating, count and category fields |
sourceUrl, source, fetchedAt | Exact listing URL requested, source attribution, and fetch time |
A row is delivered only when every check below passes:
- The listing's structured data names exactly this package ID.
- Its title equals the page's primary title heading.
- There is exactly one offer, with a valid decimal price and ISO currency.
- The visible purchase control shows the same current price.
- English grouping such as
$1,299.99is read as 1299.99. - Decimal commas (
7,49 €,1.299,99 €) are read only with a euro marker. - Invalid or ambiguous grouping (
$1,29.99,€1,299), numbers without a currency marker, and several different prices all fail the check. - A price inside semantic strike-through markup (
<s>,<del>) counts as an original price and is ignored. Sale layouts without such markup are not guessed at.
- English grouping such as
- A paid app is priced in the local currency: USD for
us, SGD forsg, EUR forde. - Any declared rating, rating count or category is well formed. A malformed value makes the record unchargeable; it is never silently dropped.
- Where the header shows a rating or count next to a declared source value, the two are compatible (see below).
What the price means, and what it doesn't:
- It is the upfront price shown on the public listing that was requested. It is not a checkout price.
"0"says nothing about ads, subscriptions or in-app purchases.- A returned listing for a country does not prove the app can be installed or bought there.
- For zero-price apps, the currency is reported as declared and may not be the local currency.
Interpreting source metrics
The source rating count is not a count of written reviews. This response does not establish whether the metrics are global, country-specific or device-specific. Do not add counts across requested countries. Values may be cached and change over time. Category codes come from structured data; translated category labels are not inferred from navigation links.
Recognizable header values are checked against the corresponding source values using display rounding or truncation. A plain, unabridged header count must match exactly; no invented cache-drift percentage is allowed. A contradiction produces an uncharged status. Formatting compatibility does not establish that both values describe the same population.
Header statuses:
consistent_with_source/compatible_with_source: a recognized display value is compatible with the source value.present_source_absent: the header is readable, but the corresponding structured field is absent.not_found: no comparable header value was found.unsupported: the header could not be isolated or parsed reliably. Its text is null; well-formed structured values remain explicitly source-reported, not canonical verified ratings.
Missing source metrics are null, not invented zeroes. Malformed declared metrics make the record unchargeable. Versions, install counts, permissions and Data Safety are not collected.
Status and run summary
The separate free status dataset has one row per invalid entry and one per requested pair that did not become a paid row, plus a summary row. The same summary is saved as OUTPUT in the key-value store. Check complete even when the run succeeded. complete: true means every requested entry became a paid row.
Row kinds:
invalid_input: malformed ID, or a URL that is not an exact Play detail URL.no_listing_returned: HTTP 404 for that request. It does not prove the app doesn't exist worldwide.no_offer: the listing declared no offer.parse_mismatch: identity, title, visible price, currency or a recognizable metric comparison disagreed. Themismatchesfield lists which.unsupported_field: malformed or unsupported declared price, currency, rating, count or category data.source_access_denied: HTTP 403 or 429, a redirect, a consent or challenge page, or robots.txt disallows the request.source_unavailable: other HTTP errors, timeouts, the 3 MiB page limit, or robots.txt unavailable.not_attempted: the run stopped first. Thereasonfield holdsbudget_limit,result_limit,request_limit,deadline,interrupted,billing_unknownor the source stop.
Access denial, a redirect, a consent/challenge page and HTTP 503 stop the run politely. Nothing further is requested and nothing further is charged. The run itself still succeeds, with an explicit reason.
Limits and source behaviour
- Only
https://play.google.com/robots.txtand generated/store/apps/details?id=…&gl=…&hl=enlisting URLs are ever requested. - robots.txt is read first, and each exact listing path is checked against it. If robots.txt is unavailable, the run fails closed.
- No login, cookies, proxy, browser, search, reviews, Data Safety or private endpoints are used.
- Redirects are never followed.
- Requests are sequential and at least 0.5 s apart.
- Each request has a 20 s timeout and a 3 MiB page limit.
- New source work has an internal 270-second window, leaving time to save results inside the default 300-second timeout. A longer platform timeout does not extend it.
- The supported memory allocation is 512 MiB (minimum, default and maximum).
- Each run has a hard budget of 102 source requests: 100 listings, robots.txt, and one robots.txt re-check after a resurrection.
- There are no retries. A failed pair appears in the status dataset; start a new run for it.
Page structure can change. When it does, affected pairs become free status rows rather than guessed data.
Large-batch limit: 100 pairs is an input cap, not a promise that all100 finish within the time window. A private production test with live PPE billing requested99 pairs, returned92 and marked7 unattempted when the deadline was reached. This is an observed workload, not a guarantee for other apps or source response times. Prefer smaller batches, inspect complete and retry only the unreturned pairs in a new run. The returned records are new snapshots, not a change-only feed.
Interruptions
If a run is interrupted after a charge, resurrect the same run. Pending paid records are then delivered without a second charge, and pairs already delivered are skipped without being fetched again. Keep run storage intact: the recovery ledger lives in the run's own storage and is not tamper-proof. Saved limits that look edited stop new work once pending paid records have been recovered. Starting a separate run is a new, separately charged snapshot.
An unresolved storage failure or crash can make an obligation's charge outcome impossible to reconstruct. Recovery then favors a possibly free delivery over withholding data that may have been paid for. A known zero-charge result is removed from the recovery ledger; failed cleanup is retried before successful completion. Persistent storage failure fails the run rather than claiming that cleanup succeeded.
Privacy and telemetry
Pseudonymous operational telemetry records actor and run IDs, run origin, timestamps, paying-plan status, a stable hashed caller identifier, and cumulative confirmed event counts. These identifiers are linkable, not anonymous. The telemetry dataset restricts unauthenticated access. Input and result content is not sent. The Actor never stores or logs page bodies.
Source: the public Google Play website. This Actor is not affiliated with or endorsed by Google, and source access and page structure can change. Keep the sourceUrl links with any data you reuse.