Carmentara

How to track App Store & Google Play keyword rankings daily (without an ASO subscription)

By the Carmentara team

Two rows of small off-white ceramic tiles stand like twin leaderboards beside a sheet of paper with a thin graphite line, with one copper tile raised in each row.

Stop paying hundreds a month for AppTweak, Sensor Tower or data.ai. Track keyword ranks on the App Store and Google Play every day, with history and alerts, on Apify's free $5 credit.

People find apps by typing a few words into the App Store or Google Play search box: "meditation", "sleep sounds", "mindfulness". Where your app lands for those words decides whether a new user sees it at all. But neither Apple nor Google gives you a free, exportable history of your organic keyword rank by country. Change your subtitle, ship a release, or watch a competitor climb, and you have no record of what moved and when.

The usual fixes hurt in different ways:

  • ASO SaaS (AppTweak, Sensor Tower, data.ai and similar) will track keywords for you, but plans often run to hundreds of dollars a month, which is a hard sell for an indie app or a small ASO team that only needs daily ranks for a short keyword list.
  • Checking by hand means opening each store, each country, each keyword in a private window, counting down to your app, and pasting the number into a spreadsheet. It works for two keywords. It falls apart for twenty, and you still have no reliable history.
  • No history means you can't tell a one-day blip from a week-long drop, and you can't prove to yourself (or a stakeholder) that last Tuesday's listing change did anything.

This guide covers three honest options. Pick the one that fits how many keywords and countries you care about.

  1. Free: check by hand (or with free storefront tools)
  2. Build it yourself on the public storefront endpoints
  3. Least effort: a scheduled Apify actor that keeps App Store + Google Play ranks in one feed

Option 1: Check by hand (free, slow)

  1. Open a private browser window, so you see what a logged-out visitor sees.
  2. On the App Store and Google Play, search each keyword for each country you care about (change the storefront country, or use the gl= / country picker).
  3. Count down to your app. Write the position, the date, the store and the country into a spreadsheet.
  4. Repeat tomorrow.

This is free and honest. It is also easy to miscount past the first screen, and almost nobody keeps it up every day across two stores and several countries. Results can also differ between a logged-in account and a private window — the stores personalise.

Option 2: Call the public endpoints yourself

You can script it. Apple exposes search and chart RSS/JSON endpoints; Google Play has public search pages and unofficial clients that read them. A weekend prototype that prints "Calm is #3 for meditation in the US App Store" is realistic.

What you then own forever:

  • Two different response shapes (Apple vs Google), plus country and language parameters.
  • Pagination and depth limits (Google Play search depth is capped around 30 results per query).
  • A place to store yesterday's ranks so you can compute a change.
  • A scheduler, retries, and someone to fix the scraper when a markup or endpoint changes.

It is doable. It is also a small product you then have to maintain. If that is your job, stop here and build it. If it isn't, option 3 exists so you don't have to.

Option 3: One scheduled actor for both stores

We built and maintain that tracker as an Apify actor: App Store & Google Play Keyword Rank Tracker (ASO). Its keyword-ranks mode returns where your apps (and competitors) sit for each keyword × country × store. What it does:

  • Covers App Store and Google Play in one feed, with the same row shape.
  • Gives you tracked-app ranks (rank, previousRank, rankChange, status) inside each keyword row.
  • Remembers the previous run via a named key-value store, so scheduled runs fill in the deltas.
  • Also has top-charts and keyword-suggestions modes when you want chart snapshots or autocomplete ideas.
  • Needs no Apple or Google developer account.
Diagram: keywords and tracked apps go into a daily Apify ASO Rank Tracker task, which writes dataset rows that feed Zapier/Make/n8n filters, Slack or email alerts, and Google Sheets history.
One scheduled run a day adds one row per keyword × country × store; filters and Sheets turn that into alerts and history.

Pricing: $0.002 per keyword-rank row (one keyword × country × store), $0.001 per top-chart entry, $0.0005 per keyword suggestion, plus a $0.00005 start fee per run. There is no monthly fee from us, and platform usage is not charged separately on pay-per-event.

Concrete free-credit example. Tracking 10 keywords in us and gb on both stores is 10 × 2 × 2 = 40 rows a day. Over a 30-day month that is 1,200 rows × $0.002 = $2.40, plus 30 × $0.00005 = $0.0015 in start fees.

How many daily checks fit in Apify's free $5/month credit? At $0.002 per keyword-rank row, $5 covers about 2,500 keyword × country × store checks a month (roughly 83 per day), before the tiny start fees. The 40-row example above uses under half of that. Unused credit does not roll over (Apify pricing: "$5 to spend in Apify Store or on your own Actors", no credit card required on the free plan).

No coding required

You can do the whole daily setup in the Apify Console, without writing any code:

  1. Open the actor in the Apify Console. Set Mode to keyword-ranks, fill in Keywords, Countries (ISO-2) and Tracked apps (ids or URLs), pick Stores, and turn on Only tracked apps (omit top list) so you only pay for the rows you care about.
  2. Click Save as a new task and run it once.
  3. Add a daily schedule for the task under Schedules (Apify schedules).
  4. Export: download the run's dataset as CSV, or wire Apify's Google Sheets integration in append mode so each day adds rows under the previous ones.

Apple ids are numeric (Calm is 571800810, Headspace is 493145008). Google Play uses package names (com.calm.android, com.getsomeheadspace.android). When the ids differ per store, prefix them: apple:… and google:….

Run it from code

Python, using the official apify-client package (version 3 or later). This is the input we actually ran on 5 October 2026:

Python
# pip install "apify-client>=3"
import os

from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run_input = {
    "mode": "keyword-ranks",
    "keywords": ["meditation", "sleep sounds", "mindfulness", "sleep"],
    "countries": ["us", "gb"],
    "stores": ["apple", "google"],
    "trackedApps": [
        "apple:571800810",                         # Calm (App Store)
        "apple:493145008",                         # Headspace (App Store)
        "google:com.calm.android",                 # Calm (Google Play)
        "google:com.getsomeheadspace.android",     # Headspace (Google Play)
    ],
    "onlyTrackedApps": True,       # one row per keyword × country × store (cheapest)
    "maxResultsPerKeyword": 50,    # Apple up to 200; Google Play caps at 30
    "maxPpeChargeUSD": 0.04,       # hard cap per run
    "deltaStoreName": "aso-tutorial-blog-20261005",
}

run = client.actor("carmentara/aso-rank-tracker").call(run_input=run_input)

for item in client.dataset(run.default_dataset_id).iterate_items():
    store = item["store"]
    country = item["country"]
    keyword = item["keyword"]
    for t in item.get("tracked") or []:
        rank = f"#{t['rank']}" if t.get("rank") is not None else "not ranked"
        title = t.get("title") or t["appId"]
        print(f"{store:<6} {country}  {keyword:<14}  {title:<32}  {rank:<11}  change: {t.get('rankChange')}")

We ran that input twice on the same day so previousRank / rankChange would fill in (a real multi-day history needs a daily schedule). Second-run excerpt for the US storefronts:

Bash
# apple  us  mindfulness     Calm                              #5           change: 0
# apple  us  mindfulness     Headspace: Sleep & Meditation     #1           change: 0
# apple  us  meditation      Calm                              #3           change: 0
# apple  us  meditation      Headspace: Sleep & Meditation     #2           change: 0
# apple  us  sleep sounds    Calm                              #5           change: 0
# apple  us  sleep sounds    493145008                         not ranked   change: None
# apple  us  sleep           Calm                              #4           change: None
# apple  us  sleep           Headspace: Sleep & Meditation     #8           change: -3
# google us  meditation      Calm - Sleep, Meditate, Relax     #7           change: 0
# google us  meditation      Headspace: Sleep & Meditation     #3           change: 0
# google us  sleep sounds    Calm - Sleep, Meditate, Relax     #6           change: 0
# google us  sleep sounds    Headspace: Sleep & Meditation     #14          change: 0
# google us  mindfulness     Calm - Sleep, Meditate, Relax     #10          change: 0
# google us  mindfulness     Headspace: Sleep & Meditation     #4           change: 0
# google us  sleep           Calm - Sleep, Meditate, Relax     #8           change: 0
# google us  sleep           Headspace: Sleep & Meditation     #9           change: 0

change is None on the first sighting of a keyword × app (and when an app is not ranked). On this second pass, Headspace dropped three places for "sleep" on the US App Store (rankChange: -3) between two runs a few minutes apart — storefront results move, which is exactly why a filter on the delta matters more than a single screenshot. The same 16 keyword × country × store rows also covered Great Britain; each run cost 16 × $0.002 + $0.00005 = $0.03205.

Grid of US App Store and Google Play ranks for Calm and Headspace across four meditation and sleep keywords on 5 October 2026, including Headspace at #1 for mindfulness on the App Store and a -3 drop for sleep.
The same second run as the output above, as a grid. #1 cells are highlighted; "not ranked" means past the scanned depth.

What a row looks like

A real keyword-ranks row from that run (US App Store, "meditation"):

JSON
{
  "store": "apple",
  "country": "us",
  "language": "en",
  "keyword": "meditation",
  "checkedAt": "2026-10-05T11:15:54.134Z",
  "resultsCount": 50,
  "tracked": [
    {
      "appId": "571800810",
      "title": "Calm",
      "rank": 3,
      "previousRank": 3,
      "rankChange": 0,
      "status": "same"
    },
    {
      "appId": "493145008",
      "title": "Headspace: Sleep & Meditation",
      "rank": 2,
      "previousRank": 2,
      "rankChange": 0,
      "status": "same"
    }
  ],
  "sourceUrl": "https://apps.apple.com/us/search?term=meditation"
}

Turn Only tracked apps off (and set Top N details per check) if you also want the top list of competitors in each row. Those still bill as one keyword-rank row per keyword × country × store; you are not charged per competitor inside top.

Or pull today's ranks with curl

Once the input is saved as a task, fetch the latest successful dataset as CSV:

Bash
curl -fsS "https://api.apify.com/v2/actor-tasks/your-username~your-task-name/runs/last/dataset/items?status=SUCCEEDED&format=csv" \
  -H "Authorization: Bearer $APIFY_TOKEN" > todays-aso-ranks.csv

In Google Sheets, the same URL works with =IMPORTDATA("...&token=YOUR_APIFY_TOKEN"). Anyone who can edit the sheet can see the token, so prefer the Google Sheets integration in append mode for a real history.

Make it daily, and get alerts on drops

  1. In the Apify Console, open the actor, enter the input above and click Save as a new task.
  2. On the task, add a Schedule that runs once a day, for example 0 7 * * * in your timezone (Apify schedules).
  3. Keep the keyword spelling and the Delta store name stable, so each run compares with the previous one.

Get an alert when a rank drops. Apify's Slack integration and webhooks fire on run events (succeeded / failed). On their own, they tell you that a run finished, not that a rank moved. To alert only when a tracked app drops — for example rankChange <= -3, or when an app leaves the top 10 (rank was ≤ 10 and is now empty / worse) — route the finished task's dataset through Zapier, Make or n8n. Trigger on the finished task run, fetch the dataset items, add a filter (Zapier filters, Make filters, n8n Filter node), then send the matching rows to Slack or email. Nested tracked[] fields flatten in most of those tools; filter on the tracked-app rank change, not only the parent row.

Bonus: keyword suggestions and top charts

The same actor has two other modes we smoke-tested the same day:

  • keyword-suggestions — seed a word like sleep and get autocomplete ideas from both stores (we got 15 suggestions for US App Store + Google Play for $0.00755).
  • top-charts — snapshot top-free / top-paid (Apple also supports top-grossing; Google Play top-grossing is not supported and is skipped with a warning).
Keyword suggestions from the seed “sleep” on the US App Store and Google Play on 5 October 2026, including sleeper, sleep tracker and sleep sounds.
Autocomplete ideas from seed "sleep". Use them to grow the keyword list you track daily.
US top-free chart snapshot, top 10 on App Store and Google Play on 5 October 2026.
A top-free snapshot is useful for category context; it is billed per chart entry ($0.001), separate from keyword-rank rows.

Limitations (read these before you rely on a number)

  • Google Play search depth is capped at about 30 results per query by the public endpoints. If your app is deeper than that, the row will say it is not ranked even though a logged-in user might still find it further down.
  • Google Play top-grossing is not supported (the public library returns top-free). The actor skips it with a warning.
  • Ranks are what a logged-out visitor sees. Storefront personalisation, A/B tests and ads can make a logged-in phone look different.
  • Apple top charts stop at 100 entries (Apple's RSS limit).
  • rankChange is positive when an app moved up. Empty / null means there was nothing to compare yet, or the app was not ranked.

Tips for useful tracking

  • Track the words users type, not only your brand name. Start with category head terms, then the jobs ("sleep sounds", "breathing exercises").
  • Add one or two competitors per store. Your own rank means more when you can see who moved around you.
  • Use apple: / google: prefixes when the identifiers differ per store (numeric Apple id vs Play package name).
  • Cap spend with maxPpeChargeUSD on every task, so a bad input cannot surprise you.
  • Watch the trend, not one day. A three-place move between two runs a few minutes apart can be noise. A drop that holds for a week is worth a look — that is what the daily schedule is for.

Ready to automate App Store & Google Play keyword tracking?

For two keywords in one country, a private window and a spreadsheet work. For a daily rank history on both stores that you don't have to maintain:

  1. Open the App Store & Google Play Keyword Rank Tracker (ASO) on Apify.
  2. Pick keyword-ranks mode, enter your keywords, countries and tracked app ids, and turn on Only tracked apps.
  3. Schedule it daily. Setups like the 10-keyword / 2-country example above stay inside Apify's free $5 monthly credit.

Questions or feature requests? Open an issue on the actor's Issues tab.