A contact form gated by a Trust Check
This form runs in keyless mode against the production API: no site key, no account, no secret. Nothing you type is stored; the server only verifies the Trust Check.
- The page renders the widget in explicit mode and keeps Send disabled.
- You click the box. The widget asks Polyguard for this page’s link, then shows a code to scan with your phone.
- Your phone completes the Trust Check. The widget puts the result in a hidden pg-trust-check-response input and calls its callback, which enables Send.
- Send posts the form to /api/submit on this site. That handler calls /v2/siteverify, compares hostname with the hostname this page was served from, and returns what it received.
- The result verifies once. The widget resets, so a second message needs a new Trust Check.
// app/api/submit/route.ts (abridged)
const response = form.get('pg-trust-check-response');
const body = new URLSearchParams({ response, remoteip });
if (process.env.POLYGUARD_SITEVERIFY_SECRET) body.set('secret', ...);
const siteverify = await fetch('https://api.polyguard.ai/v2/siteverify', {
method: 'POST', body,
}).then((r) => r.json());
const verified = siteverify.success && siteverify.hostname === requestHost;
return Response.json({ verified, hostname_matched, siteverify });The full handler is app/api/submit/route.ts in the repo. Moving from another CAPTCHA? See the reCAPTCHA and Turnstile guides.