DEV Community

Omar Eldeeb
Omar Eldeeb

Posted on • Originally published at datatooly.xyz

App Store Top Charts API: Free, Key-Free, and CORS-Open

If you've ever wanted an app store top charts API that you can hit straight from a browser tab — no API key, no OAuth dance, no server proxy — there's good news. Apple still serves a legacy iTunes RSS feed that returns the App Store top charts as plain JSON, and (the part most people miss) it's CORS-open. That means a single fetch() from client-side JavaScript works. No backend required.

This post walks through exactly how the endpoint is shaped, what the JSON looks like, the limits you'll hit, and where it stops being usable from the browser. Everything here is verified against the live feed, with a runnable example you can paste into your console right now.

The endpoint

The pattern is:

https://itunes.apple.com/{cc}/rss/{chart}/limit={N}/json
Enter fullscreen mode Exit fullscreen mode

Three pieces matter:

  • {cc} — a two-letter country code (us, gb, jp, de, br, …). Charts are per-country, so the US top free list is often very different from Japan's.
  • {chart} — one of three values:
    • topfreeapplications — ranked by download velocity (free apps)
    • toppaidapplications — ranked by download velocity (paid apps)
    • topgrossingapplications — ranked by revenue, which includes in-app purchases (this is why a free-to-download game with aggressive IAP can top grossing while sitting far down the free chart)
  • {N} — how many entries you want, e.g. limit=100.

So the US top free applications, top 100, is:

https://itunes.apple.com/us/rss/topfreeapplications/limit=100/json
Enter fullscreen mode Exit fullscreen mode

That's the whole API. No registration.

Why this works from a browser

The thing that makes this endpoint special for front-end developers is that itunes.apple.com returns a permissive Access-Control-Allow-Origin header on these RSS responses. Your browser won't block the cross-origin read. You can build a chart widget, a dashboard, or a quick research tool entirely client-side.

Here's a real, runnable example. Drop it into your browser console or a <script> tag and it returns immediately:

async function getTopCharts(country = "us", chart = "topfreeapplications", limit = 25) {
  const url = `https://itunes.apple.com/${country}/rss/${chart}/limit=${limit}/json`;
  const res = await fetch(url);
  if (!res.ok) throw new Error(`Apple RSS responded ${res.status}`);

  const data = await res.json();
  const entries = data.feed.entry ?? [];

  return entries.map((entry, i) => ({
    rank: i + 1,
    name: entry["im:name"].label,
    developer: entry["im:artist"].label,
    category: entry.category?.attributes?.label ?? null,
    url: entry.link?.attributes?.href ?? null,
  }));
}

// Top 10 free apps in the US App Store
getTopCharts("us", "topfreeapplications", 10).then(console.table);
Enter fullscreen mode Exit fullscreen mode

And the equivalent one-liner with curl, for shell and CI use:

curl -s "https://itunes.apple.com/us/rss/topfreeapplications/limit=10/json" \
  | jq '.feed.entry[] | {name: .["im:name"].label, dev: .["im:artist"].label}'
Enter fullscreen mode Exit fullscreen mode

The JSON shape

The response is a single object with one top-level feed key. The chart itself lives in feed.entry, an array where each element is one ranked app. Position in the array is the rank — index 0 is #1.

Each entry I pulled from the live feed contains these fields:

  • im:name — the app name (read .label)
  • im:artist — the developer/publisher (read .label; it may also carry a developer URL in attributes.href)
  • category — genre, with the human-readable name under attributes.label and the genre ID under attributes.im:id
  • link — the App Store URL under attributes.href
  • id — the canonical app store id, including the numeric im:id attribute
  • im:image — usually three sizes of icon
  • im:price — formatted price plus an amount/currency attribute pair
  • summary, rights, title, im:contentType

The slightly awkward part is Apple's namespaced keys (im:name, im:artist) and the consistent { label, attributes } wrapper on almost every field. Once you internalize "the value I want is usually under .label, and the metadata is under .attributes," parsing is trivial. The mapping function above handles it.

The limits (so you don't get surprised)

A few honest constraints worth knowing before you build on this:

  1. The feed caps at 100 entries per chart. You can ask for limit=200, but you'll get at most 100 back. There is no offset/pagination parameter to walk deeper into the rankings. If you need rank 101+, this feed can't give it to you.
  2. It's per-country, one country per request. Want the top charts for 30 markets? That's 30 requests. There's no "all countries" call.
  3. It's overall charts only via this simple path. The three chart types above are the clean, reliable ones. Category-scoped charts exist on Apple's side but aren't a first-class part of this simple RSS path.
  4. It's the legacy feed. Apple has a newer marketing-tools feed (more on that next), and while the iTunes RSS endpoint has been stable for years, it's not formally a "supported product." Treat it as best-effort.

For a huge share of use cases — a "what's trending today" widget, competitor monitoring, a side-project leaderboard — 100 apps per chart per country is plenty.

The newer feed: server-side only

You may run into Apple's newer endpoints at rss.marketingtools.apple.com (also referenced as applemarketingtools.com). These return similar top-charts data and are perfectly usable — but not from a browser. Those endpoints do not send permissive CORS headers, so a client-side fetch() to them will be blocked by the browser's same-origin policy.

So the rule of thumb is simple:

  • Browser / client-side code → use itunes.apple.com/{cc}/rss/... (CORS-open).
  • Server-side code (Node, Python, a cron job, a backend route) → either feed works, including the newer marketing-tools one.

Don't try to call rss.marketingtools.apple.com from front-end JavaScript and expect it to work; it won't, and the failure looks like a confusing CORS error rather than a clear message.

What about Google Play?

This is the other honest caveat. There is no equivalent CORS-open, key-free JSON feed for Google Play top charts. Play's charts aren't exposed as a browser-fetchable JSON endpoint the way Apple's RSS is, so any "Play top charts" lookup needs to run server-side (typically through a proxy or a scraping layer) rather than from the browser. If your project needs both stores, plan for an App Store-from-browser / Play-from-server split.

Try it live, then scale it up

If you just want to see the App Store top charts right now without writing a line of code, I built a free tool that runs this exact iTunes RSS feed live in your browser: datatooly.xyz/app-store-top-charts. Pick a country and a chart type and it fetches the real feed client-side — the same endpoint described above, no key, nothing fake. It's a good way to eyeball the data shape before you wire it into your own code.

When you outgrow the 100-app, one-country-at-a-time, no-history ceiling of the raw feed, the same data is available at scale through the App Store + Google Play Rank Tracker actor on Apify. It covers 150+ countries, all chart types plus category charts, per-app enrichment (ratings, reviews, screenshots), rank deltas with risers/fallers and a forecast, scheduled history so you can track movement over time, and JSON/CSV/API output — including Google Play, which (as noted) you can't reach from the browser. It's free to start, then pay-as-you-go.

Disclosure: I built both the free tool and the Apify actor.

TL;DR

  • Endpoint: https://itunes.apple.com/{cc}/rss/{topfree|toppaid|topgrossing}applications/limit={N}/json
  • CORS-open → works from a browser, no API key
  • Parse feed.entry[]; read names/devs/categories under .label, links/ids under .attributes
  • Caps at 100 per chart, one country per call, no deep pagination
  • Top Free/Paid = download velocity; Top Grossing = revenue incl. IAP
  • Use the newer rss.marketingtools.apple.com feed server-side only (not CORS-open)
  • Google Play has no browser-fetchable equivalent — proxy it server-side

Copy the fetch() snippet above and you'll have live App Store top charts in under a minute.

Top comments (0)