Bot Protection
Protect your forms from bots using Cloudflare Turnstile captcha.
Formlander integrates with Cloudflare Turnstile, a privacy-friendly CAPTCHA alternative, to protect forms from bot submissions.
Cloudflare Turnstile Setup
Section titled “Cloudflare Turnstile Setup”1. Get Turnstile Keys
Section titled “1. Get Turnstile Keys”Sign up and get your keys from the Cloudflare Turnstile dashboard:
- Site Key (public) - Embedded in your HTML
- Secret Key (private) - Stored in Formlander’s database
2. Configure in Formlander Admin
Section titled “2. Configure in Formlander Admin”- Log into your Formlander dashboard
- Navigate to Settings → Captcha Profiles
- Click Create New Profile
- Enter a profile name (e.g., “Production Captcha”)
- Enter your Turnstile Site Key and Secret Key
- Save the profile
Note: Turnstile credentials are stored securely in the database and managed through the admin interface, not environment variables.
3. Assign Captcha to Forms
Section titled “3. Assign Captcha to Forms”- Go to Forms in the admin dashboard
- Edit or create a form
- Select your Captcha Profile from the dropdown
- Save the form
4. Add Turnstile Widget to Your HTML
Section titled “4. Add Turnstile Widget to Your HTML”Include the Turnstile widget in your form:
<form action="https://your-domain.com/forms/contact/submit?token=YOUR_TOKEN" method="post"> <!-- Your form fields --> <label> Name <input type="text" name="name" required> </label>
<label> Email <input type="email" name="email" required> </label>
<label> Message <textarea name="message" required></textarea> </label>
<!-- Cloudflare Turnstile widget --> <div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
<button type="submit">Send</button></form>
<!-- Load Turnstile script --><script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>Replace YOUR_SITE_KEY with your actual Turnstile Site Key.
5. Validation
Section titled “5. Validation”Formlander automatically validates the Turnstile token server-side before accepting submissions. If validation fails:
{ "ok": false, "error": "captcha validation failed"}Turnstile Modes
Section titled “Turnstile Modes”Cloudflare offers three challenge modes:
| Mode | Description | User Experience |
|---|---|---|
| Managed | Shows CAPTCHA only when needed based on risk | ✅ Recommended - Minimal friction |
| Non-interactive | Invisible challenge runs in background | Zero friction, but may not catch all bots |
| Always visible | Traditional CAPTCHA every time | Maximum security, more friction |
Configure the mode in your Cloudflare Turnstile settings.
Multi-Domain Support
Section titled “Multi-Domain Support”Formlander supports multiple Captcha Profiles, allowing you to:
- Use different Turnstile keys for different domains
- Have separate configurations for staging vs. production
- Assign specific profiles to specific forms
Example setup:
-
Profile: “Production Forms”
- Site Key:
1x00000000000000000000AA - Assigned to: Contact Form, Newsletter Form
- Site Key:
-
Profile: “Staging Environment”
- Site Key:
1x00000000000000000000BB - Assigned to: Test Forms
- Site Key:
React Example
Section titled “React Example”For single-page applications, use the Turnstile React component:
import { Turnstile } from '@marsidev/react-turnstile'
function ContactForm() { const [token, setToken] = useState('')
const handleSubmit = async (e) => { e.preventDefault()
const formData = new FormData(e.target) formData.append('cf-turnstile-response', token)
const response = await fetch('https://your-domain.com/forms/contact/submit?token=YOUR_TOKEN', { method: 'POST', body: formData, })
// Handle response... }
return ( <form onSubmit={handleSubmit}> <input name="name" required /> <input name="email" type="email" required /> <textarea name="message" required />
<Turnstile siteKey="YOUR_SITE_KEY" onSuccess={setToken} />
<button type="submit">Send</button> </form> )}Monitoring Bot Protection
Section titled “Monitoring Bot Protection”Formlander logs all failed captcha attempts in structured logs under storage/logs/:
{ "level": "warn", "ts": "2025-11-07T14:30:00Z", "msg": "submission blocked: captcha validation failed", "form_slug": "contact", "ip_hash": "abc123...", "reason": "captcha_failed"}Monitor these logs to:
- Identify bot attack patterns
- Adjust Turnstile sensitivity if needed
- Detect false positives
Best Practices
Section titled “Best Practices”- Start with Managed Mode - Balances security and user experience
- Use multi-domain profiles - Separate production from staging/testing
- Monitor false positives - Watch for legitimate users getting blocked
- Combine with rate limiting - Captcha alone won’t stop all abuse (see Abuse Prevention)
- Test thoroughly - Verify captcha works before deploying
Troubleshooting
Section titled “Troubleshooting””Captcha validation failed” errors
Section titled “”Captcha validation failed” errors”- ✅ Verify Site Key matches your Cloudflare dashboard
- ✅ Confirm Secret Key is correctly saved in Formlander
- ✅ Check that the captcha profile is assigned to the form
- ✅ Ensure Turnstile script is loaded (
<script src="...">)
Widget not appearing
Section titled “Widget not appearing”- ✅ Check browser console for JavaScript errors
- ✅ Verify Site Key is correct in your HTML
- ✅ Ensure Turnstile script is loaded before form renders
- ✅ Check for CSP (Content Security Policy) blocking Cloudflare
High false positive rate
Section titled “High false positive rate”- Switch from “Always visible” to “Managed” mode
- Review Cloudflare Turnstile settings for sensitivity
- Consider allowing users to retry failed challenges