App Store API & Scraper
The App Store Reviews API returns unified Apple App Store and Google Play data as clean JSON.
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
The primary reviews endpoint returns an app's profile (name, id, rating) and its reviews (rating, title, text, date, reviewer, version) from both stores, and you can search apps, list top charts and categories, pull appDetails, a developer's apps and similar apps. It is built for app-intelligence, review-monitoring and competitor-tracking tools that need mobile-app data across both stores from one endpoint. One ReefAPI key, one shared credit pool, the standard envelope.
Apple app id vs Google Play package, and what each store leaves null
This engine answers for the Apple App Store and Google Play behind one set of actions, so the same field name can be filled by one store and empty on the other. Every value below is a live read on 2026-08-27: appDetails for Spotify (Apple id 324684580) and WhatsApp (Play package com.whatsapp), plus topCharts for the US and DE storefronts.
| Field | Apple App Store | Google Play |
|---|---|---|
| app_id | Numeric string, e.g. 324684580 (Spotify). bundle_id is separate: com.spotify.client | The package name itself, e.g. com.whatsapp. app_id and bundle_id hold the same value |
| released / updated | ISO 8601 UTC: 2011-07-14T11:22:37Z and 2026-08-20T07:42:38Z | Human date strings: "Oct 18, 2010" and "Aug 21, 2026". Parse them, do not compare them |
| price / currency | 0.0 and "USD" on a free app; 6.99 USD in the US chart, 6.99 EUR in the German one | Both null even when free is true. Read the free boolean instead |
| installs | null, since Apple publishes no install count | A formatted string with separators: "10,000,000,000+" |
| version, size_bytes, min_os, languages | 9.1.76, 295870464, "16.1", 61 language codes | null, null, null and an empty array |
| rating_count vs review_count | 41,731,636 ratings, review_count null | 242,088,177 ratings against 1,953,376 written reviews |
| histogram | Keys "5" down to "1" plus a "total" key | Keys "1" to "5", no total key |
| topCharts category | Numeric genre id: 6014 Games, 6000 Business, 6017 Education. listCategories returns 26 | String constant: GAME, SOCIAL, ART_AND_DESIGN. listCategories returns 52 |
appDetails takes one appId, so a numeric Apple id sent with stores ["apple","google_play"] returns the Apple profile and a google_play result with status "EMPTY" rather than an error. Note also that meta.record_count counts apps[] rows only: it reads 0 on appDetails and listCategories even when a full profile or a 52-entry category list came back. Check data.results[].status, which was "COMPLETE" on both successful reads.
Real request and response JSON
Captured from the indexed primary action, reviews, on .
{
"method": "POST",
"url": "https://api.reefapi.com/app-store/v1/reviews",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"apps": [
{
"name": "WhatsApp",
"apple": "310633997"
}
],
"stores": [
"apple"
],
"countries": [
"us"
],
"maxReviews": 100
}
}{
"ok": true,
"meta": {
"api": "app-store",
"endpoint": "reviews",
"mode": "live",
"latency_ms": 3368.5,
"record_count": 100,
"bytes": 0,
"cache_hit": false,
"kind": "reviews",
"summary": {
"units": 1,
"succeeded": 1,
"not_found": 0,
"blocked": 0,
"success_rate_pct": 100,
"total_reviews": 100,
"total_new": 0,
"avg_completeness_pct": 0.001,
"by_store": {
"apple": 1
},
"error_breakdown": {},
"retries_used": 0
}
},
"data": {
"kind": "reviews",
"results": [
{
"store": "apple",
"app_id": "[redacted-phone]",
"query": "[redacted-phone]",
"profile": {
"store": "apple",
"app_id": "[redacted-phone]",
"bundle_id": "net.whatsapp.WhatsApp",
"name": "[redacted-name]",
"subtitle": null,
"developer": "WhatsApp Inc.",
"developer_email": null,
"developer_website": "http://www.whatsapp.com/",
"avg_rating": 4.68607,
"rating_count": 18268035,
"review_count": null,
"histogram": {
"1": "[trimmed-depth]",
"2": "[trimmed-depth]",
"3": "[trimmed-depth]",
"4": "[trimmed-depth]",
"5": "[trimmed-depth]",
"total": "[trimmed-depth]"
},
"current_version_score": 4.68607,
"current_version_rating_count": 18268035,
"installs": null,
"price": 0,
"currency": "USD",
"free": true,
"content_rating": "12+",
"contains_ads": null,
"description": "WhatsApp from Meta is a free messaging and calling app used by over 2 billion people across 180+ countries. It's super simple, reliable and private, making it perfect for staying in touch with your friends and family worldwide. WhatsApp works across mobile, tablet, and desktop even on slow connections, with no subscription fees*.\n\nPrivate messaging and calls across the world\n\nYour privacy is our priority. With end-to-end encryption, you can be sure that your personal messages and calls stay between you and who you send them to. And no one, not even WhatsApp, can read or listen to them.\n\nSimple",
"release_notes": "We update the app regularly to fix bugs, optimize performance and improve the experience. Thanks for using WhatsApp!",
"released": "[redacted-phone]T02:43:49Z",
"updated": "[redacted-phone]T05:39:22Z",
"version": "26.27.74",
"size_bytes": 377079808,
"min_os": "15.1",
"languages": [
"[trimmed-depth]",
"[trimmed-depth]",
"[trimmed-depth]"
],
"screenshots": [],
"privacy_policy": null,
"icon_url": "https://is1-ssl.mzstatic.com/image/thumb/Purple211/v4/e3/8b/2f/e38b2fe8-5991-2e46-8b1c-64315e08a3e7/AppIcon-0-0-1x_U007epad-[redacted-phone]-sRGB-0-85-220.png/512x512bb.jpg",
"url": "https://apps.apple.com/us/app/whatsapp-messenger/id[redacted-phone]?uo=4",
"categories": [
"[trimmed-depth]",
"[trimmed-depth]"
]
},
"reviews": [
{
"store": "[trimmed-depth]",
"review_id": "[trimmed-depth]",
"app_id": "[trimmed-depth]",
"app_name": "[trimmed-depth]",
"country": "[trimmed-depth]",
"rating": "[trimmed-depth]",
"score_text": "[trimmed-depth]",
"title": "[trimmed-depth]",
"text": "[trimmed-depth]",
"language": "[trimmed-depth]",
"review_date": "[trimmed-depth]",
"app_version": "[trimmed-depth]",
"sub_ratings": "[trimmed-depth]",
"thumbs_up": "[trimmed-depth]",
"vote_sum": "[trimmed-depth]",
"vote_count": "[trimmed-depth]",
"reviewer_name": "[trimmed-depth]",
"reviewer_id": "[trimmed-depth]",
"reviewer_url": "[trimmed-depth]",
"reviewer_avatar_url": "[trimmed-depth]",
"reply_text": "[trimmed-depth]",
"reply_date": "[trimmed-depth]",
"review_url": "[trimmed-depth]",
"scraped_at": "[trimmed-depth]",
"scraped_at_page": "[trimmed-depth]",
"is_new": "[trimmed-depth]"
},
{
"store": "[trimmed-depth]",
"review_id": "[trimmed-depth]",
"app_id": "[trimmed-depth]",
"app_name": "[trimmed-depth]",
"country": "[trimmed-depth]",
"rating": "[trimmed-depth]",
"score_text": "[trimmed-depth]",
"title": "[trimmed-depth]",
"text": "[trimmed-depth]",
"language": "[trimmed-depth]",
"review_date": "[trimmed-depth]",
"app_version": "[trimmed-depth]",
"sub_ratings": "[trimmed-depth]",
"thumbs_up": "[trimmed-depth]",
"vote_sum": "[trimmed-depth]",
"vote_count": "[trimmed-depth]",
"reviewer_name": "[trimmed-depth]",
"reviewer_id": "[trimmed-depth]",
"reviewer_url": "[trimmed-depth]",
"reviewer_avatar_url": "[trimmed-depth]",
"reply_text": "[trimmed-depth]",
"reply_date": "[trimmed-depth]",
"review_url": "[trimmed-depth]",
"scraped_at": "[trimmed-depth]",
"scraped_at_page": "[trimmed-depth]",
"is_new": "[trimmed-depth]"
},
{
"store": "[trimmed-depth]",
"review_id": "[trimmed-depth]",
"app_id": "[trimmed-depth]",
"app_name": "[trimmed-depth]",
"country": "[trimmed-depth]",
"rating": "[trimmed-depth]",
"score_text": "[trimmed-depth]",
"title": "[trimmed-depth]",
"text": "[trimmed-depth]",
"language": "[trimmed-depth]",
"review_date": "[trimmed-depth]",
"app_version": "[trimmed-depth]",
"sub_ratings": "[trimmed-depth]",
"thumbs_up": "[trimmed-depth]",
"vote_sum": "[trimmed-depth]",
"vote_count": "[trimmed-depth]",
"reviewer_name": "[trimmed-depth]",
"reviewer_id": "[trimmed-depth]",
"reviewer_url": "[trimmed-depth]",
"reviewer_avatar_url": "[trimmed-depth]",
"reply_text": "[trimmed-depth]",
"reply_date": "[trimmed-depth]",
"review_url": "[trimmed-depth]",
"scraped_at": "[trimmed-depth]",
"scraped_at_page": "[trimmed-depth]",
"is_new": "[trimmed-depth]"
}
],
"scraped_count": 100,
"new_count": null,
"total_available": 18268035,
"fetchable_ceiling": 500,
"completeness_pct": 0.001,
"countries": [
"us"
],
"status": "PARTIAL",
"attempts": 1,
"next_cursor": {
"latest_date": "[redacted-phone]T08:17:14+00:00",
"latest_ids": [
"[trimmed-depth]",
"[trimmed-depth]",
"[trimmed-depth]"
]
},
"notes": null
}
],
"summary": {
"units": 1,
"succeeded": 1,
"not_found": 0,
"blocked": 0,
"success_rate_pct": 100,
"total_reviews": 100,
"total_new": 0,
"avg_completeness_pct": 0.001,
"by_store": {
"apple": 1
},
"error_breakdown": {},
"retries_used": 0
}
}
}What the App Store API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| reviews | unified Apple + Play reviews for one or more apps | Support teams call reviews to get unified Apple + Play reviews for one or more apps. | apps, appleAppId, googlePlayPackage, appName, stores, ... |
| search | ranked app search results | Reputation platforms call search to get ranked app search results. | query, stores, country, count |
| topCharts | ranked chart/category apps | Market researchers call topCharts to get ranked chart/category apps. | stores, country, category, count, chart, ... |
| listCategories | static genre/category list | B2B review analysts call listCategories to get static genre/category list. | stores |
| appDetails | full app profile | Support teams call appDetails to get full app profile. | appId, appleAppId, googlePlayPackage, stores, country, ... |
| developerApps | every other app published by the same developer | Reputation platforms call developerApps to get every other app published by the same developer. | appId, appleAppId, googlePlayPackage, stores, country, ... |
| similarApps | related / similar apps for an app | Market researchers call similarApps to get related / similar apps for an app. | appId, appleAppId, googlePlayPackage, stores, country, ... |
Call reviews from your stack
curl -X POST https://api.reefapi.com/app-store/v1/reviews \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"apps":[{"name":"WhatsApp","apple":"310633997"}],"stores":["apple"],"countries":["us"],"maxReviews":100}'import requests
r = requests.post(
"https://api.reefapi.com/app-store/v1/reviews",
headers={"x-api-key": REEF_KEY},
json={
"apps": [
{
"name": "WhatsApp",
"apple": "310633997"
}
],
"stores": [
"apple"
],
"countries": [
"us"
],
"maxReviews": 100
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/app-store/v1/reviews", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"apps": [
{
"name": "WhatsApp",
"apple": "310633997"
}
],
"stores": [
"apple"
],
"countries": [
"us"
],
"maxReviews": 100
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.app-store.reviews with {"apps":[{"name":"WhatsApp","apple":"310633997"}],"stores":["apple"],"countries":["us"],"maxReviews":100}.Who uses this API and why
- App teams call reviews to monitor new ratings and feedback for their app across both stores.
- Competitor-intelligence tools use topCharts and similarApps to track rivals' rankings.
- Product teams use appDetails and reviews to analyze feature requests and sentiment by version.
Questions developers ask before integrating
Does this API cover Google Play as well as the Apple App Store?
Both. The stores parameter takes ["apple","google_play"] and accepts aliases like ios, app_store, play, android and google; unknown names are ignored rather than rejected, and omitting the parameter queries both. A live appDetails call on 2026-08-27 for Apple id 324684580 came back with apple:us status COMPLETE and google_play:us status EMPTY, because a numeric Apple id is not a Play package.
What does an app id look like for each store?
Apple uses a numeric id, 324684580 for Spotify, which is the digits after /id in an apps.apple.com URL. Google Play uses the Java-style package name, com.whatsapp, which is the id query parameter on a Play URL. appDetails, developerApps and similarApps all take a single appId parameter that accepts either form, with appleAppId and googlePlayPackage as aliases.
Does the country parameter change the price and the currency?
Yes, and it changes more than the money. topPaid for country us on 2026-08-27 returned Minecraft at 6.99 USD; the same chart for country de returned it at 6.99 EUR, with the name shortened to "Minecraft" and the category localized to "Spiele". The German chart's rank 1 was Blitzer.de PRO at 0.49 EUR, an app that does not appear in the US chart at all. Treat every country as a separate catalog.
Why are the ratings null in a topCharts or search result?
Chart and search rows come from Apple's ranked feeds, which carry rank, name, developer, price, currency, category, icon and URL, but not ratings. On a live topPaid read every row had avg_rating null, rating_count null and content_rating null. Call appDetails with the app_id from the chart row to get avg_rating, rating_count and the star histogram.
What is the difference between rating_count and review_count?
rating_count is everyone who tapped a star; review_count is the subset who also typed something. Measured on WhatsApp on Google Play: 242,088,177 ratings against 1,953,376 written reviews. Apple does not split the two, so on an Apple profile review_count is null and rating_count carries the whole number.
How deep does a chart go?
Apple's chart feed is capped at roughly 100 apps per request, and each result carries that limit back to you in results[].notes as "Apple RSS feed caps at ~100 apps per request". The count parameter has no documented upper bound but cannot get you past the feed's own ceiling, so treat 100 as the practical maximum per chart, category and country combination.
Which category values does topCharts accept?
Apple wants a numeric genre id and Google Play wants a string constant, and they are not interchangeable. listCategories returned 26 Apple genres on 2026-08-27, from 6000 Business through 6027 Graphics & Design, with 6014 Games and 6017 Education in between; the same call returned 52 Play categories such as SOCIAL, TOOLS, ART_AND_DESIGN and the 18 GAME_ sub-categories. Pass the id that matches the store you are querying.
Which fields does a free app leave empty?
On Google Play a free app returns free true but price null and currency null, so a null price does not mean the app is missing a price, it means Play never publishes one. Apple fills price 0.0 and currency "USD" for the same case. On Apple, installs and contains_ads are always null; on Play, version, size_bytes and min_os are null and languages is an empty array.
What is the App Store API?
App Store API is a ReefAPI endpoint group for app details, rankings, ratings and reviews. It returns live JSON through POST requests under /app-store/v1.
Is the App Store API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. App Store calls use the same shared credit balance as every other ReefAPI engine.
Do I need an App Store login or account?
No login to App Store is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the App Store data?
The page example is captured from a live reviews call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the App Store API use?
App Store actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call App Store from an AI assistant or MCP client?
Yes. Connect ReefAPI once through MCP and your assistant can call app-store actions with the same key, credit pool and JSON envelope used by normal REST requests.