Introduction

PrivCaptcha is a privacy-first captcha. A visitor proves they are human by solving a small visual puzzle while their browser silently computes a proof of work; your backend then redeems the resulting token with a server-to-server call. No cookies are set, no fingerprint is collected, and no state is kept on the visitor's device.

The flow

  1. Your page loads /1/api.js and contains a <div class="privcaptcha" data-sitekey="pk_...">.
  2. The visitor ticks the checkbox. The parent page — not the iframe — asks POST /api/v1/challenge for a puzzle.
  3. The visitor solves the puzzle. A Web Worker solves the proof of work in parallel, so it costs a human no wall-clock time.
  4. The answer and the proof-of-work nonce go to POST /api/v1/solve, which returns a single-use token.
  5. The token lands in a hidden privcaptcha-response input, so a plain form submit carries it to your backend with no JavaScript on your side.
  6. Your backend calls POST /api/v1/siteverify with your secret and the token. A token verifies exactly once.

Step 6 is not optional. A token that is never redeemed proves nothing — anyone can post a form field.

Two keys

Key Prefix Where it lives
Sitekey pk_ Public. Pasted into your HTML.
Secret sk_ Private. Server-side only, used at /siteverify.

The two are independent random values. The secret can never be derived from the sitekey.

What makes it different

  • No visitor state. Every identifier is a random server-side handle. The answer, the difficulty and the attempt count never leave the server.
  • Failure costs something. Wrong answers are capped per challenge (three by default), and a failing client is scored, so its next challenge is harder.
  • Proof of work as a bot tax. Solving takes a bot 2^N hashes per request; verifying takes us one. It is invisible to a human and expensive at a million requests.
  • Drop-in migration. Compatibility shims let an existing reCAPTCHA or hCaptcha integration move with a hostname change. See Migrating.

Next