Webhooks
When the server finishes scoring an identification, it pushes the result to your configured callback URL as aPOST. This is the canonical, low-latency way to receive the Risk Score and the signals behind it.
This page is the reference: the envelope, the field schema, the two phases, and how to verify the signature. For a step-by-step walkthrough of configuring and testing a callback, see the webhook setup guide.
You do not poll for webhooks. The server sends them to the callback URL you set per domain (in the dashboard or via the Management API). Delivery is at-most-once with no retries, so pair it with a History API read when you cannot afford to miss a result.
The envelope
Every webhook is a JSON object with exactly two top-level keys:Data (the WebhookBody) and Assing (the signature).
Assing. Your endpoint must be reachable over HTTPS and return quickly (see delivery guarantees).
WebhookBody
TheData object. Field names are PascalCase.
The client-generated UUID for this identify call. This is the join key across the snapshot, the webhook, and the History API. Both the
initial and update phases carry the same RequestID. Make your handler idempotent on this value.Per-visit identifier from the browser’s
sessionStorage (a 10-minute visit window). Resets each browser session or tab.First-party cookie /
localStorage identifier minted client-side. Lost when the user clears cookies or storage.Server-derived identity, a UUID5 of dozens of stable browser-fingerprint components. Durable: survives cleared cookies, incognito, and IP rotation within the same browser, because it is derived from the browser environment rather than stored. Browser-bound: a different browser produces a different DeviceID (no cross-browser recognition today). See Identifiers.
Server-derived
UUID5(DeviceID + CookieID). Changes when the cookie is cleared (the CookieID regenerates, so a new VisitorID is produced). Multiple VisitorIDs can map to one DeviceID. The durability claim belongs to DeviceID, not VisitorID.The client IP address resolved for this call.
The operating system the browser reports (for example
Windows, Mac OS X, iOS).Two-letter ISO country code derived from the IP (for example
US).The customer’s own account id, passed in through the snippet via
checkAuthenticatedUser. This must be a hashed or pseudonymous value, never a raw email or user id. Absent on anonymous calls.The Risk Score, an integer from 0 to 100 (hard-capped at 100). Higher means more anonymous or more likely masked, spoofed, or abusive. The bands are Clean (0-9), Low (10-29), Medium (30-59), and High (60-100). ShieldLabs scores; your application decides allow, challenge, review, or block.
The explainable breakdown: every signal that contributed to the score, as
{ "Value": <int>, "Description": "<signal>" }. Value is the points the signal added; Description is the signal name. On the initial phase this is the full list. On the update phase it carries only the delta (see Phases).Timestamp of the request, in RFC 3339 / ISO 8601 form (for example
2026-06-16T10:00:00Z).Which delivery this is:
"initial" (the first score, sent about a second after ingest, before the WebRTC real-IP result) or "update" (recomputed after the real-IP check). See Phases.Phases
A single identification can produce up to two webhooks, both joined by the sameRequestID.
Phase | Timing | Details content |
|---|---|---|
initial | ~1s after ingest, before the WebRTC real-IP result | The full list of signals that fired |
update | After the real-IP (STUN) check resolves (optional) | Only the delta signals, not the full list |
update webhook is optional and is suppressed if more than about 10 seconds elapsed since the snapshot was created. Treat the initial score as actionable on its own, and apply the update delta when it arrives to refine your decision. Full background on why scoring is split this way is in the Identification Flow.
Example: initial webhook
The first delivery carries the fullDetails list.
Example: update webhook (delta)
When the real-IP check completes, anupdate may follow with only the new signals in Details. Here the real-IP comparison adds an IP-mismatch signal, raising the score from 25 to 55.
On the
update phase, Score is the full recomputed value (0-100), but Details lists only the signals added since the initial delivery. To keep a complete picture, merge the update deltas into the Details you stored from the initial webhook, keyed by RequestID.Verification
Verify the signature on every webhook before acting on it. The recipe:Data object (the WebhookBody), not over the full {Data, Assing} envelope. To verify, take the received Data, re-serialize it (or HMAC the raw Data bytes as received), compute HMAC-SHA256 with your Secret Key, hex-encode it, and constant-time compare against Assing.
Delivery guarantees
Webhook delivery is intentionally lightweight. Design your handler around these properties.At-most-once
Each phase is sent in a single fire-and-forget attempt. There is no retry, no backoff, and no dead-letter queue. A dropped network connection means that webhook is gone.
~1s timeout
The sender waits about one second for your endpoint, then moves on. Acknowledge with a fast
2xx and do heavy work asynchronously, off the request path.Idempotent on RequestID
The same
RequestID can arrive twice (an initial and an update). Key your writes on (RequestID, Phase) so a repeat is a no-op.Read fallback
For anything you cannot afford to miss, read the result from the History API by
request_id. That is the guaranteed, pull-based path.Persist the RequestID early
Capture
requestID from the snippet callback and store it with the user action you are protecting.Apply the initial webhook
On the
initial phase, record Score and Details against that RequestID. Verify the signature first. Treat the write as idempotent.Merge the update delta
If an
update phase arrives, merge its delta Details and use the recomputed Score.Acting on the payload
The webhook gives you theScore and the Details behind it. ShieldLabs surfaces signals; your application owns the decision. A legitimate user can score high (a corporate proxy, a VPN, a privacy browser), so decide on Score + Details + the action context, never the number alone.
| Band | Range | Recommended customer action (a guide, not a rule) |
|---|---|---|
| Clean | 0-9 | Pass through, no friction |
| Low | 10-29 | Allow, worth logging |
| Medium | 30-59 | Step-up challenge, second look, or review |
| High | 60-100 | Block, review, or require verification |
Next steps
Set up a webhook
The tutorial: configure your callback URL, test it, and go live.
Data Models
The full WebhookBody and Snapshot schemas in one place.
Management API
History search by RequestID, the snapshot superset, profile, and callback config.
Risk Score
How the 0-100 explainable score and the Clean / Low / Medium / High bands work.