A team that has instrumented its web login knows the shape of that problem by heart. Visitors arrive, some start a login, fewer finish it and the work is to find the steps where people fall out. That model produced a decade of tooling and it works.
Then the same team points it at the native app and the numbers stop making sense. Login volume is far lower, because a login in an app happens roughly once per install rather than once per visit. Only new installs, guests and users who lost their session ever reach a login screen, so the funnel that dominates every web dashboard covers a minority of app sessions. And the number that decides whether the app earns its keep, whether a user is still logged in six months after installing, appears nowhere at all.
Adding more instrumentation does not fix this. The question itself is a different one. On the web the goal is to turn a visitor into an account and a completed login. In an app that win is already paid for: somebody bought the install with an app store campaign, a banner or a checkout interstitial, and it happens once. From there the job is to keep an authenticated state alive that ideally never breaks again.

Authentication Analytics Whitepaper. Practical guidance, rollout patterns and KPIs for passkey programs.
This article sets out what native app authentication analytics has to measure instead: which KPIs are worth defining, which signals only exist inside an app and what an SDK that collects them is allowed to do on a platform where a crash rate is a distribution problem.
Web authentication analytics inherited its worldview from e-commerce. Traffic is anonymous by default, every session is a fresh chance to convert and the login is a gate standing between a visitor and the thing they came for. Measuring that gate is obviously worth it, and the login conversion rate is the number that falls out of it.
An app inverts every one of those assumptions. Traffic arrives installed rather than anonymous. The acquisition cost was paid before the first screen rendered. And the login is a one-time setup step that the operating system, the credential manager and your own token storage then conspire to never show again.
That is the entire point of an app. In many large consumer apps, 75% to 85% of app users are already authenticated when they open it. A login funnel measured on that population describes the exception rather than the rule.
Put the two shapes next to each other and they barely belong on the same diagram.
The practical consequence shows up as a mismatch between two ways of counting. The two definitions differ only in what sits in the denominator, and that one difference decides which drop-offs you can see at all.
A session funnel asks: of the sessions that started a login, how many finished it? That is the right question on the web, where a session roughly equals a visit and a visit roughly equals an opportunity.
A user funnel asks: of the people who installed, how many reached an authenticated state, and how many are still in it? That is the right question in an app, where one login is meant to serve hundreds of later sessions.
Run both against the same app and they disagree sharply, as the diagram below shows. A session funnel that reports 90% completion tells you very little, because it was computed over the small share of sessions that contained a login at all. A user funnel can show that a meaningful part of the install base fell out of the authenticated state months ago, and nothing in the session view would ever surface it.
There is a second effect, and it corrupts the web numbers rather than the app numbers.
Some users abandon a web login not because it failed, but because they know the app is already logged in. They close the tab, open the app and finish the task there. Every web analytics setup records that as a drop-off. It is the opposite: it is a user choosing the cheaper path.
The share is usually small, often only a low single-digit percentage of login attempts, but it lands precisely on the metric that gets reported upwards. You cannot detect it from the web side at all. It only becomes visible when the app emits something like an "app opened, already authenticated" event that can be joined to the same person, which is exactly the signal most app instrumentations do not send.
Try passkeys in a live demo.
Once you accept that the funnel is the minority case, native authentication analytics splits cleanly into two objects. They need different events, different KPIs and usually different owners.
| Object | Who it covers | Core question | Typical share of app users |
|---|---|---|---|
| Login flow | New installs, guests, users who lost their session | Can somebody who needs to log in actually do it? | 15% to 25% |
| Authentication state | Everybody who is already logged in | Does the authenticated state survive, and when not why? | 75% to 85% |
This is the part that transfers from the web with only small changes. You still want the full journey: which methods were offered, which one the user picked, whether the passkey ceremony completed, which error came back, whether a fallback rescued the attempt or lost it. The event model is the same one described in our guide on authentication observability.
Two things do change. Errors arrive through platform APIs rather than the browser, so the taxonomy is a different one: the codes in our overviews of native app passkey errors, Apple passkey error codes and Google Play Services passkey error codes. And a new install is a distinct starting condition rather than another session.
This object has no web equivalent worth speaking of, which is why so few teams collect it.
The subject here is a condition that persists between attempts. The app opens and the user is authenticated, anonymous or somewhere in between while a stored session is being restored. Later the condition changes: a token expires, a server invalidates a session, the user switches accounts, the user deliberately logs out or the app comes back from a reinstall with nothing left in its sandbox.
Every one of those transitions is a fact about your product. Only one of them, the deliberate logout, is something the user asked for. The rest are things that happened to them, and each costs you the ability to send a push notification, personalize a screen or recognize a returning customer. In an app, a lost session is a lost customer until they log in again, and many never do.
Android has started turning one of these transitions into a platform feature. Restore Credentials lets an app store a restore key alongside the user's account. The key travels with an Android-to-Android transfer or a cloud backup, so the app can sign the user in silently the first time it opens on the new phone, before any screen is shown. Google has made it a requirement of the Apps Experience Program, with exemptions for banking, fintech, healthcare and government apps. For measurement that cuts both ways: a silent restore is a successful authentication that no login funnel will ever record, and device migration turns into a state transition you can name instead of a hole in the data.
Six metrics describe the second object well. They are deliberately defined so that a single number can be tracked over time and broken down by OS, app version and device model.
| KPI | Definition | Why it matters |
|---|---|---|
| Durable authenticated session rate | Share of app sessions that start already authenticated | Headline health metric. A slow decline is the earliest signal that something in session handling regressed |
| Unexpected logout rate | Authentication losses per 1,000 authenticated app sessions, excluding explicit logouts | The native equivalent of a failed login. Usually the single most actionable number in this list |
| Authentication retention | Share of installs still authenticated after 7, 30 and 90 days | Turns authentication into a retention curve you can compare across app versions the same way you compare crashes |
| New-install activation rate | Share of new installs that reach an authenticated state at all | Where the classic funnel still applies, and where onboarding changes become measurable |
| Authenticated app-usage rate | Active app sessions belonging to authenticated versus anonymous users | Separates the app's real logged-in population from browsing traffic, which is what personalization depends on |
| Reinstall recovery rate | Share of users who authenticate again after a reinstall, an offload or a device migration | Reinstalls are a large, invisible source of churn. This is the number that tells you how much of it you get back |
The last one deserves a note, because it is the one most often misdiagnosed as a credential problem.
Passkeys survive a reinstall. They are stored by the platform credential manager, in iCloud Keychain or Google Password Manager, not by your app. What does not survive is the session your app was holding. On Android, uninstalling removes the app sandbox and the app's Android Keystore entries with it, so a reinstalled app starts from nothing unless Auto Backup restored something. On iOS the picture is softer: keychain items have historically outlived app deletion, although Apple has never documented that as a guarantee and briefly changed the behavior in an iOS 10.3 beta before reverting it. Offloading an app, which iOS offers to free storage, keeps documents and data and therefore behaves differently again.
The platforms are closing part of this gap, and it is worth being precise about which part. Restore Credentials covers the move to a new device. It deliberately stops short of a reinstall, because Android reads uninstalling an app as an intent to delete the restore key, the same way it reads an explicit sign-out. Apple has announced nothing of the same shape for general apps. Its Automatic Sign-In API does place a sign-in token on the Apple Account so a person stays signed in across their devices, but it runs through the Video Subscriber Account framework and is scoped to media-streaming services, so a retailer, a bank or a marketplace cannot use it.
So the recovery path is a login, and it is a login by people who already own a working credential and simply need to be asked for it well. Measuring how many of them get through is measuring how much of your install base you keep.
Igor Gjorgjioski
Head of Digital Channels & Platform Enablement, VicRoads
We hit 80% mobile passkey activation across 5M+ users without replacing our IDP.
Passkeys that millions adopt, fast. Start with Corbado's Adoption Platform.
Start Free TrialThe KPIs above are only computable if the app emits things a browser never had to. Four groups matter.
The most important event in native authentication analytics is also the most boring: the app was opened, and here is the authentication state it opened in. Without it there is no denominator for anything in section 4, and no way to detect the web-to-app switch from section 2.3.
Lifecycle also constrains everything else. An app gets backgrounded, suspended and killed by the operating system, so an SDK has to finish or safely park its work at those boundaries rather than assume a page unload it can hook.
A single boolean for "logged in" throws away the interesting part. The state model we use has four values, and every app session sits in exactly one of them:
When a session leaves the authenticated state, three named reasons account for the cases where nothing went wrong:
Everything that is left over is by definition an unexpected logout, and that residual is the number worth watching. The diagram below shows why the model has to be built this way. You never log this metric directly. It is what remains once the named exits are subtracted.
Teams that only log "user is logged out" end up with the sentence we hear constantly: it is unclear why users lose their session, which makes it hard to do anything about it.
On the web, whether a passkey prompt could ever have worked is answered by client capabilities. In an app the equivalent set is different, and it is available directly from the platform rather than inferred from a user agent. This is the attribute set our own app-side client environments carry:
None of this requires PII. It is device and build metadata, and it is what turns "passkeys fail sometimes" into "passkeys fail on this OS version, on these models, at this step".
There is one native-only signal that has no clean web counterpart and is worth designing for.
Both platforms let an app ask for credentials that are immediately available on the device,
without falling back to a QR code or a security key. On
iOS that is the preferImmediatelyAvailableCredentials option on
ASAuthorizationController; on Android it is the
preferImmediatelyAvailableCredentials field
on GetCredentialRequest. Apps use it to show a passkey overlay on launch, before the user
has typed anything.
That request produces a genuinely new fact: a passkey existed locally, the user saw it, and they logged in with something else anyway. On the web that would look like an ordinary password login. In an app it is a measurable signal that your passkey UX lost a race it should have won, and it belongs in the analytics rather than being discarded as a cancelled prompt.
Before any of this can be collected, one architectural question has to be answered per flow: where does the login actually execute? Our guide on native app passkeys covers the implementation trade-offs. For measurement, the four cases behave very differently.
| Integration | What happens | Measurement consequence |
|---|---|---|
| Fully native | Login runs entirely in native code with the platform credential APIs | Web instrumentation cannot see it at all, so it takes a native SDK |
| System WebView | Login opens Safari or Chrome Custom Tabs, as in an OAuth flow | Web instrumentation works, but the journey has to be marked as app-initiated or it pollutes your web numbers |
| Embedded WebView | Login runs in an app-owned WebView | Web instrumentation is unreliable: storage, cookies and navigation behave differently, and Conditional UI is out |
| Hybrid | Parts native, parts in a WebView | Both sides have to emit into the same journey, or every user shows up as two half-journeys |
The failure mode here is subtle and common. A team instruments the web, sees app traffic appear in the dashboard because the login happens in a System WebView, concludes the app is covered, and never notices that app-initiated journeys are being averaged into web ones. In-app browsers have their own quirks on top of that.
Adding a script tag to a website is close to free. Adding a dependency to a native app is not, and the teams who run large apps will say so within the first five minutes of any conversation. Four constraints come up every time.
Google Play publishes explicit thresholds. An app whose user-perceived crash rate reaches 1.09% of daily active users, or whose ANR rate reaches 0.47%, is likely to become less discoverable on Google Play, with an 8% per-device threshold on top. Analytics is not worth a share of that budget.
The design conclusion is unusual for an analytics product: when in doubt, drop events. Stop transferring, park the queue, do nothing. An SDK that loses a percentage of its data is recoverable. An SDK that contributes to a crash rate gets removed from the app, and then you have no data at all.
Two related requirements follow. Initialization has to be explicit rather than automatic, so nothing runs before the host app decided it should. And there has to be a remote off switch, so the SDK can be paused without shipping a release through app review.
Web analytics gets autocapture almost for free. You patch a few globals, listen to the DOM and collect a rich picture without the host application doing anything. The native equivalent is method swizzling, which is roughly the Objective-C runtime version of monkey-patching, and mature app teams reject it on sight because it makes crashes unattributable and behavior version-dependent.
That removes the shortcut and forces a better design: the app emits explicit, typed events from the places that already know what happened, its own login, session and lifecycle services. The integration is a single adapter rather than a hook into the runtime. It is more work up front and considerably easier to reason about afterwards.
Consent frameworks routinely remove a quarter of app traffic from analytics. That is acceptable for product analytics and painful for debugging, because you cannot investigate a technical failure that a consent rule deleted.
The split that resolves it is to tag events by purpose rather than to gate the whole SDK. Error and diagnostic events are necessary to operate the service; behavioral time series are analytical. Collect the first under essential consent and hold them to a shorter retention, process the second only where analytical consent exists. This is not native-specific, but apps are where the 25% actually hurts.
The remaining requirements are the ordinary ones that get forgotten: batch uploads with low priority instead of a request per event, graceful stopping when the app is backgrounded or hibernated, a networkless mode for the situations where the app deliberately stops talking to the network and a small binary. App teams count kilobytes because their users do.
See how many people actually use passkeys.
Instrumenting all of this at once is a large project. It does not have to be one, and the sequence below front-loads the parts that pay off fastest.
The ordering is deliberately the opposite of how web instrumentation usually gets built, where the funnel comes first. In an app, the funnel is the smallest object you are measuring.
Everything above starts with one thing: an authentication journey that stays one journey
even when it crosses a WebView, a redirect and an app restart.
Corbado Observe is the authentication observability layer built for that. It
models each product channel as its own application (web, ios, android) inside one
project, so app-initiated journeys stop being averaged into web numbers, and it reconstructs
what happened per user rather than per session.
Where the login runs decides how it gets instrumented. System WebView and hybrid flows are covered by the web SDK today, marked as app-initiated so they stay separable from web traffic. For fully native flows, the app-side event and client environment model is already part of Observe, which is where the attributes above come from.
If you also want the native passkey implementation handled rather than measured, Corbado Connect ships iOS and Android SDKs for passkey login, enrollment and management, so the ceremony does not have to be hand-built once per platform.
Subscribe to our Passkeys Substack for the latest news.
Native app authentication analytics is not web analytics with a smaller sample. The population is inverted: most of your users are already logged in, so the login funnel describes the exception while the authenticated state describes the product. Measuring that state means new objects (app-open events, logout reasons, reinstall recovery), new KPIs and an SDK that earns its place in a binary where a crash rate has commercial consequences.
The reason this matters more each year is that apps are where authentication is going. The credential lives in the operating system, the ceremony runs on the device and over 80% of passkey failures never reach a backend at all. An app that cannot say why its users lost their session is guessing about the single thing it spent the most money to achieve.
Corbado is the Passkey Intelligence Platform for large-scale CIAM teams running consumer authentication. We help you see what IDP logs and generic analytics tools can't: where passkeys, passwords, OTP, social login and fallback journeys succeed, stall or fail, which devices and browsers create friction, and when an OS update silently breaks login. Two products: Corbado Observe layers process mining and observability across authentication journeys. Corbado Connect adds managed passkeys with analytics built in alongside your IDP. VicRoads runs passkeys for 5M+ users with Corbado (+80% passkey activation). Talk to a Passkey Expert →
Related Articles
Table of Contents