# App Store Top Charts & App Search API (`insight.solutions/app-charts-api`) Actor

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.

- **URL**: https://apify.com/insight.solutions/app-charts-api.md
- **Developed by:** [Insight Solutions](https://apify.com/insight.solutions) (community)
- **Categories:** E-commerce, Marketing, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.18 / 1,000 app returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## App Store Top Charts & App Search API

**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](#what-is-not-here).

### Try it in 30 seconds

```json
{
  "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:

```jsonc
{
  "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:

```jsonc
{
  "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:

```jsonc
{
  "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-free` and `us/top-grossing/6014` on a schedule and you have a daily time series of who is where. `scrapedAt` is the key; `appId` is the join.
- **Competitive monitoring.** Watch a rival's whole portfolio by grouping a chart on `developerId`.
- **App store optimisation.** `searchQueries` gives you `position` for 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`, `de` and `jp` is four different lists. That difference is the research.
- **Category benchmarking.** A Play category listing plus `includeAppDetails` gives 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.com` is the modern feed. It serves `top-free` and `top-paid` at 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](https://apify.com/insight.solutions/app-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_USD` and 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.

```bash
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}'
```

```python
## pip install apify-client
from apify_client import ApifyClient

client = 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 `developer` is 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](https://apify.com/insight.solutions/youtube-transcript-api) — captions as timed segments, text, SRT or VTT, with language fallback and translation.
- [YouTube Comments API](https://apify.com/insight.solutions/youtube-comments-api) — comments and replies with likes, pinned and hearted flags, newest or top sort.
- [YouTube Channel API](https://apify.com/insight.solutions/youtube-channel-api) — a channel's videos, Shorts and live streams, plus YouTube search.
- [Podcast Search, Episodes & Charts API](https://apify.com/insight.solutions/podcast-api) — Apple Podcasts search, charts and full episode feeds.
- [Bluesky Scraper](https://apify.com/insight.solutions/bluesky-scraper) — profiles, posts, followers and follows from the public AT Protocol API.
- [Telegram Channel Scraper](https://apify.com/insight.solutions/telegram-channel-scraper) — posts, views and channel stats from public Telegram channels.
- [Substack Scraper](https://apify.com/insight.solutions/substack-scraper) — posts with full free text, comments and publication profiles.

**News, documents & the web**

- [Google News Search, Topics & Real Article URLs](https://apify.com/insight.solutions/google-news-api) — news search and topic feeds with the publisher's real URL decoded.
- [Website to Markdown — Content Extractor for LLMs & RAG](https://apify.com/insight.solutions/website-content-extractor) — any site as clean Markdown, text and heading-aware chunks.
- [Internet Archive API](https://apify.com/insight.solutions/internet-archive-api) — archive.org search, item metadata, files and reviews.
- [Wayback Machine Toolkit](https://apify.com/insight.solutions/wayback-toolkit) — archived URL inventories, snapshots and text diffs between dates.
- [Website Technology Detector](https://apify.com/insight.solutions/website-tech-detector) — the tech stack behind any site, with the evidence for each detection.
- [Domain Intelligence API](https://apify.com/insight.solutions/domain-intelligence-api) — DNS, RDAP registration, TLS certificate and HTTP facts in one row per domain.
- [SEO Page Audit](https://apify.com/insight.solutions/seo-page-audit) — sitemap crawl with on-page checks, structured data and broken-link reports.
- [Keyword Suggestions API](https://apify.com/insight.solutions/keyword-suggestions-api) — Google, YouTube, Bing, Amazon and eBay autocomplete with alphabet and question expansions.
- [Website Contact Extractor](https://apify.com/insight.solutions/website-contact-extractor) — emails, phone numbers and social profiles from any list of websites.

**Business, finance & jobs**

- [Congress & Insider Trades API](https://apify.com/insight.solutions/congress-insider-trades-api) — STOCK Act periodic transaction reports and SEC Form 4 insider trades in one schema.
- [SEC EDGAR API](https://apify.com/insight.solutions/sec-edgar-api) — filings, XBRL financials and full-text search by ticker or CIK.
- [Y Combinator Companies, Batches & Founders](https://apify.com/insight.solutions/yc-companies-directory) — the YC directory with founders and social links, filterable by batch, industry and hiring status.
- [Career Site Jobs API](https://apify.com/insight.solutions/ats-jobs-api) — jobs straight from Greenhouse, Lever, Ashby, Workable and 10+ other ATS career sites.
- [New Job Postings Monitor](https://apify.com/insight.solutions/job-postings-monitor) — new, closed and changed postings on the career sites you watch.
- [Shopify Products API](https://apify.com/insight.solutions/shopify-products-api) — any Shopify store's catalogue, variants, prices and stock signals.

**Apps & games**

- [App Store & Google Play Reviews API](https://apify.com/insight.solutions/app-reviews-api) — reviews from both stores with ratings, versions and developer replies.
- [Steam Reviews API](https://apify.com/insight.solutions/steam-reviews-api) — Steam reviews with playtime, helpfulness and game details.
- [Steam Game Data API](https://apify.com/insight.solutions/steam-store-stats-api) — prices, tags, review scores, live player counts and top charts.

# Actor input Schema

## `appleCharts` (type: `array`):

One entry per chart, written as `country/chart` or `country/chart/genreId`. Charts: **`top-free`**, **`top-paid`**, **`top-grossing`**, **`new`**, **`new-free`**, **`new-paid`**. The country is a two-letter storefront code (`us`, `gb`, `de`, `jp`) — every storefront has its own chart. The optional third part is Apple's **numeric genre ID**: `6014` Games, `6013` Health & Fitness, `6016` Entertainment, `6007` Productivity, `6015` Finance, `7012` Games — Puzzle, `7017` Games — Strategy. Genre *names* are not accepted and an unknown genre ID is refused with a free diagnostic row: Apple answers an unknown genre with the **overall** chart and HTTP 200, so a typo would otherwise return the wrong chart and look right. Duplicates are read, and billed, once.

## `chartSize` (type: `integer`):

How deep each App Store chart goes, 10 to 100. Apple's chart feeds stop at 100 ranks — both the modern feed (published at exactly 10, 25, 50 and 100; any other number is served from the next size up and trimmed) and the older feed used for grossing, new and per-genre charts, which ignores anything above 100. There is no top 200 any more (checked 2026-09-11).

## `googleCategories` (type: `array`):

One entry per Google Play category page, written as `country/CATEGORY` — for example `us/HEALTH_AND_FITNESS`, `de/GAME_PUZZLE`, `gb/FINANCE`. You get **the apps Play shows on that category's page**: its carousels, deduplicated, ranked by where each app first appears. Categories are `ART_AND_DESIGN`, `BOOKS_AND_REFERENCE`, `BUSINESS`, `COMMUNICATION`, `DATING`, `EDUCATION`, `ENTERTAINMENT`, `FINANCE`, `FOOD_AND_DRINK`, `HEALTH_AND_FITNESS`, `LIFESTYLE`, `MAPS_AND_NAVIGATION`, `MEDICAL`, `MUSIC_AND_AUDIO`, `NEWS_AND_MAGAZINES`, `PERSONALIZATION`, `PHOTOGRAPHY`, `PRODUCTIVITY`, `SHOPPING`, `SOCIAL`, `SPORTS`, `TOOLS`, `TRAVEL_AND_LOCAL`, `VIDEO_PLAYERS`, `WEATHER` and the `GAME_*` family. **This is not a Google Play top-sellers chart** — Play no longer serves one publicly, and this Actor does not pretend otherwise.

## `searchQueries` (type: `array`):

Keywords to search the app stores for. Each query returns up to `maxResultsPerQuery` `app` rows per store in the store's own ranking order — which is the ranking an app store optimisation report is about. This is the input for "every meditation app on both stores", or for tracking where your app sits for a keyword week to week.

## `stores` (type: `array`):

Which stores the **search queries** go to. It has no effect on `appleCharts` (App Store only) or `googleCategories` (Google Play only). Leave both selected to get one row per app per store, which is how you compare a keyword's results side by side.

## `maxResultsPerQuery` (type: `integer`):

How many apps each search query returns per store. The App Store's own ceiling is 200 and asking for more does not get more. Google Play serves one page of results — around 20 to 30 apps, 22 on the capture this was built against — and there is no "next page" to ask for, so a larger number has no effect on the Play side.

## `includeAppDetails` (type: `boolean`):

Fill in the columns a chart or a listing does not carry: `description`, `screenshots`, `version`, `sizeBytes`, `minimumOs`, `contentRating`, and — on App Store charts — the star rating, rating count and price. **The two stores charge very different amounts of work for this.** Apple looks up 100 apps in one request, so an enriched Top 200 is two extra requests. Google Play has no such endpoint: every app is its own 1.2 MB page, so an enriched 50-app category listing is fifty extra requests and takes a few minutes. Off by default. It adds nothing to App Store *search* rows, which already carry every field Apple has.

## `country` (type: `string`):

Two-letter ISO country code, lower case. It is the default for any `appleCharts` or `googleCategories` entry that does not name its own country, and it is the storefront every search query runs in. Both stores are per-country: catalogues, rankings, prices and currencies all differ, and an app published only in Germany is not in the `us` store at all.

## `language` (type: `string`):

Two-letter language code for Google Play's `hl` parameter — it decides the language of the titles, descriptions and category names Play returns. It does not change which apps come back; `country` does that. Apple's endpoints are keyed on the storefront rather than on a language, so this has little effect on App Store rows.

## `maxConcurrency` (type: `integer`):

How many charts, category pages or searches are read at once. Each parallel worker keeps its own proxy session, so one blocked page burns only its own exit IP. Google Play category pages are around 2 MB each, so raising this raises memory as well as speed.

## `maxRunSecs` (type: `integer`):

Wall-clock budget for the whole run. When it is reached the Actor stops fetching, keeps and bills for every row it already wrote, and files a free diagnostic row for each entry it never reached. A chart stopped part-way keeps its ranks. Nothing is charged for work that did not happen. Raise it when you turn on `includeAppDetails` for Google Play.

## `proxyConfiguration` (type: `object`):

Apple's chart, search and lookup endpoints and Google Play's store pages all answered Apify's datacenter proxy in every capture this Actor was built against, so the default is datacenter — much cheaper than residential, and the proxy cost is already inside the per-row price. Switch to residential if you are reading many Play pages in one run and start seeing `blocked` rows. Sessions rotate automatically when an exit IP is refused.

## Actor input object example

```json
{
  "appleCharts": [
    "us/top-free",
    "gb/top-paid",
    "us/top-grossing/6014",
    "de/new-free/7012"
  ],
  "chartSize": 50,
  "googleCategories": [
    "us/HEALTH_AND_FITNESS",
    "us/GAME_PUZZLE",
    "de/FINANCE"
  ],
  "searchQueries": [
    "meditation",
    "habit tracker",
    "budget planner"
  ],
  "stores": [
    "apple",
    "google"
  ],
  "maxResultsPerQuery": 25,
  "includeAppDetails": false,
  "country": "us",
  "language": "en",
  "maxConcurrency": 3,
  "maxRunSecs": 240,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One row per chart position, per app on a Google Play category page, and per search hit — rank, app, developer, price, rating, installs, icon and store link. Entries that could not be read get a free diagnostic row saying why. Delivered as JSON items in the default dataset.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "appleCharts": [
        "us/top-free",
        "us/top-grossing/6014"
    ],
    "chartSize": 50,
    "googleCategories": [
        "us/HEALTH_AND_FITNESS"
    ],
    "searchQueries": [
        "meditation"
    ],
    "stores": [
        "apple",
        "google"
    ],
    "maxResultsPerQuery": 25,
    "includeAppDetails": false,
    "country": "us",
    "language": "en",
    "maxConcurrency": 3,
    "maxRunSecs": 240,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("insight.solutions/app-charts-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "appleCharts": [
        "us/top-free",
        "us/top-grossing/6014",
    ],
    "chartSize": 50,
    "googleCategories": ["us/HEALTH_AND_FITNESS"],
    "searchQueries": ["meditation"],
    "stores": [
        "apple",
        "google",
    ],
    "maxResultsPerQuery": 25,
    "includeAppDetails": False,
    "country": "us",
    "language": "en",
    "maxConcurrency": 3,
    "maxRunSecs": 240,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("insight.solutions/app-charts-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "appleCharts": [
    "us/top-free",
    "us/top-grossing/6014"
  ],
  "chartSize": 50,
  "googleCategories": [
    "us/HEALTH_AND_FITNESS"
  ],
  "searchQueries": [
    "meditation"
  ],
  "stores": [
    "apple",
    "google"
  ],
  "maxResultsPerQuery": 25,
  "includeAppDetails": false,
  "country": "us",
  "language": "en",
  "maxConcurrency": 3,
  "maxRunSecs": 240,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call insight.solutions/app-charts-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,insight.solutions/app-charts-api"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/afhj6l3Wltrveb9Vr/builds/gFnrD6vhjJ40mduiV/openapi.json
