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

isUVPAA iOS 26.2 Bug: Fixed in iOS 26.3 stable

The iOS 26.2 WKWebView passkey detection bug where isUVPAA() returns false on Chrome is confirmed fixed in iOS 26.3 stable (23D127, Feb 11, 2026).

Vincent Delitz

Vincent

Created: February 3, 2026

Updated: March 20, 2026

isUVPAA iOS 26.2 Bug: Fixed in iOS 26.3 stable

Timeline: iOS 26.2 isUVPAA Bug#

Last updated: February 19, 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
Feb 11, 2026iOS 26.3 stable (23D127) fixes WKWebView bug✅ Fixed in Stable
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: Apple shipped the WebKit fix in iOS 26.3 stable (23D127, Feb 11, 2026). Once you can safely drop support for iOS 26.2, you can revert to simpler logic without the getClientCapabilities() branch. The Chrome workaround is still pending - monitor the timeline and simplify once both fixes are widely adopted.

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.

Frequently Asked Questions#

How do I detect passkeys reliably on iOS after the iOS 26.2 isUVPAA() bug?#

On non-Safari iOS 26.2+ browsers (Chrome, Edge, Firefox), use getClientCapabilities().userVerifyingPlatformAuthenticator instead of isUVPAA(), which always returns false due to the WKWebView bug. For Safari on iOS 26.2+, isUVPAA() works correctly and is actually more granular, returning true only if a passkey provider is configured. iOS 26.3 stable fixed the regression, so once iOS 26.2 support can be dropped the getClientCapabilities() branch can be removed.

What is the difference between isUVPAA() and getClientCapabilities() for passkey detection on iOS?#

isUVPAA() returns a single boolean and has been supported since Safari 13+, while getClientCapabilities() returns a full capabilities dictionary and requires Safari 17.4+, Chrome 133+ or Firefox 135+. On iOS 26.2 WKWebView-based browsers the two APIs diverge: isUVPAA() incorrectly returns false while getClientCapabilities().userVerifyingPlatformAuthenticator returns true, reflecting actual device capability. This divergence made getClientCapabilities() the practical workaround for the duration of the iOS 26.2 regression.

Why does isUVPAA() return false on Chrome iOS even though my device has Face ID and passkeys work?#

This is an unintended WKWebView bug introduced in iOS 26.2. Because Apple requires all iOS browsers to use the WebKit engine, the broken isUVPAA() implementation in WKWebView affected Chrome, Edge, Firefox and every in-app webview. Apple acknowledged the bug and shipped a fix in iOS 26.3 stable (build 23D127, February 11 2026).

Can I just use getClientCapabilities() everywhere to avoid the isUVPAA() iOS bug?#

No, because getClientCapabilities() reports device hardware capability rather than whether a given context can actually use passkeys. In the Google App WebView on iOS, getClientCapabilities() returns true but passkeys do not work for third-party relying parties, so assuming support would cause authentication failures. The recommended approach is context-aware: assume false for Google App WebView, use isUVPAA() for Safari iOS 26.2+ and fall back to getClientCapabilities() only for other iOS 26.2+ browsers.

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

Start Free Trial

Share this article


LinkedInTwitterFacebook