Vlozi Forms protects every form with three layers of spam defense. They run in order, from cheapest to most expensive:
Honeypot check → Rate limit → Turnstile (if enabled)Layer 1 — Honeypot field
A hidden field that humans never fill in, but bots always do. It's always active — no configuration needed.
How it works
Every form has a honeypotField (default name: botcheck). The field is included in your HTML but hidden from human visitors:
<input type="checkbox" name="botcheck" style="display:none" tabindex="-1" autocomplete="off" />If the field is filled in during submission, the service stores the submission as status=spam and returns 200 { success: true } — silently. Bots never learn they were caught.
Changing the honeypot field name
You can customise the honeypot field name per form (dashboard → Settings → Spam protection → Honeypot field name). Use this if your own form already has a botcheck field for legitimate purposes.
WARNING
Do not set the honeypot field name to the same name as one of your real fields. Every submission with a filled-in version of that field would be silently marked as spam.
Layer 2 — IP-based rate limiting
Every form automatically rate-limits submissions: 20 requests per 60 seconds per IP address. This cap applies even if the honeypot or CAPTCHA is not triggered.
If the limit is exceeded, the server returns 429 Too many requests. This is the correct behavior for high-volume bot attacks.
The rate limit is per-form-per-IP, so one user hitting your contact form quickly does not affect another user submitting a different form.
Layer 3 — Cloudflare Turnstile CAPTCHA
Turnstile is an opt-in CAPTCHA that is invisible to most users (Cloudflare classifies traffic automatically) and only shows a challenge to suspicious requests.
Setup
You need two keys from your Cloudflare dashboard:
| Key | Used by | Where to configure |
|---|---|---|
| Site key (public) | The browser widget | Form settings → Turnstile site key |
| Secret key (private) | Server-side verification | Vlozi platform settings (shared across all forms) |
Once both are set, enable CAPTCHA per form: dashboard → Forms → your form → Settings → enable CAPTCHA.
How it works
- When
embed.jsrenders your form, it detectscaptchaRequired=trueand loads the Turnstile widget from Cloudflare - The visitor solves the challenge (usually invisible — Cloudflare handles it)
- The widget injects a
cf-turnstile-responsetoken into the submission - Vlozi verifies the token with Cloudflare's siteverify API before accepting the submission
- Invalid or missing tokens return
400 Captcha verification failed— the submission is rejected and stored as spam
IMPORTANT
CAPTCHA requires both the site key (configured in the form) and the secret key (configured at the platform level). If only one is set, CAPTCHA protection will not work correctly. Check the dashboard Settings if submissions are failing with a 400 error and you have CAPTCHA enabled.
Plain HTML forms and CAPTCHA
If you use a plain HTML form (no embed.js), you must add the Turnstile widget yourself:
<form action="https://api.vlozi.app/forms/f/YOUR_FORM_ID" method="POST">
<!-- your fields -->
<!-- Load Turnstile -->
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
<button type="submit">Send</button>
</form>Turnstile injects cf-turnstile-response into the form submission automatically.
Spam submissions in the dashboard
All spam submissions — honeypot trips and CAPTCHA failures — are stored in the database with status=spam and a spamReason (honeypot or captcha). They are never billed (credits are only charged on legitimate submissions).
View them in the dashboard: Forms → your form → Submissions → filter by Spam.
Defense summary
| Defense | When active | Blocks |
|---|---|---|
| Honeypot field | Always | Simple bots that auto-fill all fields |
| Rate limiting | Always | High-volume submission floods |
| Turnstile CAPTCHA | When enabled | Sophisticated bots that avoid honeypots |
allowed_origins CORS |
When configured | Cross-origin requests from unlisted domains |