Quickstart
The fastest path from "I just made an account" to "my form is protected". You need a page with a <form> and a backend that can make an outbound HTTP call. No build step required.
By the end of this guide your form submission will only accept entries from a verified human.
1. Get a site key
Sign in to the dashboard and create a new site. You will receive two values:
| Value | Where it lives | Shape |
|---|---|---|
| Public site key | Embed in the page HTML | cpt_pub_... |
| Secret | Server-side only; never ship to the browser | cpt_sec_... |
Save the secret somewhere your backend can read it — environment variable, secrets manager, whatever you already use.
2. Drop the widget into your form
Paste these two lines into the page that hosts the form you want to protect:
<script src="https://cdn.jsdelivr.net/npm/@caputchin/widget@1/dist/widget.js"></script>
<form action="/submit" method="POST">
<!-- your existing form fields -->
<input name="email" type="email" required />
<caputchin-widget sitekey="cpt_pub_..."></caputchin-widget>
<button type="submit">Sign up</button>
</form>
On successful completion the widget injects a hidden <input name="caputchin-token"> into the enclosing <form>. Nothing else on your page needs to change.
If you want a game challenge instead of the invisible default, add the game attribute. See widget for the full attribute table.
3. Verify on your backend
When the form posts to /submit, your handler receives one extra field: caputchin-token. Pass it to /siteverify along with your secret:
// Node 18+
app.post("/submit", async (req, res) => {
const verdict = await fetch("https://api.caputchin.com/api/v1/siteverify", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
secret: process.env.CAPUTCHIN_SECRET,
response: req.body["caputchin-token"],
}),
}).then((r) => r.json());
if (!verdict.success) {
return res.status(400).json({ error: verdict["error-codes"] });
}
// Verified — continue your normal sign-up flow.
});
Snippets for Python, Go, PHP, and curl are in snippets.
4. Submit the form
Open the page, fill in the form, complete the widget challenge (or wait for the invisible flow), and hit submit. Your backend should log a successful verification.
If something is wrong, the response carries an error-codes array. The full mapping is in troubleshooting.
What just happened
| Step | Where | What it does |
|---|---|---|
| Widget mounts | Browser | Loads the challenge surface inside a sandboxed iframe |
| User completes the challenge | Browser | Proof-of-work runs in the iframe, isolated from your page |
Widget injects caputchin-token |
Browser | One-time token, single-use, expires after 10 minutes |
| Your form posts | Backend | Token rides along with the rest of the form fields |
/siteverify |
Server-to-server | Caputchin checks the token, returns success: true or an error code |
Next steps
- Integrate the widget — deeper attributes, events, programmatic control
- Verify server-side — long-form backend integration including idempotency notes
- Troubleshooting — what each error code means and how to recover
- Migrate from reCAPTCHA — field-by-field swap