Get your free and exclusive +30-page Authentication Analytics Whitepaper

isUVPAA iOS 26.2 Bug: Passkey Detection with getClientCapabilities

Fix the iOS 26.2 WKWebView passkey detection regression where isUserVerifyingPlatformAuthenticatorAvailable() returns false on Chrome.

Vincent Delitz

Vincent

Created: February 3, 2026

Updated: February 4, 2026

Blog-Post-Header-Image

Timeline: iOS 26.2 isUVPAA Bug#

Last updated: February 4, 2026

DateEventStatus
Dec 4, 2025Chromium bug filed (iOS 26.2 RC)📝 Tracked
Dec 12, 2025iOS 26.2 ships with WKWebView isUVPAA() bug🐛 Bug
Dec 2025Apple Forums: Bug acknowledged⚠️ Investigating
Jan 26, 2026iOS 26.3 beta 3 (23D5114d) fixes WKWebView bug✅ Fixed in Beta
Jan 29, 2026Chrome workaround submitted🔧 In Review
TBDChrome workaround shipped⏳ Pending
TBDiOS 26.3 stable release⏳ Pending
PasskeysCheatsheet Icon

Looking for a dev-focused passkey reference? Download our Passkeys Cheat Sheet. Trusted by dev teams at Ally, Stanford CS & more.

Get Cheat Sheet

1. Introduction#

With iOS 26.2, Apple introduced a breaking change: isUserVerifyingPlatformAuthenticatorAvailable() now returns false on all WKWebView-based browsers (Chrome, Edge, Firefox), even when passkeys work fine. This affects roughly 10-25% of iOS users.

In this article, we answer:

  1. What changed in iOS 26.2? Why does isUVPAA() suddenly return false on Chrome iOS?
  2. How do the two detection APIs differ? When should you use isUVPAA() vs getClientCapabilities()?
  3. What's the recommended fix? A decision flow for reliable passkey detection across all platforms.

2. Two Detection APIs: isUVPAA vs getClientCapabilities#

Both APIs answer the same question: "does this device have a platform authenticator (Touch ID, Face ID, Windows Hello) for passkeys?" Here's what each looks like:

Legacy API: isUserVerifyingPlatformAuthenticatorAvailable()#

// Returns a simple boolean const isAvailable = await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); console.log(isAvailable); // Output: true or false

New API: getClientCapabilities()#

// Returns an object with multiple capabilities const capabilities = await PublicKeyCredential.getClientCapabilities(); console.log(capabilities); // Output: // { // userVerifyingPlatformAuthenticator: true, // conditionalCreate: true, // conditionalGet: true, // hybridTransport: true, // passkeyPlatformAuthenticator: true, // relatedOrigins: false, // signalAllAcceptedCredentials: true, // signalCurrentUserDetails: true, // signalUnknownCredential: true // }

Why the new API? Introduced in WebAuthn Level 3 (late 2024), getClientCapabilities() unifies feature detection into a single call returning a capabilities dictionary. Instead of calling multiple methods, you get everything at once. Sites can tailor UX accordingly, showing passkey options only when supported.

Substack Icon

Subscribe to our Passkeys Substack for the latest news.

Subscribe

Browser support comparison (source):

BrowserisUVPAA()getClientCapabilities()
Chrome67+133+
Chrome Android70+133+
Edge18+133+
Firefox60+135+
Safari13+17.4+
Safari iOS13+17.4+
WebView Android
WebView iOS13+17.4+

By early 2025, getClientCapabilities() covers the vast majority of users on up-to-date browsers. Chrome 133+ shipped full support, and other browsers followed. Older browsers won't have this API, so your detection logic should handle its absence gracefully. That's where the fallback strategy comes in.

3. iOS 26.2 Regression: What Changed#

With iOS/macOS 26.2, Apple changed how isUserVerifyingPlatformAuthenticatorAvailable() behaves. Previously, it almost always returned true on Apple devices with Touch ID/Face ID, essentially nudging users to create passkeys even if they hadn't set one up yet (we covered the different vendor approaches here). Now it returns true only if the user has a passkey provider configured (iCloud Keychain or a third-party password manager like 1Password). Apple's interpretation shifted: "available" now means "actively usable," not just "technically present."

Regression bug: During iOS 26.2 beta, developers noticed that isUVPAA() always returned false, even on fully passkey-capable devices with Face ID and existing passkey provider. Apple acknowledged this and fixed it in the final Safari 26.2 release. However, the bug persisted in WKWebView, the rendering engine used by all third-party iOS browsers. Any non-Safari context (Chrome, Edge, Firefox, in-app webviews) kept returning false regardless of actual device capability.

Slack Icon

Become part of our Passkeys Community for updates & support.

Join

Impact was significant: Chrome alone has 10-25% iOS market share depending on region. These users were suddenly misdetected as lacking platform authenticators. The same user who worked fine in Safari was broken in Chrome iOS. Apple's forums got bug reports, and Apple staff confirmed they're investigating.

In summary, iOS 26.2 introduced two distinct changes:

  1. Intended change (Safari): isUVPAA() now requires a configured passkey provider. Fresh devices return false even with hardware support. This is by design.
  2. Unintended bug (WKWebView): All third-party browsers and webviews always return false. Since Apple mandates WebKit for all iOS browsers, this breaks passkey detection across Chrome, Edge, Firefox, and every in-app webview.

4. How Both APIs Diverged: A Timeline#

Here's where things get interesting. When getClientCapabilities() was introduced, most developers didn't adopt it for passkey detection. They kept using isUVPAA() for "is platform authenticator available?" checks since it was well-supported and worked reliably. New API was primarily adopted for other capabilities like conditionalCreate, conditionalGet, relatedOrigins, and hybridTransport.

This meant that when both APIs started returning different values for userVerifyingPlatformAuthenticator, almost nobody noticed.

Debugger Icon

Want to experiment with passkey flows? Try our Passkeys Debugger.

Try for Free

Pre-iOS 26.2: Google App WebView Precedent#

Divergence actually existed before iOS 26.2, but in opposite direction. Google App on iOS uses an embedded WebView that doesn't support passkeys for third-party domains due to relying party (RP) limitations. This is expected behavior for embedded WebViews. In this environment:

PlatformisUVPAA()getClientCapabilities()What it meant
Google App WebView iOSfalsetrue ⚠️WebView can't use passkeys

Here, isUVPAA() was actually correct. Google App WebView genuinely couldn't perform passkey authentication for third-party RPs, so returning false was accurate. Meanwhile, getClientCapabilities() returned true because it reports device hardware capability (iPhone has Face ID), not whether current WebView context can actually use passkeys for a given RP.

This divergence went unnoticed for two reasons:

  1. Developers weren't checking both APIs for passkey detection
  2. Google App is a known edge case where passkeys don't work anyway, so false was expected behavior

iOS 26.2+: Inversion#

With iOS 26.2, the situation flipped. Now isUVPAA() started returning false on WKWebView-based browsers (Chrome, Edge, Firefox) even though passkeys do work in these contexts. Meanwhile, getClientCapabilities() continued returning true.

PlatformisUVPAA()getClientCapabilities()Status
Safari iOS 26.2⚠️ false if no passkey providerfalseIntended change
Chrome/Edge/Firefox iOS❌ Always falsetrueBug
In-App WKWebView❌ Always falsetrueBug
Chrome/Edge macOS✅ Works correctly✅ Works correctlyUnaffected
Safari macOS 26.2⚠️ false if no passkey providerfalseIntended change
Windows/Android✅ Works correctly✅ Works correctlyUnaffected

Important nuance: We can't say getClientCapabilities() is "more accurate" or "tells truth." What we know is that it continued returning true while isUVPAA() started returning false. Whether that's because the new API is architecturally better or simply because Apple didn't change its implementation, we don't know.

For developers, the practical reality is: passkeys do work on Chrome/Edge/Firefox iOS, and getClientCapabilities() returns true on these browsers. Whether that's by design or coincidence, the outcome is that you can use it to offer passkey flows where they actually work.

StateOfPasskeys Icon

Want to find out how many people use passkeys?

View Adoption Data

5. Recommendations: Reliable Passkey Detection#

Given the nuances above, we recommend a conservative approach that accounts for both iOS 26.2 bugs and known WebView limitations.

Decision Flow#

Pseudo-code:

function canUsePasskeys() { if (isGoogleAppWebView() && isIOS()) { return false; // RP limitations } if (isIOS26_2Plus()) { if (isSafari()) { return isUVPAA(); } else { return getClientCapabilities()?.userVerifyingPlatformAuthenticator ?? false; } } return isUVPAA(); }

Logic Explained#

1. Google App WebView on iOS: Assume false

Google App uses an embedded WebView where passkeys don't work for third-party RPs due to platform limitations. Even though getClientCapabilities() returns true (reporting device capability), passkey authentication will fail. Offer fallback options (cross-device passkey, password).

2. Safari iOS 26.2+: Use isUVPAA()

On Safari, isUVPAA() works correctly and is now more granular. It returns true only if a passkey provider (iCloud Keychain, 1Password, etc.) is configured. This stricter behavior is intentional and gives you a better signal than the capabilities API.

3. Other iOS 26.2+ browsers (Chrome, Edge, Firefox, WKWebView): Use getClientCapabilities()

On non-Safari iOS 26.2+ browsers, isUVPAA() is broken due to WebKit bug - it always returns false. Use getClientCapabilities().userVerifyingPlatformAuthenticator instead. Passkeys do work on these browsers, and the new API happens to return true.

4. Everything else: Use isUVPAA()

For older iOS versions, macOS, Windows, Android, use the legacy API as before.

TL;DR#

  1. Google App WebView iOS? Assume no passkey support (RP limitations)
  2. Safari iOS 26.2+? Use isUVPAA() (works correctly, more granular)
  3. Other iOS 26.2+ browsers? Use getClientCapabilities() (workaround for bug)
  4. Everything else? Use isUVPAA()

Looking ahead: Once Apple ships a WebKit fix or Chrome's workaround lands in stable, consider reverting to simpler logic. The branching above is a temporary workaround - monitor the timeline and simplify when fixes are confirmed.

Analyzer Icon

Are your users passkey-ready?

Test Passkey-Readiness

6. Conclusion#

In this article, we covered:

  1. What changed in iOS 26.2? Apple's WKWebView now returns false for isUVPAA() on all third-party browsers, even when passkeys work. This is an acknowledged bug affecting Chrome, Edge, Firefox, and in-app webviews.

  2. How do the two APIs differ? isUVPAA() is the legacy single-boolean check, while getClientCapabilities() returns a full capabilities dictionary. On iOS 26.2+, they diverge: the new API happens to return correct values where the legacy one is broken.

  3. What's the recommended fix? Use platform-aware detection: isUVPAA() for Safari and older browsers, getClientCapabilities() for non-Safari iOS 26.2+, and assume false for Google App WebView.

Passkey APIs are evolving rapidly. Platform vendors ship changes, sometimes unintentionally breaking existing behavior. Close monitoring and dynamic handling are essential. When Apple fixes WebKit or Google adds third-party RP support, re-evaluate and simplify your detection logic. The passkeys space moves fast; your implementation should too.

Add passkeys to your app in <1 hour with our UI components, SDKs & guides.

Start Free Trial

Share this article


LinkedInTwitterFacebook