CaptchaBox by natbox
A captcha your visitors never have to solve
Get your free site key Add it in 2 minutes
Try it
This is the real widget. It starts working as soon as the page loads, so it is usually done before you get to it.
Why CaptchaBox
- No puzzles. No traffic lights, no crosswalks, no "click every bus". Most visitors only see a tick.
- No cookies, no tracking, no Google. We do not store visitor IP addresses or build profiles. Nothing to add to a cookie banner.
- Works where Google is blocked, and on old phones: a plain script with no third parties, served from our server in Germany.
- Gets harder for bots, not for people. Each check costs a little computing time. Someone sending hundreds of requests gets much harder puzzles (up to 64 times harder), so mass spam becomes slow and expensive.
- Easy switch from reCAPTCHA, hCaptcha or Turnstile. The server check answers in the same format, and the widget can fill
g-recaptcha-responsefor you. - 7 languages (English, Arabic, Spanish, German, French, Portuguese, Turkish), right-to-left for Arabic, light and dark themes.
Add it to your site
1. Get a site key. Sign in to the client area (a free account is enough), add your site and its domain. You get a site key (public) and a secret (keep it on your server). Subdomains of your domain work automatically.
2. Put the widget in your form:
<script src="https://captcha.natbox.io/v1/widget.js" async defer></script>
<form action="https://natbox.io/contact" method="post">
<input name="email" type="email">
<div class="captchabox" data-sitekey="YOUR_SITE_KEY"></div>
<button>Send</button>
</form>
The widget adds a hidden field captchabox-response to the form. If the visitor presses Send before the check is done, the form waits and then sends itself.
Already using the older natbox.io/captchabox/v1/ and natbox.io/api/captchabox/v1/ addresses? They keep working; nothing to change.
3. Check the answer on your server before you accept the form. Send your secret and the response to our API:
POST https://captcha.natbox.io/v1/siteverify
secret=YOUR_SECRET&response=VALUE_OF_captchabox-response
{"success": true, "challenge_ts": "2026-11-03T17:36:11Z", "hostname": "example.com", "error-codes": []}
PHP
$r = json_decode(file_get_contents('https://captcha.natbox.io/v1/siteverify', false, stream_context_create(['http' => [
'method' => 'POST', 'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query(['secret' => 'YOUR_SECRET', 'response' => $_POST['captchabox-response'] ?? '']),
]])), true);
if (empty($r['success'])) { http_response_code(400); exit('Captcha failed, please try again.'); }
Node.js
const r = await fetch('https://captcha.natbox.io/v1/siteverify', {
method: 'POST',
body: new URLSearchParams({ secret: process.env.CAPTCHABOX_SECRET, response: req.body['captchabox-response'] || '' }),
}).then(res => res.json());
if (!r.success) return res.status(400).send('Captcha failed, please try again.');
Python
import json, urllib.parse, urllib.request
data = urllib.parse.urlencode({"secret": SECRET, "response": form.get("captchabox-response", "")}).encode()
r = json.load(urllib.request.urlopen("https://captcha.natbox.io/v1/siteverify", data, timeout=10))
if not r["success"]:
abort(400)
Switching from reCAPTCHA
| Change | reCAPTCHA v2 | CaptchaBox |
|---|---|---|
| Script | google.com/recaptcha/api.js | captcha.natbox.io/v1/widget.js |
| Widget | class="g-recaptcha" | class="captchabox" data-compat="recaptcha" |
| Form field | g-recaptcha-response | the same, with data-compat="recaptcha" |
| Server check | google.com/recaptcha/api/siteverify | captcha.natbox.io/v1/siteverify |
| Answer | success, hostname, error-codes | the same fields |
With data-compat="turnstile" the widget fills cf-turnstile-response instead.
Widget options
| Attribute | Values | What it does |
|---|---|---|
data-sitekey | your site key | Required. |
data-theme | auto, light, dark | auto follows the visitor's system setting. |
data-size | normal, compact, invisible | invisible shows only a small badge. |
data-start | auto, focus, click | When the check starts: on page load, when the visitor first uses the form, or when they click the box. |
data-lang | auto, en, ar, es, de, fr, pt, tr | auto uses the page's language. |
data-compat | recaptcha, turnstile | Also fills the other service's field name. |
data-callback, data-expired-callback, data-error-callback | function names | Called with the token, when it expires, or with an error code. |
JavaScript: captchabox.render(element, options), captchabox.getResponse(), captchabox.reset(), and await captchabox.execute(), which gives you a token for forms sent with fetch.
Rules for tokens: each token works once and for 5 minutes. The widget gets a new one by itself before the old one expires. Always check the token on your server: the hidden field alone proves nothing.
Error codes from siteverify: missing-input-secret, invalid-input-secret, missing-input-response, invalid-input-response, timeout-or-duplicate.
Test keys work on any domain, including localhost, and are not counted: site key cb_test_pass with secret cbs_test_pass always passes, and cb_test_fail with cbs_test_fail always fails at siteverify.
Pricing
Every plan has the same widget, the same privacy and the same code. A check is one visitor who passed the captcha; the count starts again on the 1st of each month (UTC).
| Plan | Checks a month | Sites | Price |
|---|---|---|---|
| Free | 10,000 | up to 10 | $0 |
| Plus | 100,000 | unlimited | $2 a month |
| Pro | 1,000,000 | unlimited | $9 a month |
| More | over 1,000,000 | unlimited | Ask us |
Start free, and upgrade in the client area when you need more: the higher limit works as soon as the invoice is paid, with no new keys. Plans are billed monthly. Plus ($2) is paid with PayPal; Pro ($9) with PayPal or crypto. Account credit works for both. Cancel any time and you go back to the free plan at the end of the month. You can see your usage in the client area. If an account goes more than 10% over its limit, new checks stop until the 1st of the next month.
What proof of work can and cannot do
CaptchaBox makes every form submission cost computing time, and makes repeated requests from one address much more expensive. That stops the cheap, high-volume spam most sites get. It cannot stop a determined attacker with lots of computers, and no captcha can stop a person typing spam by hand. Keep your usual checks too: rate limits, email confirmation, moderation.
CaptchaBox questions
Is CaptchaBox really free?
Yes, up to 10,000 checks a month per account. You only need a natbox account, not a server. If you need more, Plus is $2 a month for 100,000 checks and Pro is $9 a month for 1,000,000.
Does it set cookies or need a cookie banner?
No. The widget sets no cookies and uses no local storage. We do not store visitor IP addresses: they are kept in memory for at most 10 minutes for rate limits, then forgotten. See the privacy policy.
Will it slow down my page?
The script is about 19 KB and loads after your page. The work runs in background threads, so the page stays responsive. On a phone it usually takes about one second.
Does it work with WordPress, Laravel or other frameworks?
Anything that has an HTML form and a server can use it: add the two lines of HTML and the server check above. Because the API answers like reCAPTCHA's, existing reCAPTCHA code can usually be switched by changing the script URL, the verify URL and the field name (or use data-compat="recaptcha").
What happens if your service is down?
The widget shows "Could not reach the captcha service" and a Try again button, and your server check fails. If you would rather accept forms in that case, treat a failed connection to siteverify as a pass in your code and moderate those messages. Our uptime is on the status page.
Is it accessible?
There is nothing to see or hear, so it works with screen readers and keyboards. The status is announced to screen readers.
CaptchaBox is made by natbox, a small hosting company. If you need a server for your site, natbox runs small Linux servers from $1.00 a month. See our plans.