Skip to main content
Every Foil session produces a verdict (human, bot, or inconclusive) and a risk score (integer 0100). Your backend uses these to decide what to do.

Verdicts

VerdictScore rangeMeaningSuggested action
human0 – 39Real user behavior detectedAllow
inconclusive40 – 69Not enough evidence for a confident callChallenge or gather more context
bot70 – 100Automated or non-human behavior detectedBlock or rate-limit

Risk score

The risk score is an integer from 0 (definitely human) to 100 (definitely bot). It’s normalized via a sigmoid function, so scores cluster near the extremes — most sessions score below 10 or above 90. Use the score for granular policy when the verdict alone isn’t enough:
if risk_score < 10  → fast-path allow (no friction)
if risk_score < 40  → allow (human verdict)
if risk_score < 70  → challenge (inconclusive)
if risk_score >= 70 → block (bot verdict)

Evaluation phases

Foil evaluates sessions in two phases:
PhaseWhenWhat it usesConfidence
snapshotImmediately on session creationEnvironment probes, fingerprint, anti-tamperGood for deterministic signals
behavioralAfter user interactionMouse, keyboard, touch, timing patternsHigher confidence for ambiguous cases
If you call getSession() before the user interacts with the page, you’ll get a snapshot-phase result. For highest confidence, wait for at least a few seconds of user interaction.

Preliminary vs final

StatusMeaning
preliminaryEarly result, may be updated as more data arrives
finalComplete evaluation, won’t change
Snapshot-phase results are usually preliminary. Behavioral-phase results are final.

Automation attribution

When Foil identifies the specific automation tool, the session includes attribution details:
CategoryExamples
automationPlaywright, Puppeteer, Selenium
ai-agentbrowser-use, OpenAI Operator
crawlerGooglebot, Bingbot
verified-botLegitimate crawlers with Web Bot Auth
fabricatedAnti-detect browsers, spoofed profiles
Attribution includes the framework name, variant, organization (if known), and a confidence score.

Using verdicts in your API

The sealed token returns the Decision shape directly:
{
  "verdict": "bot",
  "risk_score": 94,
  "phase": "behavioral",
  "is_provisional": false
}
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.)
Sealed token fieldSession API fieldValues
verdictdecision.automation_statushumanhuman, botautomated, inconclusiveuncertain
risk_scoredecision.risk_score0100 integer (same scale)
phasedecision.evaluation_phasesnapshot or behavioral (may be null on sessions that haven’t evaluated yet)
is_provisionaldecision.decision_statustruepreliminary, falsefinal
The underlying data is identical — only the field names and the automation_status / decision_status value labels differ.

Policy recommendations

  1. Start with report-only — log verdicts without blocking for the first week
  2. Treat inconclusive as an opportunity — challenge with CAPTCHA or email verification, don’t block
  3. Wait for behavioral phase on high-value actions when possible
  4. Use the score for edge cases — a bot verdict at 71 is weaker than one at 98
  5. Keep your Foil decision in your audit trail — log the sessionId alongside the business action

What’s next