Network lookup unavailable
The response is still returned, marked state: unavailable with a reason, and carries no suspect score rather than a smaller one.
The SDK describes the device at the moment that matters. The server identifies it, checks its network, runs every detection and scores the result, and sends it all back in the same response. Your server makes the decision.
Everything up to the answer happens inside a single identify request.
At signup, login or checkout, the SDK describes the browser or app under a strict time budget and never shows the visitor a prompt.
await fingerly.identify({ tag: "checkout" })The report goes to the identify endpoint with a public key that only works from the origins you allowed.
POST /api/v1/identifyThe server recognises the device, looks up the network, runs every detection again on its side, and adds up your weights.
The response carries the visitor ID, score and triggers. Your backend reads the stored result with a secret key, or receives it by webhook, and acts.
GET /api/v1/events/{request_id}Code that runs on a visitor’s device can be edited by that visitor. So the SDK reports what it observed, and the server draws the conclusions. The visitor ID is issued by Fingerly, not computed in the page, and every detection is run again over the stored report.
That split has a second benefit. A detection improved on the server applies to the next request scored, for every integration at once. On mobile, where an app update can take months to reach every phone, that is the difference between a fix this week and a fix next year.
The score in your hand came from a device you do not control. Use the client result for a hint in the interface. Block on the server’s.
The identify response, in the order the API writes it. Fields that do not apply are left out rather than sent empty.
request_idstringvisitor_idstringvisitor_is_newbooleanidentifiablebooleanvisitor_confidenceintegerstatestringsuspect_scoreintegersuspect_levelstringtriggersarray{
"request_id": "01a0a84b-e6a2-7c09-9f51-0b3d7a26c8e4",
"visitor_id": "X9pL2mRc7KvT4bQw8NdF",
"visitor_is_new": false,
"identifiable": true,
"visitor_confidence": 100,
"state": "enriched",
"suspect_score": 23,
"suspect_level": "medium",
"triggers": [
{
"signal": "automation",
"group": "bot",
"weight": 9,
"confidence": "high"
},
{
"signal": "tampering",
"group": "browser_tampering",
"weight": 8,
"confidence": "medium"
},
{
"signal": "high_activity",
"group": "high_activity",
"weight": 6,
"confidence": "high"
}
]
}A synthetic example. Some responses also carry a short-lived deferred_token, used by the SDK for a follow-up report.
A fraud check should never take your checkout down, and it should never pass off missing information as a clean result.
The response is still returned, marked state: unavailable with a reason, and carries no suspect score rather than a smaller one.
A visitor ID is still issued, identifiable is false, and the thin report is itself scored as fingerprint suppression.
Only the high activity and cross-device signals go quiet. Every other detection keeps scoring.
Detection fails open so your product keeps working. Your policy can still refuse any request that arrives without a score.
Start with the signals, keep your own decisions, and pay only for what you identify. No credit card needed.