App Store Keyword Rank Monitor
Pricing
Pay per usage
App Store Keyword Rank Monitor
Reports an app's position in Apple's public iTunes Search API results for one keyword and storefront. That number is a proxy and can differ from the App Store app. Apple's terms restrict automated rank measurement. Not affiliated with Apple.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
Muhammet Mustafa Dincer
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
18 hours ago
Last modified
Categories
Security
Limited permissionsShare
What is App Store Keyword Rank Monitor?
App Store Keyword Rank Monitor tells you where an app sits in Apple's public iTunes Search API results for a keyword and a storefront. For each keyword, country and app it calls https://itunes.apple.com/search with entity=software (or iPad / Mac software) and reads the app's 1-based position in the results array. If the app is not in that window, the rank is null.
That number is a commonly used proxy. It can differ from the order a person sees in the App Store app. Apple's search page, the App Store app, and this API are not the same list. Do not treat the number as the official chart.
A bundle id is resolved to a numeric track id with https://itunes.apple.com/lookup before the search. There is no App Store HTML page, no private Apple endpoint, no Apple developer token, and no proxy. Google Play is not part of this Actor.
Apple's Media Services terms generally forbid using an automated process to measure or monitor the services, including ranking. This Actor calls the public JSON API anyway. Whether you may run it is your decision. This README is not legal advice. The Actor is not affiliated with Apple.
Quick answer: when should you (or an AI agent) pick this Actor?
Pick this Actor when you want a scheduled check of where your app, or a competitor, sits in the iTunes Search API for a list of keywords and storefronts such as us, tr and gb. A typical input is 10 to 40 keywords, one to three storefronts, and one app id.
Pick something else when you need the rank a person sees inside the App Store app, a keyword's search popularity, install estimates, or Google Play. This Actor does not have those. It also does not keep a chart: the dataset of each scheduled run is the changelog, and the saved memory is only the previous rank.
Defaults that work: keyword podcast, Apple id 324684580, storefront us, limit 200. One Start is one Search API call.
At a glance
| Does | Calls the public iTunes Search API and records the 1-based position of each app in results. Resolves a bundle id with Lookup. |
| Input | Keywords, app ids and/or bundle ids, storefronts, result limit (max 200), optional app kind and attribute, concurrency and delay. |
| Output | One dataset row per keyword × storefront × app: rank or null, the apps around it, the top of the window, and the previous rank when one was saved. |
| Needs | Nothing. No Apple key and no proxy. |
| Depth | At most 200 results per search, which is the Search API maximum. |
| Pricing | Pay per event. Free plan: $0.0005 per run and $0.008 per completed rank row, including a miss. |
| Does not | Read the App Store app's own ranking, scrape App Store HTML, call a private API, use a proxy, or read Google Play. |
Key terms used in this README
- Search API rank: the 1-based index of the app in the
resultsarray fromitunes.apple.com/searchfor that keyword, storefront, entity and limit. This is the only rank this Actor reports. - Miss:
rankis null andstatusisnot_found. The app was not inside the returned window. A miss is a result and is charged. It does not mean the app is unpublished. - Window: the
resultLimityou set, from 1 to 200.hitResultLimitis true when Apple returned a full window, so a miss may be past the cut rather than absent from a short list. - Track id: the numeric App Store id, the same digits as
id324684580in anapps.apple.comURL. The field istrackId. - Lookup:
itunes.apple.com/lookup, used only to turn a bundle id into a track id and to fill the app name. Several numeric ids share one Lookup call. - Previous rank: the last completed check for the same watchlist name, keyword, storefront, app, entity, attribute and limit.
rankChangeis the previous rank minus the new rank when both were numbers. Positive means the app moved up. This is not a history. - Blocked: Apple answered 403 or 429 after the backoff. That keyword's rows are not charged. Other keywords continue.
What can you use it for?
A weekly keyword watch
Schedule the same input once a week. Twenty keywords, two storefronts and one app are 40 rows. On the Free plan that is 40 × $0.008 = $0.32 plus the start fee. The dataset from each run is the record of what changed. rankChange only compares with the previous saved check.
A storefront check
Pass countries: ["us", "gb", "tr"]. Each storefront is its own search. The same app can be present in one and missing in another.
Your app and two competitors
Pass three ids. One Search API call still covers the keyword and storefront. You get three rows, and you pay for three completed checks, because each rank is a separate answer. The neighbor list shows the apps immediately above and below yours.
How does it work?
- App ids are checked as digits, bundle ids are checked as
com.example.app, and anapps.apple.comoritunes.apple.comURL is reduced to its id. Anything else is skipped. The Actor never requests a host you typed. The only host isitunes.apple.com. - Numeric ids are sent together to Lookup. Each bundle id is looked up on its own, then on each requested storefront if the default store returns nothing. A lookup miss does not drop the app: the search still matches the id you gave.
- For each keyword and storefront the Actor calls Search with
media=software, your entity, your limit, and no attribute unless you chose developer-name search. Every app is then located in that oneresultsarray. - Request starts are at least
requestDelayMsapart (default 500, minimum 400). At mostmaxConcurrencyrequests are in flight (default 2, maximum 3). Connections are reused. A 403 or 429 waits 1s, then 2s, then 4s, and is tried up to four times in all. After that, every app on that keyword is ablockedrow and the run moves on. A 5xx and a dropped connection use the same backoff. The Actor does not change IP, does not open a proxy, and does not call another Apple host. - The previous rank is read from the named key-value store
app-store-keyword-rank-monitor-state. After a completed row is stored and charged, that one rank replaces the saved value. A failed request does not replace it. There is no list of older ranks. - If the run hits its maximum charge, rows that did not fit are left unsaved, so the next run can deliver them. Rows already refused by Apple are still written and are not charged.
How to check a keyword (step by step)
- Open the Actor. Keep the prefilled keyword and app, or replace them.
- Add storefronts if you need more than the US.
US,TRandGBare the usual codes.ukis read asgb. - Leave the limit at 200 unless you only care about a shorter window.
- Leave Search attribute on All attributes. Developer name only is a different search.
- Click Start. Each app is one row.
status: rankedmeans the app was in the window.status: not_foundmeans it was not. - Schedule the same input. The next run fills
previousRankandrankChangewhen both checks found the app inside the window.
Input
| Field | Type | Default | Meaning |
|---|---|---|---|
keywords | list | prefilled podcast | Up to 40. One Search API call per keyword and storefront. |
apps | list | prefilled 324684580 | Up to 8 track ids, bundle ids or App Store URLs. |
countries | list | us | Up to 5 storefronts. uk is read as gb. |
resultLimit | integer | 200 | 1 to 200. A null rank is outside this window. |
entity | string | software | software, iPadSoftware or desktopSoftware. |
attribute | string | all | all is the keyword rank. softwareDeveloper searches the developer name only. |
stateName | string | default | Letters, digits, - and _. Same name, same previous-rank memory. |
maxConcurrency | integer | 2 | In-flight requests, 1 to 3. |
requestDelayMs | integer | 500 | Gap between request starts. Minimum 400. |
There is no proxy field.
Output
One dataset row per keyword, storefront and app, including failures. The view is Ranks. assets/sample-run-data.json is two rows from a local Search API call on 5 November 2026: keyword spotify, US store, limit 10. Spotify was position 1, and the next check a moment later reported rankChange: 0. Apple Podcasts was not in that short list. Ranks move. The file shows the shape, not today's order.
| Field | Meaning |
|---|---|
keyword, country | What was searched. country is lowercase. |
trackId, bundleId, appName | The app. trackId is the App Store id. |
rank | 1-based Search API position, or null. |
rankChange | Previous rank minus this rank. Positive means moved up. Null when either side was outside the window or there was no previous check. |
previousRank, comparedAt | The last saved check. comparedAt is null the first time. |
resultCountReturned, resultLimit, hitResultLimit | How many results came back, what you asked for, and whether the window was full. |
searchedAt, searchUrl | When, and the Search API URL. |
entity, attribute | App kind, and softwareDeveloper or null. |
source | Always itunes-search-api. |
neighbors | Up to three apps above and three below: rank, trackId, bundleId, appName. |
topResults | The first results, up to 10, with the same fields. |
status | ranked, not_found, blocked or search_failed. |
message | Why the rank is null, or why the request failed. |
Key-value store
| Key | Where | Meaning |
|---|---|---|
RUN_SUMMARY | default store | Counts, warnings, and why the run stopped. |
STATE | default store | Internal resume marker. |
rank--{stateName}--{hash} | named store app-store-keyword-rank-monitor-state | The last rank only. Not a chart. |
finishedReason in the summary is completed, charge_limit or aborted. A run where every keyword fails ends as a failed run. One failed keyword does not.
Pricing
Pay per event. Prices below are US dollars on the public tier list in pricing-ppe.json. Apify's margin is 20%. This file is the proposal. It is not applied on the platform by this change.
| Event | Free | Bronze | Silver | Gold and above | When |
|---|---|---|---|---|---|
| Actor start | $0.0005 | $0.0005 | $0.0005 | $0.0005 | Once per run (one event per GB of memory, minimum one) |
| Rank reported | $0.008 | $0.007 | $0.006 | $0.005 | One per completed row |
The charge in the code is Actor.charge({ eventName: 'rank-reported', count }) after the rows are stored. pushData is called without an event name, so a row is not billed twice.
Charged: ranked and not_found. A miss is the answer "not in this window".
Not charged: blocked and search_failed rows, Lookup calls, neighbor and top-result lists, rankChange, and the run summary. There is no proxy traffic.
A charge result of zero events is a spending limit only when eventChargeLimitReached is true. A run that is not on pay-per-event still stores the rows.
Worked examples on the Free plan, plus the start fee: 20 keywords × 2 storefronts × 1 app, weekly, is about 160 rows a month, about $1.28. The same set daily is about $9.60. Forty keywords × 3 storefronts × 1 app, daily, is 3,600 rows, about $28.80. A heavier daily matrix costs more than a flat ASO subscription; use a weekly schedule if that is the job you want.
The band sits above those public per-row prices and near a small ASO subscription for a working keyword set. See the comparison. The platform cost of a run was not measured here, because this change does not publish the Actor or set a live price.
Comparison
| This Actor | Public Search-API rank actors | An ASO subscription | |
|---|---|---|---|
| What the number is | Position in iTunes Search API results | The same family of signal | Their own rank product |
| Google Play | No | Varies | Often included |
| Previous rank | Last check only | Varies | A chart inside the product |
| Price signal | $0.008 per completed row on Free, $0.005 on Gold | About $0.002 and about $0.001 per row on public list prices | About $19/month on annual billing, or $29/month on monthly billing, for a suite that does more than this |
The $0.002 figure is the public list price cited for petersutarik/aso-keyword-intel (about 95 users in 30 days). The $0.001 figure is the public list price cited for slothtechlabs/aso-keyword-rank-tracker. The subscription figures are from AppFollow's October 2026 article on building versus buying an ASO tool. Those products are named only so the price has a reference. Their text and their implementation are not reused here.
Every paid tier of this Actor is at least $0.005, which is 2.5 times the $0.002 row. The price is for the rank answer. The HTTP call is shared by every app on that keyword, and that cost was not measured on Apify in this change.
Legal and privacy
Apple. The Search and Lookup URLs are public and need no key. They are documented by Apple as the iTunes Search API. itunes.apple.com/robots.txt (fetched 5 November 2026) contains Disallow: /search* and Disallow: /*/lookup?. The Search call this Actor makes is under /search, so the robots file disallows it. The Lookup call is /lookup on the same host, and the robots file has a lookup rule. Apple's Media Services terms say you may not use an automated process to scrape, copy, or perform measurement, analysis, or monitoring of the services. Rank checking is that kind of measurement. This Actor calls the API anyway. It does not have Apple's permission.
It does not rotate addresses, open a proxy, raise the delay above your setting except for the 403/429 backoff, or switch to a private API when Apple refuses. If Apple asks for this Actor to be removed, it comes off the Store. The place to say so is an issue on https://github.com/mmdincer/apify. This README is not legal advice. The Actor is not affiliated with Apple.
Personal data. Rows store the app name, the numeric id, the bundle id, and the same fields for neighboring apps. Those are the public store listing. Review text, user names and device data are not requested.
No chart. Do not expect this Actor to draw a 90-day graph. Schedule it and keep the datasets. The key-value store holds one previous rank so the next run can show the move.
FAQ
Is this the rank I see in the App Store?
No. It is the position in the iTunes Search API results for that keyword and storefront. The App Store app can show a different order. The row's source is itunes-search-api for that reason.
Why is the rank null for a famous app?
It was not inside the first resultLimit results. The default limit is 200, which is as far as this API goes. Raise the limit if you set it lower. A null rank with hitResultLimit: false means the whole response was shorter than the limit and the app was still not in it.
What if Apple returns 403 or 429?
That keyword is retried with a wait, then marked blocked and not charged. The run does not switch IP or turn on a proxy. Other keywords still run. If every keyword is blocked, the run fails.
Does the first run cost money? Yes. The rank itself is the product, including the first time you see it. You are not charged for a request Apple refused.
What does rankChange mean?
Previous rank minus the new rank. From 12 to 5, rankChange is 7 (the app moved up). From 5 to 12, it is -7. If either check missed the window, rankChange is null and previousRank still shows the number when the earlier check had one.
Can I track Google Play? No. This Actor does not call Google. A public Play search that would require scraping the Play page is out of scope.
Local run
From actors/app-store-keyword-rank-monitor after npm install:
$mkdir -p storage/key_value_stores/default
Write storage/key_value_stores/default/INPUT.json, then npm start. npm test runs the unit tests and does not call Apple.