None of these tells you who the person is.
In the page, live
When the widget offers Link with BotShield ID, it also keeps a live connection to BotShield that answers one question: is this account secured right now? It needs no tap.- The offer is on in the Console, on the site key’s Link with BotShield ID surface or on the gate named in
scope. platform-user-refis set.site-keyis apk_test_...orpk_live_...key, and the page origin is in its allowed origins.
botshield:presence
The widget fires botshield:presence with its first answer, and again each time the answer changes.
fresh and stale both mean secured. fresh_until is a time BotShield works out from the person’s latest passkey use. It is null when state is none. BotShield does not send a change from fresh to stale that comes only from the clock passing fresh_until. If you need that, compare fresh_until with your own clock.
The detail never carries a handle, a BotShield ID, a gate name or a request ID.
The widget acts on the answer itself: on none it puts the Link with BotShield ID chip back, and on fresh or stale it shows Account secured. Listen for the event when the rest of your page has to change too.
When the connection drops
The widget never shows an account as secured without an answer from BotShield.
The re-read when the tab becomes visible again needs widget
3.0.12 or later — the current stable version at /sdk.js. Pinned 3.0.9 has the live connection and the 60-second fallback only. See Widget versions.On your server, pushed
Two webhook events keep your records in step when the person is not on your site. Both carry the account’shandle, an opaque value that starts with OP_, and never your platform-user-ref.
surface_id names the Link with BotShield ID surface the account was secured on. It is null for a link made through a gate. See Token and webhooks for the full payloads.
environment field, and a person’s handle is the same in Development and Production. Keep Development traffic away from the endpoint your production system reads. Set up delivery, signatures and deduplication in the Webhooks overview.
On a fresh pass
Every time the person passes, with the chip or at one of your gates, your page receives a signed token. Your server checks it withPOST /sdk/verify-token, and the claims say whether the account is secured at that moment. At a gate, send the same platform-user-ref with the request, or the claim has no account to look up and reads false.
data.data.claims.trusted. It is true only when an active link exists for your platform and the platform-user-ref that came with the pass. It is false for an account that was never secured, or was unlinked. This is the strongest of the three answers: it is signed, and it comes from a live human who just used their passkey. See Token and webhooks for every claim and check.
What there is not
There is no server-to-server call today that asks “is this account secured right now?” without a pass. The live answer in the page is for the widget, and BotShield checks it against your site key’s allowed origins. Between passes, your server’s best answer is the lastaccount.secured or account.unlinked event it recorded for the handle. When it matters, ask for a pass and read trusted on the token.
Putting it together
1
On account.secured
Store the handle beside your user, and mark the account secured.
2
On every pass
Verify the token on your server. Update your record from
trusted.3
On account.unlinked
Find the user by handle and mark the account not secured.
4
In the page
Listen for
botshield:presence and update what the person sees while they are on your site.