# ASO Keyword Scraper: App Store Rank Tracker (`axiorasolutions/aso-keyword-scraper`) Actor

Scrape App Store search results for any keyword and country storefront. Returns each app exact rank, plus name, developer, price, rating, rating count, genres, screenshots and description. Also resolves app metadata by ID, bundle ID or URL. Built for ASO and competitor tracking.

- **URL**: https://apify.com/axiorasolutions/aso-keyword-scraper.md
- **Developed by:** [Axiora Solutions](https://apify.com/axiorasolutions) (community)
- **Categories:** Marketing, Business, For creators
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 1,000 app rankings

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## App Store Keyword Rankings & ASO Scraper

App Store keyword rankings, made exact: this Actor returns the precise App Store search rank of every app for any keyword and country storefront you give it, plus the app's full store metadata — developer, price, rating, rating count, genre, screenshots, description and update date. Rankings are measured per storefront, so the same app can sit at #3 in the US and #40 in Germany, and no API key, Apple account or login is needed. Run it to answer the three questions ASO turns on: where do I rank, who is beating me, and is the keyword worth fighting for?

### What you get

- `rank` — the exact position (1, 2, 3 …) Apple returns for each app, per keyword, per storefront. Real rank, not a reconstructed or vendor-invented score.
- `appName`, `developerName`, `primaryGenre`, `averageUserRating`, `userRatingCount` — the full competitive snapshot on every row.
- `price`, `formattedPrice`, `currency`, `isFree` — monetisation per storefront, so you see where a niche is paid and where it is free-only.
- `keywordMatchInTitle` and `keywordMatchInDescription` — whether the ranked app uses your keyword in its own name, Apple's strongest ranking signal.
- `screenshotUrls`, `descriptionChars`, `supportedLanguages`, `minimumOsVersion` and `version` — listing metadata for a visual and textual teardown.
- `recordHash` — deterministic over app, keyword and storefront, so two scheduled runs diff into a rank-change report.

### Quick start

1. Add one or more keywords to **Keywords to rank for** — phrase them the way a real user types them (`habit tracker`, `budget app`). The field comes prefilled, so you can also just run it as-is.
2. Add **Country storefronts** as two-letter codes (`us`, `gb`, `de`, `jp`). Every storefront is measured separately.
3. Run it with this minimal input:

```json
{
  "keywords": ["habit tracker", "budget app"],
  "countries": ["us"],
  "resultsPerKeyword": 50
}
```

4. Click **Start**, then open the **Rankings**, **Competitive landscape** and **App metadata** dataset tabs.

### Example output

One representative dataset row (US storefront, keyword `habit tracker`):

```json
{
  "recordType": "ranking",
  "ok": true,
  "errorCode": null,
  "keyword": "habit tracker",
  "storefront": "us",
  "rank": 4,
  "appId": "1091189122",
  "bundleId": "com.example.habits",
  "appName": "Habit Tracker - Daily Goals",
  "developerName": "Example Labs",
  "developerId": "1234567890",
  "developerUrl": "https://example.com",
  "appStoreUrl": "https://apps.apple.com/us/app/habit-tracker/id1091189122",
  "price": 0,
  "formattedPrice": "Free",
  "currency": "USD",
  "isFree": true,
  "primaryGenre": "Health & Fitness",
  "genres": ["Health & Fitness", "Productivity"],
  "averageUserRating": 4.82,
  "userRatingCount": 128411,
  "version": "4.12.0",
  "currentVersionReleaseDate": "2026-09-24T10:00:00Z",
  "releaseDate": "2016-05-02T07:00:00Z",
  "minimumOsVersion": "16.0",
  "contentAdvisoryRating": "4+",
  "fileSizeBytes": 189663232,
  "artworkUrl": "https://is1-ssl.mzstatic.com/image/thumb/.../512x512bb.jpg",
  "screenshotCount": 8,
  "supportedLanguages": ["EN", "DE", "FR"],
  "descriptionChars": 2410,
  "keywordMatchInTitle": true,
  "keywordMatchInDescription": true,
  "recordHash": "5f2b8c1d94e03a76",
  "scrapedAt": "2026-10-02T12:00:00.000Z"
}
```

### What this ASO keyword scraper returns

- 🏆 **Real ranks, per storefront** — one row per app per keyword per country, with `rank` starting at 1. Rankings are **per storefront**, so the same app can sit at 3 in the US and 40 in Germany. Add countries and the Actor tells you that in its run summary.
- 🧠 **Difficulty you can audit** — `keywordMatchInTitle` records whether each ranked app uses the keyword in its own name, the strongest signal Apple uses. The run summary reports how many of the top 5 titles contain the keyword. A top 5 where nobody uses the keyword is an opening; a top 5 where everybody does is a wall.
- 💪 **Incumbent strength in one glance** — `userRatingCount` next to `rank`. **A high rank with a low rating count is a weak incumbent**, and that is the most actionable pattern in ASO.
- 💰 **Price and business model** — `price`, `formattedPrice`, `currency` and `isFree` per storefront, so you can see where a niche is monetised and where it is free-only.
- 🖼️ **Creative and listing data** — up to 10 screenshot URLs, icon, description and its length, supported languages, minimum iOS, age rating and file size. Everything you need to benchmark a listing visually and textually.
- 🔍 **Direct app lookup** — skip the keyword search and resolve any app by numeric ID, bundle ID, App Store URL, or `name:Search Term` for the top match by name. Those rows carry `rank: null`.
- 📈 **Rank-change tracking** — `recordHash` is deterministic over app, keyword and storefront. Schedule the Actor and diff two runs to get a rank-movement report for free.
- 🎯 **Filters that cut your bill** — minimum average rating, free-only and paid-only all run before rows are written, so filtered apps are never charged.

Running on Apify adds scheduling, webhooks, monitoring, API and SDK access, and one-click export to JSON, CSV, Excel, Google Sheets and 20+ integrations.

### How to use it

1. Add search terms to **Keywords to rank for**, phrased the way a real user types them.
2. Add **Country storefronts** — two-letter codes such as `us`, `gb`, `de`, `fr`, `jp`.
3. Set **Results per keyword**. Top 10 is the usual ASO target; 50 exposes the long tail.
4. Optionally add apps to the **Apps to look up directly** list for pure metadata pulls.
5. Click **Start**, then use the **Rankings**, **Competitive landscape** and **App metadata** dataset tabs.

#### How do I find out if a keyword is worth targeting?

Run the keyword, then look at two things in the **Competitive landscape** view: `userRatingCount` across the top 5, and `keywordMatchInTitle` across the top 5. Low rating counts with few title matches means a weak, beatable set. High rating counts with the keyword in every name means you would be fighting established apps on their own strongest signal.

#### How do I track my own rank over time?

Schedule the Actor daily, keep `keyword` and `storefront` fixed, and compare `rank` between runs using `recordHash` or the app ID. You get a rank-tracking pipeline without paying a per-seat ASO subscription.

### How much does it cost to scrape App Store rankings?

Pricing is **pay per event** with one event:

| Event | What triggers it | Billed |
|---|---|---|
| App ranking | One app's rank and metadata written to the dataset | per row |
| Actor start | Once per run, platform fee | per run |

A 50-result keyword in one storefront is **50 rows**. Five keywords across three storefronts at 50 results each is 750 rows — that is the whole calculation. Compute, bandwidth and storage are included; there is no separate platform-usage charge on top.

Rows removed by your filters are **not** billed. Keywords and apps that return nothing are **not** billed.

Set **Max cost per run** in the run options for a hard ceiling. Higher Apify plans get progressively lower per-row pricing through Apify Store tier discounts.

**Zero-cost sizing:** set **Results per keyword** to `10` with one keyword and one country, and you can see the entire output shape for the price of ten rows.

### Example input

A full input with keywords, storefronts, direct lookups and filters:

```json
{
  "keywords": ["habit tracker", "budget app", "learn spanish"],
  "countries": ["us", "gb", "de"],
  "resultsPerKeyword": 50,
  "apps": ["310633997", "com.spotify.client", "name:Duolingo"],
  "includeAppDetails": true,
  "minRating": 0,
  "freeOnly": false,
  "maxTotal": 3000
}
```

### More example output

A keyword that returns nothing:

```json
{
  "recordType": "ranking",
  "ok": false,
  "errorCode": "EMPTY_RESULT",
  "error": {
    "code": "EMPTY_RESULT",
    "message": "No apps matched \"a very long phrase nobody searches\" in the US storefront. Very long-tail phrases can genuinely return nothing.",
    "hint": "The source responded correctly but returned nothing for this query."
  }
}
```

### Use cases

- **ASO keyword research** — build the ranked competitive set for every keyword in your niche, with real difficulty evidence.
- **Rank tracking** — schedule daily and diff `rank` per keyword and storefront.
- **Competitor teardown** — screenshots, description length, update cadence, language support and pricing for the apps outranking you.
- **Niche discovery** — `userRatingCount` across a category reveals which sub-niches have weak incumbents.
- **Market entry research** — compare the same keyword across storefronts to decide which country to launch in first.
- **Listing optimisation** — flag every top-5 competitor that uses the keyword in its app name and pull their descriptions to study metadata structure.

### Related Actors by Axiora Solutions

| Actor | Use it for |
|---|---|
| **App Store Review Scraper** | Pull the reviews of every competitor you find here and see what their users complain about |
| **Domain Contact Enricher** | Contact details for the developers and companies behind the apps |
| **News & RSS Feed Scraper** | Press and release coverage about the apps in your tracked set |

### Frequently asked questions

#### Is the rank Apple's real position or a computed score?

It is Apple's own relevance order, fetched from Apple's public search endpoint in the order Apple returns it, and numbered from 1. Nothing is recomputed server-side, which is why the number is trustworthy and why it is comparable between runs.

#### Do rankings differ by country?

Yes, substantially. Rankings, ratings, prices, screenshots and even the descriptions are per storefront. That is why `countries` is an array and why every row carries `storefront`. A one-country view of a global app is a partial view.

#### How can I tell if a keyword is hard?

Two auditable signals, both on your rows. **`userRatingCount` of the top 5** — hundreds of thousands means established incumbents; under a few thousand means you can compete. **`keywordMatchInTitle` across the top 5** — if most of them use the keyword in their own name, that position is reinforced by Apple's strongest ranking signal.

#### Can I get search volume for a keyword?

Not from Apple — **Apple publishes no keyword search volume data at all**, and any tool that shows you a precise volume number is modelling it, not measuring it. This Actor deliberately does not invent one. It gives you the ranked competitive set and incumbent strength, which is the evidence you can actually defend. Pair it with your own impression data from App Store Connect if you have it.

#### Does it work for any storefront?

Any two-letter App Store country code. Ratings, prices and screenshots are returned in that storefront's own currency and language.

#### What is `descriptionChars` for?

Apple does not use the description for ranking, but it drives conversion. Comparing `descriptionChars` across a ranked set tells you how much copy the incumbents are investing — and if the whole top 10 is under 1,000 characters, that is an easy place to out-work them.

#### Do I need an Apple account or API key?

No. Apple's public search and lookup endpoints are open, and nothing in the input is a credential, so an autonomous agent can call this Actor without a human.

#### Is scraping the App Store legal?

The Actor calls the same public JSON endpoints a browser hits when you search the App Store, and it identifies itself. Store listing data is public. You remain responsible for how you use it, including Apple's terms and any applicable marketing law.

#### Something looks wrong — how do I report it?

Open the **Issues** tab on this Actor page with the keyword, the storefront and what you expected to see.

***

Runnable examples and how-to guides for these Actors: [github.com/batow133/axiora-apify-actors](https://github.com/batow133/axiora-apify-actors)

# Actor input Schema

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

One search term per entry. These are searched exactly as written, so use the phrasing a real user would type: "habit tracker", "budget app", "learn spanish". Results come back in Apple's relevance order.

## `countries` (type: `array`):

Two-letter App Store country codes. Rankings are per storefront, so the same app can sit at position 3 in the US and 40 in Germany. Add every market you care about.

## `apps` (type: `array`):

Optional. Resolve app metadata without a keyword search. Rows written from this list have rank null and keyword null. Accepts a numeric App Store ID, a bundle ID, an App Store URL, or name:Search Term for the top match by name.

## `resultsPerKeyword` (type: `integer`):

How deep to rank each keyword. Top-10 is what most ASO work targets; 50 gives you the long tail and the competitive picture below the fold.

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

Turn off to run a pure keyword-ranking pass and ignore the apps list.

## `minRating` (type: `integer`):

Drop ranking rows whose average rating is below this value. Leave at 0 to keep everything.

## `freeOnly` (type: `boolean`):

Keep only apps that cost nothing to download. In-app purchases are not covered by this filter.

## `paidOnly` (type: `boolean`):

Keep only apps with a download price above zero.

## `maxTotal` (type: `integer`):

Hard ceiling across all keywords, storefronts and app lookups.

## Actor input object example

```json
{
  "keywords": [
    "habit tracker",
    "budget app",
    "learn spanish",
    "photo editor"
  ],
  "countries": [
    "us",
    "gb",
    "de",
    "jp"
  ],
  "apps": [
    "310633997",
    "com.spotify.client",
    "name:Duolingo"
  ],
  "resultsPerKeyword": 50,
  "includeAppDetails": true,
  "minRating": 0,
  "freeOnly": false,
  "paidOnly": false,
  "maxTotal": 3000
}
```

# Actor output Schema

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

Every ranked app, plus directly resolved app metadata.

## `runSummary` (type: `string`):

Per-keyword results returned and written, storefronts, top result, how many top-5 titles contain the keyword, filter effects, billing and network totals.

# 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",
        "budget app"
    ],
    "countries": [
        "us"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiorasolutions/aso-keyword-scraper").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",
        "budget app",
    ],
    "countries": ["us"],
}

# Run the Actor and wait for it to finish
run = client.actor("axiorasolutions/aso-keyword-scraper").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",
    "budget app"
  ],
  "countries": [
    "us"
  ]
}' |
apify call axiorasolutions/aso-keyword-scraper --silent --output-dataset

```

## MCP server setup

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

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/acnvUrPaxCntwmUI5/builds/VxC1smEx3evXtfHca/openapi.json
