Package Exports
- google-play-scraper-ts
Readme
google-play-scraper-ts
Fully typed Node.js client for Google Play Store metadata inspired by google-play-scraper. The rewrite keeps the familiar API while adding:
- ✅ TypeScript-first types and emitted declaration files
- ✅ Fixtures & offline tests (no live traffic unless
LIVE=1) - ✅ Retries + memoization out of the box
- ✅ Dual CJS/ESM builds with verified parity
Installation
npm install google-play-scraper-tsRequires Node.js 18 or newer.
Quick start
CommonJS:
const gplay = require('google-play-scraper-ts').default;
const app = await gplay.app({ appId: 'com.spotify.music' });
console.log(app.title, app.score);ESM / TypeScript:
import gplay, { constants } from 'google-play-scraper-ts';
const topFreeMusic = await gplay.list({
collection: constants.collection.TOP_FREE,
category: constants.category.MUSIC_AND_AUDIO,
num: 10,
});Common conventions
langcontrols the Play Store UI language (default'en').countrycontrols geotargeting and pricing (default'us').- Methods that accept
requestOptionsforwardrequestOptions.headersto the underlying HTTP client so you can inject cookies or additional headers (see per-method notes—suggestcurrently ignores the option for API parity). - Every function returns a Promise; runtime errors (invalid inputs, store shape changes, HTTP failures) surface as rejected promises.
Proxy routing
- The HTTP client can route calls through HTTP(S) proxies keyed by country (ISO alpha-2, case-insensitive). If no per-country match is found, the optional
defaultproxy is used instead of a direct connection. - Configure proxies once via
configureProxies(settings)or construct an isolated client withcreatePlayStoreApi({ proxies }). All methods automatically opt into proxy usage—thecountryargument (orglquery param) determines the lookup. - HTTPS proxies are supported; pass
protocol: 'https'or use anhttps://URL. To work with debugging gateways that present expired/self-signed certificates, setrejectUnauthorized: false(defaults totrue).
import { createPlayStoreApi } from 'google-play-scraper-ts';
const gplay = createPlayStoreApi({
proxies: {
default: { host: 'proxy.example', port: 8080 },
perCountry: {
us: { host: 'us-proxy.internal', port: 8080, auth: { username: 'user', password: 'secret' } },
fr: { url: 'http://fr-proxy.internal:8080' },
br: { url: 'https://br-proxy.internal:10443', rejectUnauthorized: false },
},
},
});
const result = await gplay.app({ appId: 'com.spotify.music', country: 'us' });Already instantiated clients can be updated in-place with
configureProxies(newSettings); passnullor omit entries to clear previously configured proxies.
API reference
All methods are asynchronous and resolve to typed results. The library mirrors the original google-play-scraper surface while enriching the responses with strict TypeScript types.
Shared types
AppDetails
Identification & copy
| Field | Type | Description |
|---|---|---|
appId |
string |
Requested package identifier. |
url |
string |
Canonical details URL including hl/gl query params. |
title |
string |
App title localized to lang. |
summary |
string |
Short marketing blurb. |
description |
string |
Plain-text description (HTML stripped). |
descriptionHTML |
string |
Raw HTML description from the store. |
genre |
string | undefined |
Primary genre label. |
genreId |
string | undefined |
Primary genre identifier. |
categories |
Array<{ name: string; id: string }> |
All category tags discovered in the payload. |
Ratings & installs
| Field | Type | Description |
|---|---|---|
installs |
string | undefined |
Play Store installs text (e.g. '10,000,000+'). |
minInstalls |
number | undefined |
Minimum installs inferred by the store. |
maxInstalls |
number | undefined |
Maximum installs inferred by the store. |
score |
number | undefined |
Average rating (0–5). |
scoreText |
string | undefined |
Rating text shown in the UI. |
ratings |
number | undefined |
Total number of ratings. |
reviews |
number | undefined |
Total number of textual reviews. |
histogram |
Record<1 | 2 | 3 | 4 | 5, number> |
Star histogram counts (missing buckets default to 0). |
Pricing & monetisation
| Field | Type | Description |
|---|---|---|
free |
boolean |
true when the app can be installed without payment. |
price |
number |
Current price in the store currency (e.g. 0, 3.99). |
originalPrice |
number | undefined |
Pre-discount price in the store currency, when available. |
discountEndDate |
number | undefined |
Unix timestamp (ms) for the promotion end, if provided. |
currency |
string | undefined |
ISO-4217 currency code. |
priceText |
string |
Human readable price (falls back to 'Free'). |
offersIAP |
boolean |
Whether the listing advertises in-app purchases. |
IAPRange |
string | undefined |
Raw in-app purchase price range from the store. |
isAvailableInPlayPass |
boolean |
Indicates Google Play Pass availability. |
Media & merchandising
| Field | Type | Description |
|---|---|---|
icon |
string | undefined |
Square icon URL. |
headerImage |
string | undefined |
Feature graphic URL. |
screenshots |
string[] |
Screenshot URLs (order preserved). |
video |
string | undefined |
Promotional video URL. |
videoImage |
string | undefined |
Poster image for the promo video. |
previewVideo |
string | undefined |
Short autoplay preview clip URL. |
comments |
string[] |
Up to five highlighted user quotes. |
recentChanges |
string | undefined |
“What’s new” text block. |
Developer & policies
| Field | Type | Description |
|---|---|---|
developer |
string | undefined |
Developer display name. |
developerId |
string | undefined |
Developer identifier extracted from profile link. |
developerInternalID |
string | undefined |
Internal developer ID used by Play. |
developerEmail |
string | undefined |
Contact email. |
developerWebsite |
string | undefined |
Website URL. |
developerAddress |
string | undefined |
Mailing address. |
developerLegalName |
string | undefined |
Legal entity name. |
developerLegalEmail |
string | undefined |
Legal contact email. |
developerLegalAddress |
string | undefined |
Legal contact address (line breaks normalised). |
developerLegalPhoneNumber |
string | undefined |
Legal contact phone number. |
privacyPolicy |
string | undefined |
Privacy policy URL. |
Platform & release information
| Field | Type | Description |
|---|---|---|
released |
string | undefined |
Store-published release date text. |
updated |
number | undefined |
Last update timestamp in ms since epoch. |
version |
string |
Latest version string (falls back to 'VARY'). |
androidVersion |
string |
Minimum Android version, normalised (e.g. '5.0' or 'VARY'). |
androidVersionText |
string |
Raw minimum version text from the listing. |
androidMaxVersion |
string | undefined |
Maximum supported Android version if provided. |
contentRating |
string | undefined |
Content rating label (e.g. 'Teen'). |
contentRatingDescription |
string | undefined |
Additional content rating guidance. |
adSupported |
boolean |
true if the listing discloses ads. |
available |
boolean |
Indicates overall availability in the requested country. |
preregister |
boolean |
true when the app is only available for preregistration. |
earlyAccessEnabled |
boolean |
true for early access / beta listings. |
AppSummary
Returned by list, search, developer and similar methods when fullDetail is false.
| Field | Type | Description |
|---|---|---|
appId |
string | undefined |
Package identifier. |
title |
string | undefined |
App title. |
url |
string | undefined |
Absolute Play Store URL. |
icon |
string | undefined |
Icon URL. |
developer |
string | undefined |
Developer display name. |
developerId |
string | undefined |
Developer profile identifier (when exposed). |
summary |
string | undefined |
Short synopsis. |
price |
number | undefined |
Current price in the store currency (0 for free apps). |
priceText |
string | undefined |
Price label ('FREE', '$0.99', …). |
currency |
string | undefined |
Currency code. |
free |
boolean | undefined |
true when no payment required. |
score |
number | undefined |
Average rating. |
scoreText |
string | undefined |
Rating text. |
Review
| Field | Type | Description |
|---|---|---|
id |
string | undefined |
Review identifier used by the Play Store. |
userName |
string | undefined |
Reviewer display name. |
userImage |
string | undefined |
Avatar image URL. |
date |
string | null |
ISO string of the review timestamp (null if unavailable). |
score |
number | undefined |
Star rating (1–5). |
scoreText |
string | null | undefined |
Rating represented as text. |
url |
string | undefined |
Deep link back to the review on Play. |
title |
null |
Placeholder (Play no longer serves review titles). |
text |
string | undefined |
Review body. |
replyDate |
string | null |
ISO timestamp of the developer reply. |
replyText |
string | null |
Developer reply content. |
version |
string | null |
App version cited in the review. |
thumbsUp |
number | undefined |
Helpfulness vote count. |
criterias |
Array<{ criteria: unknown | null; rating: unknown | null }> | undefined |
Per-criteria ratings when supplied by Play (e.g. for games). |
PermissionItem
| Field | Type | Description |
|---|---|---|
permission |
string |
Permission string (e.g. 'CAMERA'). |
type |
0 | 1 |
Section identifier (0 = constants.permission.COMMON, 1 = constants.permission.OTHER). |
DataSafetyItem
| Field | Type | Description |
|---|---|---|
data |
string | undefined |
Data point name (e.g. 'email'). |
optional |
boolean | null | undefined |
Whether the data is optional (null when Google has no flag). |
purpose |
string | null | undefined |
Usage purpose label (e.g. 'ads'). |
type |
string | undefined |
Category grouping (e.g. 'Personal info'). |
app(options): Promise<AppDetails>
Fetch detailed information about a single application.
| Option | Type | Default | Description |
|---|---|---|---|
appId |
string |
– | Required package identifier (com.spotify.music). |
lang |
string |
'en' |
Store UI language. |
country |
string |
'us' |
Store country / pricing market. |
requestOptions |
{ headers?: Record<string, string> } |
– | Extra HTTP headers passed to Play (cookies, locale overrides, …). |
Resolves to an AppDetails object as documented above.
list(options): Promise<AppSummary[] \| AppDetails[]>
Retrieve curated charts (Top Free, Top Paid, Grossing, …). Set fullDetail to fetch the richer AppDetails payload for each entry.
| Option | Type | Default | Description |
|---|---|---|---|
collection |
constants.collection |
constants.collection.TOP_FREE |
Chart to fetch. |
category |
constants.category |
constants.category.APPLICATION |
App category filter. |
age |
constants.age | string | undefined |
– | Optional age-range filter. |
lang |
string |
'en' |
Locale for metadata. |
country |
string |
'us' |
Region / storefront. |
num |
number |
500 |
Maximum entries (Play caps at ~500). |
fullDetail |
boolean |
false |
When true, fetch each item with app(). |
Returns an array of AppSummary entries, or AppDetails entries when fullDetail is enabled.
search(options): Promise<AppSummary[] \| AppDetails[]>
Search the Play Store catalogue.
| Option | Type | Default | Description |
|---|---|---|---|
term |
string |
– | Search query (required). |
lang |
string |
'en' |
Metadata language. |
country |
string |
'us' |
Storefront country. |
num |
number |
20 |
Maximum results (hard limit 250). |
fullDetail |
boolean |
false |
When true, hydrate each match via app(). |
price |
'all' | 'free' | 'paid' |
'all' |
Price filter. |
requestOptions |
{ headers?: Record<string, string> } |
– | Forwarded headers for the search request. |
Results mirror the modern /store/search layout (including single-result pages). When fullDetail is enabled each result is re-fetched via app().
Need the legacy “global” feed? Use
searchGlobal(options)to call the former/work/searchendpoint. Its options matchsearch(), but expect geo-neutral results unless you route traffic through a country proxy.
searchGlobal(options): Promise<AppSummary[] \| AppDetails[]>
Back-compat wrapper around the legacy /work/search flow. Accepts the same options as search() and returns identical payload shapes. Pagination still uses the shared batchexecute endpoint, but the initial page reflects Google’s global results regardless of the country parameter.
suggest(options): Promise<string[]>
Fetch autocomplete suggestions from Play.
| Option | Type | Default | Description |
|---|---|---|---|
term |
string |
– | Partial query (required). |
lang |
string |
'en' |
Suggestion language. |
country |
string |
'us' |
Storefront country. |
requestOptions |
{ headers?: Record<string, string> } |
– | Reserved for API compatibility (currently ignored). |
Resolves to an array of suggestion strings ordered by relevance.
developer(options): Promise<AppSummary[] \| AppDetails[]>
List applications published by a developer profile.
| Option | Type | Default | Description |
|---|---|---|---|
devId |
string |
– | Developer identifier (numeric or slug). |
lang |
string |
'en' |
Metadata language. |
country |
string |
'us' |
Storefront country. |
num |
number |
60 |
Maximum apps to collect. |
fullDetail |
boolean |
false |
Set to true for AppDetails results. |
Returns developer listings as AppSummary entries, or full details when fullDetail is enabled.
reviews(options): Promise<{ data: Review[]; nextPaginationToken: string \| null }>
Pull paginated user reviews for a given app.
| Option | Type | Default | Description |
|---|---|---|---|
appId |
string |
– | Target package identifier. |
sort |
constants.sort |
constants.sort.NEWEST |
Sorting mode (NEWEST, RATING, HELPFULNESS). |
lang |
string |
'en' |
Review language. |
country |
string |
'us' |
Locale used for review localisation. |
num |
number |
150 |
Maximum reviews to gather before stopping. |
paginate |
boolean |
false |
When false, auto-follow tokens until num reviews or exhaust data. |
nextPaginationToken |
string | null |
null |
Pass a token from a previous response to resume manually. |
When paginate is true, the method fetches a single page and returns the next token (if any). The data array contains Review entries.
similar(options): Promise<AppSummary[] \| AppDetails[]>
Retrieve apps from the “Similar” / “Related” clusters for a given listing.
| Option | Type | Default | Description |
|---|---|---|---|
appId |
string |
– | Reference package identifier. |
lang |
string |
'en' |
Metadata language. |
country |
string |
'us' |
Storefront country. |
fullDetail |
boolean |
false |
Hydrate each result via app() when true. |
Returns up to ~60 related apps as AppSummary or AppDetails entries.
permissions(options): Promise<string[] \| PermissionItem[]>
Inspect runtime permissions declared in the Play listing.
| Option | Type | Default | Description |
|---|---|---|---|
appId |
string |
– | Target package identifier. |
short |
boolean |
false |
When true, return a flat list of permission strings. Otherwise return PermissionItem objects grouped by type. |
lang |
string |
'en' |
Language for permission descriptions (when available). |
country |
string |
'us' |
Storefront country. |
datasafety(options): Promise<{ sharedData: DataSafetyItem[]; collectedData: DataSafetyItem[]; securityPractices: Array<{ practice?: string; description?: string }>; privacyPolicyUrl?: string }>
Fetch the Google Play “Data safety” disclosure for an app.
| Option | Type | Default | Description |
|---|---|---|---|
appId |
string |
– | Target package identifier. |
lang |
string |
'en' |
Disclosure language. |
The result contains separate sharedData and collectedData arrays of DataSafetyItems, a list of high-level securityPractices, and an optional privacyPolicyUrl.
categories(): Promise<string[]>
Scrape the public category directory and return category identifiers (e.g. 'APPLICATION', 'GAME_TRIVIA').
memoized(options?: { maxAge?: number; max?: number }): PlayStoreApi
Wrap the API with an in-memory cache.
| Option | Type | Default | Description |
|---|---|---|---|
maxAge |
number |
300_000 |
Cache TTL in milliseconds. |
max |
number |
1_000 |
Maximum cache size; oldest entries are evicted first. |
The returned object has the same surface as the default export (including a memoized method) but memoises every call.
Constants helper
The default export re-exports structured enums under constants for convenience:
constants.collection–TOP_FREE,TOP_PAID,GROSSING.constants.category– All Play categories (apps, games, family variants, etc.).constants.sort– Review sort orders (NEWEST,RATING,HELPFULNESS).constants.age– Age-range filters used by the family charts.constants.permission– Permission buckets (COMMON,OTHER).constants.clusters– Internal cluster identifiers used by list parsing utilities.
Releases
- Preflight checks before releasing:
npm run release:preflight(lint, tests, type verification)
- Publish (requires npm login and 2FA):
- Patch:
npm run release:patch - Minor:
npm run release:minor - Major:
npm run release:major
- Patch:
- Notes
prepackbuilds automatically before pack/publish.- For scoped packages (e.g.
@your-scope/google-play-scraper-ts), publish with--access public(already included in release scripts). - To validate after publish: install in a clean folder and require/import both CJS/ESM entries.
Debugging & Fixtures
- Verbose debugging for
similar()resolution:- Set
GP_DEBUG=1to print minimal breadcrumbs when the service-request cluster id is missing (e.g., container keys available).
- Set
- UI tests (manual exploration):
- Build the library:
npm run build - Start the UI server:
LIVE=1 node ui-tests/server.js - Open the playground and use the forms to call each method.
- Build the library:
- Record live fixtures for
similar()(optional):LIVE=1 npm run build && node scripts/record-similar-fixture.js --appId com.spotify.music --lang en --country us --out tests/fixtures/similar- Re-run tests with fixture replay:
USE_FIXTURE=1 npm test
constants.sort– Review sort order valuesconstants.age,constants.permission, plus other helpers
Retries & throttling
- Retries – The internal HTTP client retries 5xx responses with exponential backoff (configurable via helper APIs).
- Caching – Use
memoized()to deduplicate hot requests. For full control, combine with your own throttling or caching layer.
TypeScript support
- Published package includes type declarations generated from the TypeScript sources.
npm run verify:typescompilestests/types/usage.tsagainst the generated.d.tsto guarantee correctness.
Running the docs & tests
npm run lint
LIVE=1 npm test # only needed when you want to exercise live tests (default suite uses fixtures)
npm run test # builds both ESM and CJS bundles before running mocha
npm run docs # generates TypeDoc output in /docs
npm run verify:typesBy default the test suite blocks outbound HTTP requests. Set
LIVE=1to allow network calls when you want to run ad-hoc live checks.
Manual UI testing playground
Looking for the interactive UI harness? It now lives in a standalone repository with prebuilt assets and GitHub Pages hosting:
- GitHub repo:
google-play-scraper-ts-ui-tests - Hosted playground: https://guiguito.github.io/google-play-scraper-ts-ui-tests/
The hosted version always targets the latest npm release of this package. It includes the search-mode toggle (modern /store/search vs. legacy /work/search) and the enhanced proxy configuration panel (per-country entries, auth, TLS validation overrides), plus a direct Play Store link for each query so you can inspect the underlying page.
Contributing
Issues and pull requests are welcome! Please review AGENTS.md for repository conventions (linting, commit style, release workflow).