# ASO Keyword Rank Tracker (App Store & Google Play) (`superslowsloth/aso-keyword-rank-tracker`) Actor

Track where your app ranks for any keyword in the Apple App Store and on Google Play - position, the competitors above you, their ratings and prices, in any storefront.

- **URL**: https://apify.com/superslowsloth/aso-keyword-rank-tracker.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (community)
- **Categories:** SEO tools, Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 keyword checkeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## ASO Keyword Rank Tracker (App Store & Google Play)

Tells you where your app sits in store search for the keywords you care about,
in whichever storefront you sell in - and who is above you.

One row per keyword per store, every run: the position, the competitors at the
top of that result list, their ratings and prices, and the timestamp the
measurement was taken at.

### Where the numbers come from

**Apple App Store** - the official iTunes Search API,
`https://itunes.apple.com/search`. It is an unauthenticated, documented
endpoint that returns results in Apple's own relevance order for the term. That
order is the App Store's ranking; nothing here is inferred.

**Google Play** - the Play search page, read from the data Google embeds in
it. Play returns roughly thirty results for a search and offers no deeper
paging without scrolling, so an Android rank is measured within that window.

### The keywords you do not rank for are rows too

A keyword your app does not appear for is the reason to run a rank tracker, so
it is never dropped. Those rows carry `rank: null` and `found: false`.

`rank` is **null**, not `0` and not `999`. A placeholder would average into any
chart built on this dataset as though it were a position, which silently
invents a trend. `results_returned` says how far the check actually looked, so
a null rank reads precisely: *not inside the first N*.

### Every check is charged once

Two spellings of one search - `habit  tracker` and `Habit Tracker` - are the
same request to both stores, so they are collapsed to one check and one charge
before anything is fetched. A store you supply no app id for is not searched
and is not charged.

### Output fields

| Field | Notes |
|---|---|
| `keyword` | The keyword exactly as you typed it, so a merged dataset joins back to your own list. |
| `store` | `ios` or `android`. |
| `country` | The storefront the search ran in. Rankings differ by storefront. |
| `language` | The language Play searched in. Null on App Store rows - see below. |
| `tracked_app_id` | The app id you supplied, normalised. |
| `checked_at` | UTC ISO-8601. A rank with no timestamp is not a measurement. |
| `rank` | 1-based position, or `null` when the app was not in the scanned window. |
| `found` | Whether the app was found at all. |
| `results_returned` | How many results the store returned; the limit `rank` can be trusted to. |
| `app_name`, `app_developer`, `app_url`, `app_icon_url` | The tracked app as this store describes it. All null when it was not found. |
| `app_rating` | Average rating out of 5. Null when the store publishes none. |
| `app_rating_count` | Number of ratings. App Store only - see below. |
| `app_price`, `app_currency` | Price in whole currency units; `0.0` for a free app, which is a real price. |
| `app_category` | The store's own primary category. |
| `top_results` | The head of the result list, in rank order: `rank`, `app_id`, `name`, `developer`, `rating`. |

### What this does not give

Stated rather than guessed. A missing value is always `null`, never `0`,
because a zero reads as a measurement that was taken.

- **No rating count on Google Play.** A Play search card carries an install
  band (`5,000,000+`), never an exact review count. `app_rating_count` is null
  on every Android row rather than filled with a number that means something
  else.
- **No language on App Store rows.** Apple's storefront decides the language;
  there is no separate knob, so reporting one would be inventing a parameter.
- **Google Play depth is fixed at about thirty results.** The `depth` setting
  applies to the App Store only. An Android app outside the first page reads as
  `rank: null`, and `results_returned` is what says how far we looked.
- **Ranks are relevance order, not a chart position.** This is where a search
  for that term puts your app. It is not a Top Free chart rank, and the two do
  move independently.
- **No search volume and no difficulty score.** Those are estimates that no
  store publishes. This actor reports only what the stores themselves return.
- **`app_price` of `0.0` is a real price.** A free app is priced zero; it is not
  the same as the null that means the store stated no price at all.

# Actor input Schema

## `keywords` (type: `array`):

The search terms to check your app's position for, one per line, e.g. "habit tracker", "daily planner". Each keyword is checked once per store you supply an app id for, and each check is one charge. Duplicate spellings that differ only in spacing or case are collapsed before anything is fetched, so you are never charged twice for the same search.

## `iosAppId` (type: `string`):

The app to track in Apple's App Store. Accepts the numeric id (1438388363), the bundle id (com.davetech.habit), or the full store URL you copied from your listing. Leave empty to skip the App Store entirely - nothing is fetched or charged for a store with no app id.

## `androidAppId` (type: `string`):

The app to track on Google Play. Accepts the package name (com.davetech.habit) or the full store URL. Leave empty to skip Google Play entirely - nothing is fetched or charged for a store with no app id.

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

Two-letter country code for the storefront to search, e.g. "us", "gb", "jp". Rankings differ by storefront, so this is part of the measurement and not a display preference.

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

Language code Google Play should search in, e.g. "en", "ja", "pt-BR". Ignored for the App Store, where the storefront decides the language and there is no separate setting - App Store rows carry a null language for exactly that reason.

## `depth` (type: `integer`):

How many App Store results to scan before concluding your app does not rank. Apple's own limit is 200 and anything higher is clamped to it. A rank outside this number is reported as null, never as a large placeholder, so it cannot be averaged into a trend line as though it were a position. Google Play returns a fixed page of about 30 results and ignores this setting.

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

Optional. Apple's Search API is an official unauthenticated endpoint and answered a plain datacenter address with no proxy at all on 2026-09-12. Google Play does rate-limit an address that searches quickly, and answers with its unusual-traffic page; a proxy is what gives the run a fresh address to retry on when that happens.

## Actor input object example

```json
{
  "keywords": [
    "habit tracker"
  ],
  "country": "us",
  "language": "en",
  "depth": 200,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `rankings` (type: `string`):

No description

# 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 = {
    "keywords": [
        "habit tracker"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/aso-keyword-rank-tracker").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 = {
    "keywords": ["habit tracker"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/aso-keyword-rank-tracker").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 '{
  "keywords": [
    "habit tracker"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call superslowsloth/aso-keyword-rank-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,superslowsloth/aso-keyword-rank-tracker"
        }
    }
}
```

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/vMCAVbHLuwmahHEBU/builds/gHnHSEefwgr0ane1V/openapi.json
