Skip to main content
This example serves a form at /check and saves one receipt after successful server verification. It includes the backend, browser-session binding, error handling, and a persistent record that prevents duplicate writes.

1. Run locally

Install Node 24 or later. Download and extract the server examples, then run:
Open http://127.0.0.1:3000/check. Wait for the widget, then choose Save receipt. Repeating the same submission returns the same receipt. The supplied configuration uses public test keys and labels the page as local test mode. These keys exercise the form and API connection; they do not exercise browser measurements, phone ceremonies, or production policy checks. Production mode rejects test proofs.

2. Use your keys

Create a site and verify its domain. In your server’s private environment, set:
Use the exact dashboard values in place of the labels above. APP_ORIGIN is your form’s exact HTTPS origin, with no path or trailing slash. Restart the server. The local HTTP server listens on loopback; serve it through your existing HTTPS reverse proxy.

3. The form

The example generates the attempt ID on the server and saves it with an HttpOnly browser-session cookie. Its HTML includes:
The downloadable server replaces those placeholders. The widget adds the hidden heretic-response field. Its default mode requests a phone challenge after a contradicted or refused probe. The POST handler checks the request Origin and saved session, then calls siteverify with server-chosen policy, hostname, action, attempt ID and site ID. Missing proof, failed verification and network errors cannot save a receipt. See verification policies before changing the example’s uncontradicted policy.

4. Connect your write

examples/lib/form-flow.mjs saves the receipt and consumes the attempt in one SQLite transaction. Replace that write with your application’s account or order write in the same transaction. Bind authenticated account IDs and submitted business data to the saved attempt as well. For serverless or multiple-host deployments, use your application’s shared database with equivalent transactions and unique constraints. A local SQLite file needs persistent storage. The standalone API clients work independently of this example store. The example’s CSP permits https://heretic.tech in script-src and frame-src. Merge those sources with your existing policy. Its response includes Cache-Control: no-store so caches cannot share a visitor’s pending form.

Check the integration

  1. Submit without a token: the write is refused.
  2. Repeat a successful submission: the same receipt returns.
  3. Change the attempt or use another browser session: the write is refused.
  4. Interrupt verification: the action stays pending; retry the same submission.
  5. Use real keys to check an uncontradicted probe and a phone challenge on your verified domain.
Test keys accept repeated tokens and bypass production context checks. Real keys are required for the final step.