App Store Top Charts & App Search API
Pricing
from $0.18 / 1,000 app returneds
App Store Top Charts & App Search API
App Store top charts by category and country — free, paid, grossing, new — as ranked rows. Plus Google Play category listings, and app search across both stores: title, developer, price, rating, installs, icon, store link. No API key, no login. Google Play top charts are not available.
Pricing
from $0.18 / 1,000 app returneds
Rating
0.0
(0)
Developer
Insight Solutions
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
13 hours ago
Last modified
Categories
Share
The App Store's top charts as a flat table, by category and by country. Ask for us/top-free, gb/top-paid, us/top-grossing/6014 or de/new-free/7012 and get one row per rank: the app, the publisher, the price, the store link, the icon. Add a Google Play category and you get the apps Play shows on that category's page. Add a keyword and you get the search results from both stores, side by side, in each store's own ranking order.
No API key. No login. $0.30 per 1,000 apps, proxy included, entries that could not be read are free, and a run that returns nothing costs nothing at all.
One thing up front, because it matters more than anything else on this page: Google Play no longer publishes a top-sellers chart that can be read without a browser. This Actor does not offer one. See What is not here.
Try it in 30 seconds
{"appleCharts": ["us/top-free", "us/top-grossing/6014"],"chartSize": 50,"googleCategories": ["us/HEALTH_AND_FITNESS"],"searchQueries": ["meditation"],"maxResultsPerQuery": 25}
Five requests, about 170 rows: the US top free chart, the US top grossing games chart, the apps on Play's Health & Fitness page, and "meditation" on both stores.
Want a market rather than a keyword? {"appleCharts": ["us/top-free", "gb/top-free", "de/top-free", "jp/top-free"], "chartSize": 100} is four requests and 400 ranked rows. Want to watch one genre? {"appleCharts": ["us/top-grossing/7012"]}.
What comes back
One chart row per rank in an App Store chart:
{"ok": true,"rowType": "chart", // "chart" | "listing" | "app" | "diagnostic""input": "us/top-grossing/6014","store": "apple","country": "us","chart": "top-grossing","genreId": "6014","genreName": "Games","rank": 1,"appId": "1621328561","bundleId": "com.scopely.monopolygo","title": "MONOPOLY GO!","developer": "Scopely, Inc.","developerId": "305003647","developerUrl": "https://apps.apple.com/us/developer/scopely-inc/id305003647?uo=2","price": 0,"currency": "USD","formattedPrice": "Get", // localised: "Get", "Free", "£5.99""free": true,"category": "Games","releaseDate": "2023-04-11T07:00:00.000Z","iconUrl": "https://is1-ssl.mzstatic.com/image/thumb/…/100x100bb.png","url": "https://apps.apple.com/us/app/monopoly-go/id1621328561?uo=2","rating": null, // set includeAppDetails to fill these"ratingCount": null,"version": null,"description": null,"screenshots": null,"error": null,"errorType": null,"scrapedAt": "2026-09-11T16:00:45.311Z", // when this row was written — your time axis"source": "itunes.apple.com","sourceUrl": "https://itunes.apple.com/us/rss/topgrossingapplications/limit=50/genre=6014/json"}
One listing row per app on a Google Play category page:
{"ok": true,"rowType": "listing","input": "us/HEALTH_AND_FITNESS","store": "google","country": "us","language": "en","categoryId": "HEALTH_AND_FITNESS","categoryName": "Health & Fitness","section": null, // Play ships no carousel headings — see below"sectionId": "non_personalized_APPS_CATEGORY_recs_topic_WDAqUYiVfMs_RECOMMENDED_IN_TOPIC","rank": 1, // order of first appearance across the page's carousels"appId": "com.sec.android.app.shealth","bundleId": "com.sec.android.app.shealth","title": "Samsung Health","developer": "Samsung Electronics Co., Ltd.","rating": 3.1471076, // unrounded; Play renders "3.1""category": "Health & Fitness","price": 0,"currency": "USD","free": true,"installs": "10,000,000+", // Play publishes a band, not a number"iconUrl": "https://play-lh.googleusercontent.com/…","url": "https://play.google.com/store/apps/details?id=com.sec.android.app.shealth&hl=en&gl=US","scrapedAt": "2026-09-11T16:02:11.088Z","source": "play.google.com","sourceUrl": "https://play.google.com/store/apps/category/HEALTH_AND_FITNESS?hl=en&gl=US"}
And one app row per search hit, from either store:
{"ok": true,"rowType": "app","input": "meditation","store": "apple","query": "meditation","position": 1, // the store's own ranking — the ASO number"appId": "337472899","bundleId": "com.spotlightsix.zentimer","title": "Insight Timer: Meditate, Sleep","developer": "Insight Network Inc","rating": 4.89513,"ratingCount": 446151,"category": "Health & Fitness","price": 0,"free": true,"releaseDate": "2009-11-05T18:55:12.000Z","updatedAt": "2026-09-04T05:13:59.000Z","url": "https://apps.apple.com/us/app/insight-timer-meditate-sleep/id337472899?uo=4"}
Every row has every column, null where it does not apply, so a run mixing charts, categories and searches exports as one rectangular table. Anything that could not be read gets a free diagnostic row saying why.
Use cases
- Chart tracking. Run
us/top-freeandus/top-grossing/6014on a schedule and you have a daily time series of who is where.scrapedAtis the key;appIdis the join. - Competitive monitoring. Watch a rival's whole portfolio by grouping a chart on
developerId. - App store optimisation.
searchQueriesgives youpositionfor a keyword on both stores. Run it weekly and you can see a change in ranking rather than guess at one. - Market entry research. The same chart in
us,gb,deandjpis four different lists. That difference is the research. - Category benchmarking. A Play category listing plus
includeAppDetailsgives you the rating, install band and update cadence of everything Play is promoting in a category. - Feeding a model or an agent. One JSON object in, one flat array out.
How it works, and why it keeps working
The App Store charts come from Apple's own two feeds, and this Actor uses both because neither alone is enough:
rss.marketingtools.apple.comis the modern feed. It servestop-freeandtop-paidat 10, 25, 50 and 100 apps, in clean JSON, and it is about 0.1 KB of traffic per row. It has no grossing chart, no "new apps" chart and no genre filter at all. There is no 200-app size either — that URL answers HTTP 500, and the older feed silently stops at 100 too — so 100 is the deepest any App Store chart goes.itunes.apple.com/<cc>/rss/…is the older feed. It carries all six charts, it takes a genre ID, and it is the only Apple endpoint that hands over the bundle ID without a second request. It is also an XML document converted to JSON, which means a chart with exactly one app arrives as an object where a chart with two arrives as an array. Both shapes are handled and both are in the test suite.
The Actor routes each request to the feed that can actually answer it, and the source column on every row says which one did.
Genre IDs are validated before a request is sent, and that is a correctness feature, not a convenience. Apple answers an unknown genre ID with HTTP 200 and the overall chart — no error, no warning, nothing in the payload to say the filter was dropped. A capture of genre=99999 in the US store comes back as "Top Free Apps" with ChatGPT at rank 1, and a user who mistyped a genre would have no way to tell. So this Actor ships Apple's genre table, refuses an ID that is not in it with a free invalid-input row, and — belt and braces — discards a chart whose entries turn out not to be in the genre that was asked for.
Google Play pages are read the way a browser reads them. Play ships its store pages as a shell plus a set of AF_initDataCallback data blocks; the cards you see are built from those in the browser, which means the app titles are not in the markup at all. The Actor extracts the blocks and finds the app cards by shape — a node is a card when it carries a package name, a title and a /store/apps/details?id=… link together — rather than by a fixed path, so a renumbered block or a carousel moved one level deeper does not break it.
Nothing here needs a key, a cookie, a login or anyone's account. Every endpoint is one a browser or an RSS reader would hit.
Requests are paced and sessions rotate. 250–600 ms between successive requests of one job; each parallel worker has its own proxy session; a refusal earns exactly one retry from a different exit IP, and a second refusal ends that job with a free blocked row and every row already written kept.
What is not here
Google Play top charts. Play's "Top charts" are served by an internal RPC (vyAe2) that answers PlayDataError to every unauthenticated request — seven captures across the free, paid and grossing charts, no chart data in any of them — and the older /store/apps/collection/topselling_free page still loads but contains zero apps. Play's own category pages carry a "Top free / Top grossing / Top paid" widget with nothing behind it, which is as clear a statement as you will get. Neither is a scraping problem that better headers would solve; Play simply stopped publishing that data to the open web. Any tool that claims to give you Google Play top charts without a signed-in device is either using a paid third-party dataset or estimating. What this Actor offers on Play is what Play actually serves: category listing pages and search, both of which are ranked by Google and both of which are genuinely useful — but they are not a top-sellers chart and are not described as one anywhere in this Actor.
Carousel headings on Play category pages. The visible headings ("Recommended for you", "New releases") are fetched by the browser after the page has rendered and are in neither the HTML nor the page data. section is therefore null on every row, and sectionId — Google's own identifier for the carousel, which is in the page data — is what you group by instead. Saying null is more useful than inventing a label.
Reviews. Neither store's reviews are here. Our App Store & Google Play Reviews API does that.
Revenue, download counts and rank history. Nobody publishes them. Play publishes an install band; the App Store publishes nothing. Any exact figure is an estimate, and this Actor does not make estimates.
Input reference
| Field | Type | Default | What it does |
|---|---|---|---|
appleCharts | array | ["us/top-free", "us/top-grossing/6014"] | country/chart or country/chart/genreId. Charts: top-free, top-paid, top-grossing, new, new-free, new-paid |
chartSize | integer | 50 | 10–100 ranks per chart (Apple's feeds stop at 100) |
googleCategories | array | ["us/HEALTH_AND_FITNESS"] | country/CATEGORY — the apps on that Play category page |
searchQueries | array | ["meditation"] | Keywords to search both stores for |
stores | array | ["apple", "google"] | Which stores the search queries go to |
maxResultsPerQuery | integer | 25 | Apps per query per store. Apple's ceiling is 200; Play serves one page (~22) |
includeAppDetails | boolean | false | Fill the description, screenshots, version, size, minimum OS and content rating columns |
country | string | "us" | Default storefront for entries that do not name one |
language | string | "en" | Google Play's hl — the language of titles and descriptions |
maxConcurrency | integer | 3 | Charts, categories or searches read at once |
maxRunSecs | integer | 240 | Wall-clock budget for the whole run |
proxyConfiguration | object | {"useApifyProxy": true} | Datacenter by default; residential if Play starts refusing you |
Apple genre IDs, the ones you are most likely to want: 6014 Games, 6013 Health & Fitness, 6016 Entertainment, 6007 Productivity, 6015 Finance, 6012 Lifestyle, 6008 Photo & Video, 6005 Social Networking, 6017 Education, 6023 Food & Drink — and the game subgenres 7001 Action, 7012 Puzzle, 7014 Role Playing, 7015 Simulation, 7017 Strategy. The full table is in src/genres.js; the ID is the number in an apps.apple.com/…/genre/…/id6014 URL.
Output reference
| Column | Type | Notes |
|---|---|---|
ok, rowType | boolean, string | chart, listing, app or diagnostic |
input, store, country, language | string | Where the row came from |
chart, genreId, genreName | string | On chart rows |
categoryId, categoryName, section, sectionId | string | On listing rows. section is always null — see above |
query, position | string, integer | On app rows |
rank | integer | Chart position, or order of first appearance on a Play category page |
appId, bundleId | string | Apple's numeric ID / Play's package name |
title, developer, developerId, developerUrl | string | |
price, currency, formattedPrice, free | number, string, string, boolean | 0 is free; null is "not stated" |
rating, ratingCount | number, integer | Unrounded |
category | string | The app's own store category |
installs, installsMin | string, integer | Google Play only |
releaseDate, updatedAt | string | UTC ISO 8601 |
version, sizeBytes, minimumOs, contentRating, description, screenshots | Only with includeAppDetails | |
iconUrl, url | string | |
error, errorType | string | invalid-input, not-found, no-results, blocked, timeout, unavailable |
scrapedAt, source, sourceUrl | string | Which endpoint, and the exact address |
Pricing
| Event | FREE | BRONZE | SILVER | GOLD |
|---|---|---|---|---|
| Run started | $0.001 | $0.001 | $0.001 | $0.001 |
| Chart position returned | $0.0003 | $0.0003 | $0.0003 | $0.0003 |
| Category listing returned | $0.0003 | $0.0003 | $0.0003 | $0.0003 |
| App returned | $0.0003 | $0.0003 | $0.00024 | $0.00018 |
Proxy, compute and dataset storage are inside those numbers. There is no usage surcharge.
The example above — two charts at 50, one Play category, one keyword on both stores — is 75 chart rows, 50 listing rows and 45 app rows: $0.052 at the FREE tier, including the start fee. A daily US top-100 chart is $0.031 a run.
What you are never charged for
- Diagnostic rows. A chart that does not exist, a genre Apple would have ignored, a category Play has no page for, a search that matched nothing, a request that was refused twice — all of them file a free row explaining what happened.
- A run that returns nothing. If no chart, listing or app row could be retrieved, the run finishes FAILED and bills nothing at all, start fee included.
- Work your budget did not cover. Set
ACTOR_MAX_TOTAL_CHARGE_USDand the Actor stops fetching when it is reached, rather than fetching rows it would have to give away. - Retries. A blocked request retried from a fresh exit IP is one row when it succeeds, not two.
Limits, and the ones that might bite
Google Play has no public top-sellers chart. Said once at the top and again here, because it is the single most common thing people come to an Actor like this for. Play category listings and Play search are what is available.
The App Store's chart is a snapshot. Apple publishes today's chart and no history. Every run captures the chart as it stands; a time series is something you build by running on a schedule, and scrapedAt is the column to build it on.
Apple's modern chart feed is thin. top-free and top-paid come back with no price, no bundle ID, and a genre on only about four entries in five — ChatGPT at rank 1 of the US top-free chart arrives with no genre at all. That is what Apple publishes. includeAppDetails fills the gaps with one lookup per 100 apps; without it, those columns are honestly null.
includeAppDetails costs very different amounts on the two stores. Apple enriches 100 apps in one request. Google Play has no bulk endpoint, so every app is its own 1.2 MB page — an enriched 50-app category listing is fifty extra requests and several minutes. Raise maxRunSecs before you turn it on for Play.
Google Play search returns one page. Around 20 to 30 apps, 22 on the page this was built against. There is no "next page" to ask for, so maxResultsPerQuery above that has no effect on the Play side. Apple's search goes to 200.
A Play category page is several carousels, not a ranking. The apps are what Play chose to promote in that category for that country, deduplicated across the carousels and numbered by first appearance. It is a useful, Google-ranked list. It is not "the top 50 health apps".
Play has no version, size or minimum-OS for every app. An app whose build varies by device — Spotify is one — ships no version string on its page at all, and Play never states a download size. Those columns are null for such apps even with includeAppDetails on.
Prices are per storefront and are what the store shows. The gb chart is in GBP, the us chart in USD, and neither is converted. In-app purchases are not prices: plenty of free: true apps are subscription businesses.
The upstream format may change. Apple's feeds and Google Play's page structure change without notice — that is true of every tool that reads this data, including the ones that do not say so. When a shape changes, rows stop arriving and you get free blocked or no-results diagnostic rows rather than quietly wrong data, and a run that returns nothing bills nothing.
Rate and reliability. Requests go out through proxy sessions pinned per worker, one rotation per block, and a 250–600 ms pause between requests of the same job. Three jobs in parallel is the default because Play pages are around 2 MB each; raising maxConcurrency speeds a long list up and raises memory use with it.
Use it from an AI agent, or from code
One JSON object in, one flat array out — the shape agent runtimes want. The Actor runs with limited permissions, uses pay-per-event pricing and never enters Standby, so it works over the Apify MCP server and with x402 agentic payments. The Integrations tab pushes results to Slack, a webhook, Zapier, Make, Google Sheets, Snowflake or BigQuery.
curl -X POST "https://api.apify.com/v2/acts/insight.solutions~app-charts-api/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"appleCharts":["us/top-free"],"chartSize":50}'
# pip install apify-clientfrom apify_client import ApifyClientclient = ApifyClient("<APIFY_TOKEN>")run = client.actor("insight.solutions/app-charts-api").call(run_input={"appleCharts": ["us/top-grossing/6014", "gb/top-grossing/6014"],"chartSize": 100,"searchQueries": ["idle tycoon"],})for row in client.dataset(run["defaultDatasetId"]).iterate_items():if row["rowType"] == "chart":print(row["country"], row["rank"], row["title"], row["developer"])
FAQ
Do I need an Apple or Google developer account? No. Every source here is public: Apple's chart feeds, its search and lookup endpoints, and the Google Play website.
Why can't I get Google Play top charts?
Because Google stopped serving them to anything that is not a signed-in Play client. The RPC that backs the "Top charts" tab answers PlayDataError, and the old collection page returns an empty list. This Actor would rather tell you that than sell you a substitute labelled as a chart.
Can I get the top 200?
No — 100 is the deepest Apple publishes. The modern feed's /200/ URL answers HTTP 500 and the older feed returns 100 entries whatever limit you send (both checked 2026-09-11). chartSize therefore stops at 100; if Apple brings the longer chart back, raising the cap is a one-line change.
Why is rating null on my chart rows?
No Apple chart feed carries a star rating. Turn on includeAppDetails and it is filled in from one lookup per 100 apps.
Why did my genre ID get rejected? Because it is not one Apple filters on, and Apple would have answered it with the overall chart under your genre's name. The free diagnostic row names valid IDs.
How do I deduplicate between runs?
On (store, appId). Add country when you run several storefronts, and scrapedAt is your time dimension.
Does country change the results?
Completely. Both stores are per-country: different catalogues, different rankings, different prices, different currencies. An app published only in Germany is not in the us store at all.
What does rank mean on a Play listing row?
The order the app first appears in as the page's carousels are read top to bottom. Apps in more than one carousel are returned once, at the earliest position. It is Play's own ordering of what it chose to show.
What happens if one chart fails?
The others still run. The failed one produces a free diagnostic row and the run finishes SUCCEEDED. If every entry fails, the run finishes FAILED and you are billed nothing at all.
Is the data fresh? Live. Every run reads both stores at that moment; nothing is cached.
Legal and data-protection notes
- Public endpoints only. Apple's chart feeds are published for exactly this purpose; its search and lookup endpoints are the ones its own web store uses; Google Play's store pages are the pages any visitor loads. The Actor never logs in, never accepts cookies or session tokens, and never takes an API key belonging to anyone else.
- No personal data. Charts, listings and search results are about applications and their publishers. Reviews — which do contain personal data — are deliberately not in this Actor.
- A developer name can still be a person's name. Plenty of apps are published by individuals, and
developeris then personal data under most regimes. Have a lawful basis before you use it for outreach. - Store content belongs to its publisher. Titles, descriptions, icons and screenshots are copyrighted works. Indexing, analysis, ranking and linking are the ordinary uses and are what this is built for; republishing the descriptions or the artwork is your call and your responsibility.
- Not affiliated with Apple Inc. or Google LLC, nor with any app or publisher whose listing you retrieve. All names and trademarks belong to their owners and are used only to describe which public endpoints this Actor reads.
Our other Actors
Every Insight Solutions Actor is pay-per-result with no browser, no login and no API key, and every one of them returns free diagnostic rows instead of billing for failures. Prices are per 1,000 results.
Video, audio & social
- YouTube Transcript API — captions as timed segments, text, SRT or VTT, with language fallback and translation.
- YouTube Comments API — comments and replies with likes, pinned and hearted flags, newest or top sort.
- YouTube Channel API — a channel's videos, Shorts and live streams, plus YouTube search.
- Podcast Search, Episodes & Charts API — Apple Podcasts search, charts and full episode feeds.
- Bluesky Scraper — profiles, posts, followers and follows from the public AT Protocol API.
- Telegram Channel Scraper — posts, views and channel stats from public Telegram channels.
- Substack Scraper — posts with full free text, comments and publication profiles.
News, documents & the web
- Google News Search, Topics & Real Article URLs — news search and topic feeds with the publisher's real URL decoded.
- Website to Markdown — Content Extractor for LLMs & RAG — any site as clean Markdown, text and heading-aware chunks.
- Internet Archive API — archive.org search, item metadata, files and reviews.
- Wayback Machine Toolkit — archived URL inventories, snapshots and text diffs between dates.
- Website Technology Detector — the tech stack behind any site, with the evidence for each detection.
- Domain Intelligence API — DNS, RDAP registration, TLS certificate and HTTP facts in one row per domain.
- SEO Page Audit — sitemap crawl with on-page checks, structured data and broken-link reports.
- Keyword Suggestions API — Google, YouTube, Bing, Amazon and eBay autocomplete with alphabet and question expansions.
- Website Contact Extractor — emails, phone numbers and social profiles from any list of websites.
Business, finance & jobs
- Congress & Insider Trades API — STOCK Act periodic transaction reports and SEC Form 4 insider trades in one schema.
- SEC EDGAR API — filings, XBRL financials and full-text search by ticker or CIK.
- Y Combinator Companies, Batches & Founders — the YC directory with founders and social links, filterable by batch, industry and hiring status.
- Career Site Jobs API — jobs straight from Greenhouse, Lever, Ashby, Workable and 10+ other ATS career sites.
- New Job Postings Monitor — new, closed and changed postings on the career sites you watch.
- Shopify Products API — any Shopify store's catalogue, variants, prices and stock signals.
Apps & games
- App Store & Google Play Reviews API — reviews from both stores with ratings, versions and developer replies.
- Steam Reviews API — Steam reviews with playtime, helpfulness and game details.
- Steam Game Data API — prices, tags, review scores, live player counts and top charts.