Why this matters
Old mobile clients are a slow-moving operational tax:
- They hit endpoints you’ve already deprecated, forcing you to maintain shims
- They crash on patterns you’ve already fixed, dragging your aggregate crash-free metric down
- They miss the security fix you shipped last quarter
- They prevent you from removing legacy fields from your API contract
The fix is usually a force-update prompt — but you can’t make that call without knowing the population. Force-updating 80% of your users is a PR disaster. Force-updating 4% is a Tuesday.
Agentry gives you the distribution in one query: distinct users per version over a 7-day window. The N-2-or-older percentage tells you whether the force-update is now or later.
What you get
- Per-version distinct user count and rollout share
- N-2-and-older count and percentage — the “force update” candidate population
- A published dashboard for the mobile/ops team to pull up at release planning
Walk through it
Show me distinct users per app_version in the last 7 days. What % are still on N-2 or older?
Distinct users grouped by version, then a tail sum.
agentry_analytics_query {
project_id: "default",
query: "
select
properties.app_version as ver,
count(distinct distinct_id) as users
from events
where event = 'app_open'
and timestamp > now() - interval 7 day
group by ver
order by ver desc
"
}
{
"rows": [
{ "ver": "4.2.0", "users": 68420 },
{ "ver": "4.1.3", "users": 142100 },
{ "ver": "4.1.2", "users": 61880 },
{ "ver": "4.1.1", "users": 18340 },
{ "ver": "4.0.5", "users": 8400 },
{ "ver": "4.0.4", "users": 2300 },
{ "ver": "3.9.2", "users": 1840 },
{ "ver": "3.8.1", "users": 420 }
]
}
Now the rollup. Latest is 4.2.0, so “N-2 or older” means anything below 4.1.3.
agentry_analytics_query {
project_id: "default",
query: "
with d as (
select properties.app_version as ver,
count(distinct distinct_id) as users
from events
where event = 'app_open' and timestamp > now() - interval 7 day
group by ver
)
select
sum(users) as total_users,
sumIf(users, ver >= '4.1.3') as latest_or_n_minus_1,
sumIf(users, ver < '4.1.3') as n_minus_2_or_older
from d
"
}
{
"rows": [
{ "total_users": 303700, "latest_or_n_minus_1": 210520, "n_minus_2_or_older": 93180 }
]
}
Distribution:
- Latest or N-1 (4.1.3+): 210,520 (69%)
- N-2 or older (≤ 4.1.2): 93,180 (31%)
- 3.x: 2,260 (0.7%) — these are the truly ancient
31% on N-2-or-older is borderline. A force-update right now would inconvenience ~93k users. If your 4.0.x cohort is missing a security fix you’ve shipped, do it. If they’re just missing a UI refresh, wait one more release.
Worth a separate look: the 1,840 users on 3.9.2. Those are 18 months stale. Force-update those specifically with a one-time prompt is usually low-PR-risk.
Let me publish the dashboard.
agentry_publish_query {
recipe_id: "raw_hogql",
description: "App version distribution (7d)",
params: { query: "<first query above>" }
}
{ "publication_id": "pub_ver_dist", "public_url": "https://agentry.sh/q/pub_ver_dist?key=agp_…" }
The output
App version distribution (7d distinct users)
Version Users Share Cumulative
─────────────────────────────────────────────
4.2.0 68,420 22.5% 22.5% ← current
4.1.3 142,100 46.8% 69.3% ← N-1
4.1.2 61,880 20.4% 89.7% ← N-2 ★ force-update candidate
4.1.1 18,340 6.0% 95.7%
4.0.5 8,400 2.8% 98.5%
4.0.4 2,300 0.8% 99.3%
3.9.2 1,840 0.6% 99.9% ★ 18 months stale
3.8.1 420 0.1% 100.0% ★ ancient — force update
Recommended:
- Force-update 3.x users now (low PR risk, ~2,260 users)
- Wait one more release before force-updating 4.0.x
- Set up Routine to alert when latest reaches >40% adoption
Public dashboard:
https://agentry.sh/q/pub_ver_dist?key=agp_xxx
Setting it up
You only need app_version on a regular event — typically app_open or session_start:
// Android — fire on cold start
postAnalytics("app_open", mapOf(
"app_version" to BuildConfig.VERSION_NAME,
"platform" to "android",
"os_version" to Build.VERSION.RELEASE
))
// iOS — fire from AppDelegate.application(_:didFinishLaunching...)
postAnalytics("app_open", [
"app_version": Bundle.main.releaseVersion,
"platform": "ios",
"os_version": UIDevice.current.systemVersion
])
Where postAnalytics is your fetch helper:
async function postAnalytics(event: string, properties: Record<string, unknown>) {
await fetch(`https://api.agentry.sh/v1/analytics/${PROJECT_ID}/`, {
method: "POST",
headers: {
"Authorization": `Bearer ${DSN}`,
"Content-Type": "application/json",
"User-Agent": "myapp/1.0", // REQUIRED — Cloudflare 403s default UAs
},
body: JSON.stringify({ event, distinct_id: userId, properties }),
});
}
Variations
- “Same query split by platform — iOS adopters tend to update faster than Android.”
- “Per-country distribution — emerging markets have older OS versions and slower updates.”
- “Show me the adoption curve of v4.2.0 day-by-day since release. Is it tracking last release’s curve?”
- “Compare crash-free rate of users on N-2 vs latest — are old-clients-still-using-the-API hitting issues that newer ones don’t?”