Detecting Platform Authenticator Availability
The platform-authenticator probe answers one narrow question: does this device have a built-in authenticator that could answer a ceremony. It is the right input for deciding whether to offer enrolment and the wrong input for almost everything else. This page covers what it reports, where it belongs in the flow, and the mistakes that turn a helpful capability check into a lockout. It sits under Progressive Enhancement and Passkey Fallback Flows.
Probe Reference
| Probe | Answers | Latency | Can reject |
|---|---|---|---|
| API presence | is the credential API available at all | synchronous | no |
| platform authenticator available | is there a built-in authenticator | asynchronous, milliseconds | yes, on some engines |
| conditional mediation available | can passkeys appear in autofill | asynchronous, milliseconds | yes |
All three are independent. A device can have the API and no built-in authenticator; it can have a built-in authenticator and no autofill support; it can have both and hold no credentials at all.
Root Cause Analysis
1. Using it to gate sign-in. The most damaging misuse. A user whose passkey lives on their phone, signing in on a desktop with no built-in authenticator, gets a negative probe — and if that hides the passkey button, the cross-device flow they needed is now unreachable.
2. Treating it as a readiness check. A positive result means a device exists, not that it is enrolled, unlocked, or that the user will consent. Enrolment can still fail for entirely ordinary reasons, and the interface must handle that.
3. Blocking the render on it. It resolves in milliseconds, but “milliseconds” is not “always”, and a promise that never settles on some engine will leave the sign-in page in a loading state forever if the layout waits for it.
4. Not handling a rejection. Some engines throw rather than resolving false, particularly in hardened or embedded contexts. An unhandled rejection in the probe takes out the rest of your initialisation.
5. Caching the answer across sessions. Users plug in security keys, update operating systems and enrol biometrics they did not have last week. A persisted negative hides the passkey path indefinitely.
Step-by-Step Resolution
Step 1 — check API presence first, synchronously
If the credential API is absent there is nothing to probe, and the page should render its password form and stop.
Step 2 — wrap the probe so it cannot reject
Catch and coerce to false. The conservative answer is always safe, because the fallback is a working page.
Step 3 — probe once per page load, in memory
Module scope, not component state, and never persisted to storage.
Step 4 — use the answer only for the enrolment offer
Positive means offer enrolment on this device. Negative means offer a security key, or the cross-device path, or simply do not offer enrolment here.
Step 5 — leave sign-in alone
The passkey sign-in button stays visible regardless, because the credential may live somewhere else entirely.
Step 6 — reserve layout space
Render the container at its final height from the server so a resolved probe fills it rather than inserting an element under the user’s cursor.
Verification and Testing
Stub the probe to false and assert the page still renders a complete sign-in surface, that no enrolment offer appears, and that the passkey sign-in button is still present. That last assertion is the one that catches the gating mistake.
Stub it to reject and assert the same. Real engines do this, and an unhandled rejection is indistinguishable from a broken page.
With a virtual authenticator configured as an internal transport, assert the probe returns true and the enrolment offer appears. Remove the authenticator and assert the offer disappears on the next load but the sign-in path does not.
Pitfalls
1. Hiding the passkey sign-in button on a negative probe. Strands cross-device users.
2. Persisting the result. Guarantees a stale answer for anyone whose device gained support.
3. Awaiting it before first paint. Turns a capability check into a rendering dependency.
Frequently Asked Questions
Does a positive result mean the user has a passkey?
No, and nothing in the browser will tell you that. Credential existence is deliberately unobservable to a page; it is a question you answer from your own records once the user has identified themselves. The probe reports hardware capability only.
Should I offer enrolment when the probe is false?
Offer a different enrolment path rather than none. A device with no built-in authenticator can still enrol a security key, and a user who wants a passkey on their phone can be pointed there. What you should not do is present the same “set up a passkey on this device” copy that a positive probe would have earned.
Why do some browsers reject instead of returning false?
Because the check touches platform surfaces that may be unavailable in hardened, embedded or policy-restricted contexts, and the resulting failure surfaces as a rejection rather than a negative answer. Coercing both to false at the boundary makes the difference irrelevant to the rest of your code.
Is there a probe for whether a security key is connected?
No, and there should not be — enumerating attached authenticators would be a fingerprinting surface. The way to find out is to run the ceremony and let the user choose, which is why the sign-in button stays visible whatever the platform probe says.
How does this interact with the conditional-mediation probe?
They are independent and both worth running. A device can support autofill without having a built-in authenticator, because the credential may arrive over the cross-device flow. Treating one as a proxy for the other produces a page that hides the wrong thing.
Should the result be sent to analytics?
Aggregate counts are useful for understanding your population and deciding when to promote the passkey path. What to avoid is attaching the result to a user record alongside other device attributes, which turns a capability check into a fingerprint you did not previously hold.
Choosing the Enrolment Copy from the Result
The probe’s real value is that it lets you write two different enrolment offers instead of one vague one, and the difference in conversion between a specific offer and a generic one is large.
When the probe is positive, name the device. “Set up a passkey on this Mac” or “Use Touch ID to sign in next time” tells the user exactly what is about to happen and what they will do next time. The platform prompt that follows will match the expectation you just set, which is what stops the biometric dialog reading as an interruption.
When the probe is negative, offer the alternatives explicitly rather than falling silent. A security key is enrollable on almost any device, and a user who wants their passkey on a phone can be told to set it up there. “This computer does not support passkeys” is both slightly untrue and unhelpful; “Set up a passkey on your phone, or use a security key” gives them something to do.
When the API is absent entirely, say nothing about passkeys at all. There is no action available, and an offer the user cannot act on is noise that trains them to ignore the next one.
It is also worth deciding what happens on a device where the probe is positive but the user has already enrolled a credential on it. You know this from your own records rather than from the probe, and the right offer at that point is not another enrolment but a reminder that they can sign in with what they already have — which is the case a settings page usually handles better than a prompt.
Related
- Progressive Enhancement and Passkey Fallback Flows — the parent topic area and the layering this sits in
- Feature-Detecting Passkey and Conditional Mediation Support — the three probes together
- Conditional Mediation Browser Support Matrix — why runtime probes beat published tables
- Prompting Users to Add a Passkey — what to do with a positive result