human, bot, or inconclusive) and a risk score (integer 0 – 100). Your backend uses the verdict to decide what to do.
Verdicts
The score ranges are typical, not a fixed mapping. Foil decides the verdict from the score together with the evidence behind it:
- Definitive evidence of automation produces
bot, whatever else the session shows. - A score of
70or higher becomesbotonly when deterministic evidence corroborates it. Behavioral evidence alone never producesbot, so a high score without corroboration givesinconclusive. - In the snapshot phase, a score below
40giveshuman. After the snapshot phase, a score below40giveshumanonly when the session has enough behavioral evidence, and otherwise givesinconclusive.
verdict, not on the score.
Risk score
The risk score is an integer from0 to 100. A higher score means stronger evidence of automation. Foil combines the evidence from each detection category and normalizes the result with a sigmoid function.
Branch your policy on the verdict:
inconclusive sessions first, or treat a bot verdict at 71 with more caution than one at 98.
Evaluation phases
Foil evaluates sessions in two phases:If you call
getSession() before the user interacts with the page, you get a snapshot-phase result, which is provisional. A session that shows no sign of automation typically receives human. For the highest confidence, call getSession() after the user has interacted with the page for at least a few seconds, so that the result includes behavioral evidence.Preliminary vs final
Snapshot-phase results are always
preliminary. Behavioral-phase results are always final.
Attribution
When Foil can tell what is behind a session, the session includes attribution: a list of labels and a list of behaviors. Attribution helps you log and review sessions. Useverdict to decide whether to allow, challenge, or block.
Each label has a kind, a machine-readable value, and a confidence.
Behaviors describe how the session produced input. Each behavior has a
channel (typing, form, mouse, touch, scroll, or clipboard), a value such as synthetic-typing or natural-mouse, and a confidence.
The two places that return attribution use slightly different shapes:
- The session detail endpoint (
GET /v1/sessions/:id) returnsattributionwith alabeldisplay string on each entry and confidence as an integer from0to100. - The sealed token returns
attribution.botwith the samelabelsandbehaviorslists, but its entries have nolabelstring, and confidence is a number from0to1.
attribution (session detail) and attribution.bot (sealed token) are null when Foil has nothing to report, so check for null before you read labels.
Using verdicts in your API
The sealed token returns theDecision shape directly:
event_id is unique to each token, and evaluated_at is the time Foil produced it. manipulation is null when Foil has no manipulation assessment for the session.
The session detail endpoint (GET /v1/sessions/:id) renames these fields into a more descriptive, action-oriented vocabulary. (The list endpoint, GET /v1/sessions, keeps the sealed-token names - verdict, phase, is_provisional - in its latest_decision summary.)
The underlying data is identical - only the field names and the
automation_status / decision_status value labels differ. The session detail decision also carries event_id and evaluated_at under the same names, and it doesn’t include manipulation or evaluation_duration_ms.
Policy recommendations
- Start with report-only - log verdicts without blocking for the first week
- Treat
inconclusiveas an opportunity - challenge with CAPTCHA or email verification, don’t block - Wait for behavioral phase on high-value actions when possible
- Use the score for edge cases - a
botverdict at71is weaker than one at98 - Keep your Foil decision in your audit trail - log the verified
session_idalongside the business action
What’s next
- Detection categories - what signals feed into the score
- Server verification - verify handoffs on your backend
- Sessions API - full session detail response