Website integration
Callbacks
onVerified, onChange, the imnotahuman:verified and imnotahuman:change DOM events, and the exact payloads they carry.
onVerified
const off = window.imnotahuman.onVerified((result) => {
// result.verified === true
fetch("/api/agent-session", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ token: result.token }),
});
});
// later: off();{
"verified": true,
"type": "agent",
"agent_id": "agent_nova_8f2a",
"agent_name": "Nova",
"verification_method": "ed25519_challenge",
"mode": "live",
"challenge_id": "ch_mfr4q2xk7tbn3ycz5w6ah2ep4d",
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImluaC1...",
"issued_at": "2026-09-20T12:00:07.412Z",
"expires_at": "2026-09-20T12:10:07.000Z"
}verification_method is ed25519_challenge for registered agents, web_bot_auth for the experimental HTTP Message Signatures path, and simulated in test mode. token is null only if the token was already consumed or expired by the time the widget polled.
onChange
window.imnotahuman.onChange(({ status, challenge, result, error }) => {
// status: "LOADING" | "PENDING" | "VERIFIED" | "REJECTED" | "EXPIRED" | "ERROR"
// challenge: the challenge document or null
// result: VerifiedResult when status === "VERIFIED", else null
// error: an API error code such as "ORIGIN_UNAUTHORIZED" when status === "ERROR"
document.body.dataset.agentCheck = status;
});The listener runs immediately with the current snapshot, then on every transition.
DOM events
Both callbacks have DOM equivalents dispatched on the host element with bubbles: true, so you can listen at the document level without a reference to the widget:
document.addEventListener("imnotahuman:verified", (event) => {
const result = (event as CustomEvent).detail; // VerifiedResult
});
document.addEventListener("imnotahuman:change", (event) => {
const { status, error } = (event as CustomEvent).detail;
});| Event | detail | Fires |
|---|---|---|
imnotahuman:verified | VerifiedResult | Once per verified challenge |
imnotahuman:change | { status, challenge, result, error } | On every status change |
Multiple widgets
window.imnotahuman.onVerified and onChange subscribe to every widget on the page, including ones mounted later. getChallenge() and getResult() read the first widget only; use the instance returned by render() or the widgets array for others.
Security note
Anything a callback tells you can be forged by a script on the page. Use callbacks to update the UI and to forward the token; make decisions only after server verification.