Why rating count alone isn’t enough to measure keyword competition
Sometimes an app with 200,000 ratings ranks #3 for a niche search term purely by accident—because one word in its description or category matched loosely, while its 30-character App Title targets a completely different topic. A newer app whose Title explicitly matches that niche phrase can often outrank a giant that isn’t intentionally targeting the query.
To capture both authority and intentional targeting, Searchbop’s [`difficultyFrom()`](file:///Users/tarik/Desktop/TengrX-SEO/packages/core/src/aso/score.ts#L37-L50) function inspects the top 10 results returned by Apple for that country and combines three components:
| Component | Weight | Exact Mathematical Formula | What It Measures in the Top 10 |
|---|---|---|---|
| 1. Rating Volume Strength | 55% | clamp(mean(log10(1 + ratingCount)) / 6) |
Logarithmic authority of the top 10 apps (`1,000,000` ratings = `1.0`; `1,000` ratings = `0.5`; `10` ratings = `0.17`). |
| 2. Rank-Weighted Title Match | 30% | Harmonic rank weight 1 / (i + 1) × Title match (1.0 exact phrase, 0.6 all words present, 0.3 partial word hit, 0.0 none) |
Whether the `#1`, `#2`, and `#3` apps are intentionally targeting this exact keyword in their 30-character App Name. |
| 3. Rating Quality | 15% | clamp((mean(averageUserRating) - 3) / 2) across rated apps |
User satisfaction wall (`4.8★` average is much harder to beat on tap-to-install conversion than `3.4★` apps). |
Why fewer than 3 App Store results must never be labeled “Difficulty: 0”
When an obscure typo or ultra-long query returns zero, one, or two apps on the App Store, naive scripts calculate `difficulty = 0` and flag the term as an “Easy Win.” In reality, fewer than 3 results (`MIN_RESULTS_FOR_DIFFICULTY = 3`) means the query has no established storefront SERP—often because nobody searches that phrasing or Apple’s search parser failed to match any category.
When `results.length < 3`, Searchbop returns `difficulty: null, state: "no_data"` and withholds the Opportunity score so your Quick Wins filter never fills up with ghost keywords.
03 / THE OPPORTUNITY FORMULAHow Searchbop calculates your 0–100 Opportunity Score
Once both Popularity (`P`) and Difficulty (`D`) are known, [`opportunityFrom()`](file:///Users/tarik/Desktop/TengrX-SEO/packages/core/src/aso/score.ts#L53-L59) computes a single prioritization score:
export function opportunityFrom(k: {
popularity: number | null;
difficulty: number | null;
relevance?: number | null;
rank?: number | null;
}): number | null {
if (k.popularity == null || k.difficulty == null) return null;
let score = Math.sqrt(k.popularity * (100 - k.difficulty)) * (k.relevance ?? 1);
if (k.rank != null && k.rank >= 4 && k.rank <= 30) score *= 1.15; // Striking-distance boost
if (k.popularity < 20) score *= 0.5; // Low-volume dampener
return Math.round(Math.min(100, score));
}
How country and language parameters work on Apple’s Store Search API
To check where your app ranks in a specific country (`US`, `TR`, `DE`, `JP`, `BR`, etc.), Searchbop queries `https://itunes.apple.com/search` with `entity=software`, `limit=200`, `country={cc}`, and—crucially—the storefront’s explicit `lang={lang}_{cc}` parameter ([`itunes.ts`](file:///Users/tarik/Desktop/TengrX-SEO/packages/core/src/aso/itunes.ts#L50-L63)).
Why does `lang` matter? Without the `lang` parameter, Apple’s public Search API frequently returns English localized app titles even when querying a non-English storefront, which distorts title-match difficulty calculations. And for the few storefronts whose regional locale string Apple’s endpoint rejects with `HTTP 400` (such as `ar_dz` or `he_il`), Searchbop automatically retries without `lang` so every single one of the 91 countries resolves cleanly.
Honest boundaries: Public API vs. on-device personalization
Why your phone may show a slightly different rank: Apple’s public `itunes.apple.com/search` endpoint reflects unpersonalized storefront rankings and updates at a `3,000 ms` pace (~20 queries/minute). On a physical iPhone signed into an Apple ID, the App Store personalizes results slightly based on prior installs and device context. Tracking unpersonalized storefront ranks over time in `asoRankHistory` gives you a consistent baseline across releases.
Research context & search queries covered on this page Difficulty & Ranks · P1
Cluster & intent: aso-difficulty-ranks (Informational / Commercial · P1) · Target queries: app store keyword difficulty, how to check app store ranking, ios keyword rank tracker, app store competitor keyword research.