Common errors
getSession() rejects or the import fails
Cause: getSession() doesn’t return null. It resolves with { sessionId, sealedToken } or rejects with a FoilError. A rejection means Foil.start() hasn’t resolved (runtime.unavailable), the runtime failed to start, or the handoff request failed or timed out (runtime.session_failed). If import("https://cdn.usefoil.com/t.js") itself rejects, the script didn’t load, and the page has no client to call.
Fix: Await Foil.start() before you call getSession(), and read error.code on the rejection. See Browser SDK → Error codes for each code and the recommended fallback policy.
Sealed token verification fails
Cause: The publishable key used in the browser and the secret key used on the server belong to different organizations or different environments (test and live). Fix: Verify both keys are from the same organization and the same environment. Check the dashboard for your active key pairs.Many sessions return inconclusive
Cause: The evidence for those sessions is mixed. The score falls between the typical human and bot ranges, a high score has no deterministic corroboration, or a behavioral-phase result has too little interaction for a human verdict. A session with no sign of automation that you evaluate before any interaction gets a provisional human verdict in the snapshot phase, not inconclusive.
Fix: Log decision.phase, decision.is_provisional, and decision.risk_score for the affected sessions to see which case applies. Call getSession() at action time, when the user submits, rather than on page load, so the result includes behavioral evidence. If the sessions come from a page with monitoring or tag manager scripts, see Frontend JavaScript compatibility.
Webhook returns 401
Cause: TheX-Foil-Signature header doesn’t match.
Fix: Verify you’re computing the HMAC over ${timestamp}.${rawBody} using both the X-Foil-Timestamp and the raw request bytes (not JSON.stringify(req.body) which may reorder keys).
FAQ
Q: Does Foil add latency to my pages? A: The browser SDK loads asynchronously and doesn’t block rendering. ThegetSession() call adds ~50-200ms depending on how much behavioral data has been collected.
Q: What happens if the Foil CDN is down?
A: Your application continues to work if you handle the failure. When the script doesn’t load, the import() rejects, and when a handoff request fails, getSession() rejects with a FoilError. Catch both and apply a fallback policy (for example, allow the request but flag it for review). See Browser SDK → Fallback policy.
Q: Can I use Foil with a Content Security Policy?
A: Yes. Add cdn.usefoil.com and 'wasm-unsafe-eval' to your script-src directive and api.usefoil.com to your connect-src directive, and allow blob: workers and same-origin frames. See Content Security Policy for the full list.
Q: How long are sessions stored?
A: Sessions are available via the API for 90 days. Fingerprints are stored for 1 year.