Skip to main content
The widget runs a browser check when it loads. By default, an uncontradicted result returns a token without interaction. A contradicted or refused result requires a phone challenge before a token is issued. Your server verifies the token before accepting the form.

Before you start

  1. Create an account or sign in and create a site with the domain your form is served from.
  2. Verify the domain using the instructions below.
  3. Take the site key (hrtc_live_…) for the page and issue a secret key (hrtc_sk_…) for your server.
Use the test keys to check your form integration before creating an account.

Add the widget

On success the widget writes a token into a hidden heretic-response field in the form. On a phone the ceremony runs inline. On a desktop it shows a QR code that continues on a phone.

Verify your domain

In the dashboard, open the site, set its domain, and publish the token it gives you in one of two places: Then press Check now. A verified site accepts its domain and subdomains. Changing the domain requires verification again. Until then the widget reports site-unverified and issues no token.

Configure

Challenge concealed connections

Concealment indicators are reported separately from the verdict. An uncontradicted probe can still report concealment, so this setting is independent of data-escalate. Enable this option when your policy requires a challenge for a connection with concealment indicators.
A ceremony with detected concealment stays pending and asks the visitor to disable the VPN, proxy, or relay. The visitor can retry before the original expiry. See what a pass means. The widget also requests a challenge if the probe cannot be read. data-cdata correlates the result with an attempt in your application. It never selects a passkey account. Use the authenticated challenge API with account_ref for account-bound authentication.

Script API

heretic.getResponse(id), heretic.getClearance(id), heretic.reset(id), heretic.remove(id), heretic.execute(id), heretic.isExpired(id). heretic.challenge(url) opens a ceremony minted by the challenge API. A page that also loads the collector keeps one heretic name: heretic({ siteKey }) runs the probe and heretic.render(...) runs the widget, whichever script loads first.

Test keys

A real secret never accepts a test token. To exercise the ceremony itself, use a real site key with data-mode="challenge".

Verify on your server

Send expected_hostname, expected_action, and expected_cdata from your server session, and require success === true. Use policy: "challenge" with challenge-only mode and reject_concealed: true when your backend requires no observed concealment. Browser attributes cannot enforce your backend policy. request_id reads the full assessment at GET /v1/verdict. Each probe or completed ceremony supplies one single-use proof, expiring 300 seconds after the probe opened or the ceremony completed. Repeating a token exchange does not renew it. Every field and error code is on the siteverify page. Node, Python and PHP clients implement siteverify, verdict reads and challenge calls. The plain HTML guide includes a complete form and backend.

Content security policy

For the heretic.challenge(url) modal, also allow https://heretic.tech in style-src so its external guard.css can load. The modal supports keyboard focus containment, Escape dismissal when allowed, and focus return.

Limits

60 widget calls a minute per visitor address, 1,200 decisions a minute per site, and 500 ceremonies open per account. Over a limit the widget reports 429 through data-error-callback. The widget counts one probe per visitor and one challenge per ceremony against your plan. Sandbox stops at its limit and the widget reports quota-exceeded.