Load the SDK
One script tag with your public site key. The key only works from domains you whitelist.
pk_live_ key · ~5.6 KB gzip
Human Entropy Integrity Protocol
HEIP reads live interaction for signs of automation. Your server then allows, steps up or denies each sensitive action.

The login passed. The CAPTCHA was solved. The token is valid. None of it says who is driving the session when it moves money.
HEIP watches the session itself, not the account. These are four patterns the engine flags today, with the reason code it reports.
Scripts that fake human timing
timing_quantizedHeadless browsers with too-perfect motion
overly_smooth_motionReplayed or forged signal payloads
proof_mismatchInput from a hidden or unfocused tab
active_while_hiddenThe browser collects evidence. Only your server, holding the secret key, ever hears the decision.
One script tag with your public site key. The key only works from domains you whitelist.
pk_live_ key · ~5.6 KB gzip
About once a second the SDK sends timing and motion deltas, chained with an HMAC so a forged or replayed batch is rejected.
POST /v2/signal/:sessionId
When evidence is thin or risk climbs, the server answers with a canary or challenge directive that needs a live response.
directive: canary | challenge
On submit, prepareAction() returns a single-use nonce tied to this session and this action. It expires in 25 seconds by default.
TTL 5 to 120 s
Your backend sends the nonce to /v2/verify with its secret key and gets ALLOW, STEP_UP or DENY with reasons. The browser never learns the verdict.
POST /v2/verify
The public site key runs in the page. The secret key stays on your backend and is the only thing that can read a verdict.
<script src="https://api.heip.io/sdk.js"
data-site-key="pk_live_…" async></script>
<script>
form.addEventListener("submit", async (e) => {
e.preventDefault();
const { sessionId, actionNonce } =
await HEIP.prepareAction("payment");
await fetch("/api/pay", {
method: "POST",
body: JSON.stringify({ sessionId, actionNonce }),
});
});
</script>{
"success": false,
"decision": "STEP_UP",
"confidence": 0.71,
"risk": 1.32,
"stage": 1,
"mode": "enforce",
"reasons": [
{ "code": "policy_confidence_low",
"value": 0.71, "expected": ">=0.85" },
{ "code": "policy_stage_high",
"value": 1, "expected": "<=0" }
]
}Policies
Map your actions to a built-in template from the console, then override only the values you need. Your server keeps sending the same three fields.
strict_withdrawalPayouts, payout changes, API keys, admin
0.85min confidence
fast_tradingTrade confirms, order submits
0.78min confidence
marketplace_standardPosting, messaging, new listings
0.70min confidence
passive_consumption_observeWatching, reading, listening
0.55min confidence
A false DENY locks out a real customer, so it needs all four conditions at once. Anything else that fails a gate becomes STEP_UP. A site in observe mode never returns DENY.
Reasons come back as codes with the measured value and the expected one. Notable sessions also leave a short-lived audit trace you can fetch by id.
No identity, no biometrics, no stored profile. Session state lives in Redis and expires on its own.
SHA-256 only. Shown once, two active at most, 24 h grace on rotation.
A secret key used from a browser is refused and audited.
Label-boundary matching with Public Suffix List rules, so *.com is never allowed.
Run a site without enforcement. It never returns DENY while you tune policies.
Engineering
Each security guarantee is broken on purpose in a mutation run, and the suite has to fail. The engine is replayed against golden fixtures from the original implementation.
382
unit tests
207
end-to-end tests on real Postgres and Redis
115
mutation checks, each one caught
5.6 KB
browser SDK, gzipped

HEIP is self-hosted and in pilot. Tell us which action you want to protect and we will set up a site and keys with you.