Do you need a CAPTCHA on a small website?
Decide whether a public form needs a puzzle, what a honeypot and a rate limit already cover, and when to add a real bot check.
You published a site on Webflow, Lovable, or a static host. The contact form stores messages. The next suggestion is often “add a CAPTCHA.”
Look at the live form first. If it posts to a public URL, you need protection. A puzzle is only one way to do that.
Start from the submit path
A brochure with no form can wait. Spam starts when someone can send you data.
Contact pages, waiting lists, newsletter fields, job applications, and testimonial forms all count. So does a quote form.
If the control only shows “Thanks” in the browser and stores nothing, spam is not your problem yet. Connect a backend first. Follow the static contact form guide if that is the gap.
If the message is stored, anything can POST to the same endpoint. Bots do not need to see the page.
A hidden field catches a lot of junk
A honeypot is an extra input that people never fill. You hide it with CSS, skip it in the tab order, and mark it hidden from screen readers. Bots that fill every field give it a value. The server drops that submit and still shows success.
<form method="post" action="/contact">
<label>
Email
<input type="email" name="email" required>
</label>
<label>
Message
<textarea name="message" required></textarea>
</label>
<p style="position:absolute;left:-9999px" aria-hidden="true">
<label>
Company website
<input type="text" name="company_url" tabindex="-1" autocomplete="off">
</label>
</p>
<button type="submit">Send</button>
</form>
If company_url has any value, ignore the rest of the body. Do not tell the sender which field was the trap.
A per-visitor rate limit sits next to that. The same client cannot submit in a tight loop.
Those two layers never show a challenge. They also do not load a Google script.
Add a bot check before you share the URL
Honeypots fail against better bots. Share the page widely only after a real check is in place.
Google reCAPTCHA is the common paste. It loads a Google script on your page. If you skipped Google Analytics to keep Google tags off the site, this puts one back.
Cloudflare Turnstile is a CAPTCHA alternative. It is free. The check is mostly invisible. You create a widget for your domain in the Cloudflare dashboard. Paste the site key and secret key into your form backend.
Sitebase forms already include the honeypot and the per-visitor rate limit. Honeypot hits are dropped silently. Turnstile is a separate switch on the website Config tab. One toggle applies it to every form on that site: contact, waiting list, newsletter, careers, and custom forms.
Sitebase is in private beta. Public signup isn’t open.
Cloudflare’s test keys render the widget and always pass. Use them while you wire the form. Replace them with keys for the public hostname before you send traffic. Cloudflare binds a widget to hostnames, so a preview domain and the live domain need different widgets.
Hosted embed pages run on sitebase.dev. Those use Sitebase’s own Turnstile keys. Your domain keys apply when the script snippet renders the form on your site.
If the check fails, the visitor should see an error and be able to retry. That is different from the honeypot, which looks like success.
Name Turnstile in the privacy policy if you turn it on. A copied template that only lists reCAPTCHA is wrong.
You can wire the same layers on your own endpoint. Drop honeypot hits. Verify the token on the server. Keep the secret key off the page.
Submit it yourself on the live URL
Open the published page in a fresh window, not the preview.
Send a message with an address you control. Confirm that it arrives in storage. Confirm that an empty required field shows an error.
If Turnstile is still on test keys, the check will pass. That does not prove bots are blocked.
Then walk the other checks in the launch checklist.