How to Add Cloudflare Turnstile to Laravel in 5 Minutes (No Packages Required)
If you’ve built a public-facing web app, you eventually run into the same annoying problem: bots. They fill out your forms, spam your inbox, and waste your server’s time. Most developers immediately think of Google reCAPTCHA, but there’s a cleaner option that solves the same problem without the tracking baggage: **Cloudflare Turnstile**. Turnstile is Cloudflare’s privacy-friendly CAPTCHA alternative. * ❌ No user friction. * 🚍 No weird “click the traffic lights” puzzles. (ehem.. Google) * ⏲️ And setup takes only a few minutes. In this quick guide, I’ll show you why you should use Turnstile — and how to integrate it into a Laravel app without any third-party packages. ## Why use Cloudflare Turnstile? Here are the biggest reasons I migrated to it: **1. No user frustration** Turnstile doesn’t make users solve puzzles. It verifies silently in the background unless something looks suspicious. **2. Privacy-respecting** Unlike reCAPTCHA, Turnstile doesn’t track users across the web. No profiling, no annoying consent banners. **3. Dead simple to implement** It’s literally: * Load a script * Place a widget * Verify the token server-side Done! **4. Completely free** Cloudflare offers Turnstile with unlimited usage on the free plan. ### Step 1 — Create a Turnstile Widget in Cloudflare 1. Log in to Cloudflare 2. Application Security → Turnstile 3. Click **Add Widget** 4. Set: * Name: e.g: my-domain-name-turnstile * Add Hostnames: If you already have existing hostnames setup in Cloudflare you can select it, or you can just type your domain name manually. You can also add your local domains here - very useful if you are using Herd on your local machine. * Widget Mode: Managed (recommended) * Would you like to opt for pre-clearance for this site?: Just select "No" 5. Copy your **Site Key** and **Secret Key** ### Step 2 — Add the Keys, Widget and Script into Laravel Add these to your `.env` file ``` # Cloudflare Turnstile Captcha TURNSTILE_ENABLED=true # This will be so that you can just disable it quickly, especially on your tests TURNSTILE_URL=https://challenges.cloudflare.com/turnstile/v0/siteverify TURNSTILE_SITE_KEY=Your-Turnstile-Site-Key TURNSTILE_SECRET_KEY=Your-Turnstile-Secret-Key ``` Then, configure these values on your `config/services.php` file ``` // On services.php 'turnstile' => [ 'enabled' => env('TURNSTILE_ENABLED', false), 'turnstile_url' => env('TURNSTILE_URL'), 'site_key' => env('TURNSTILE_SITE_KEY'), 'secret_key' => env('TURNSTILE_SECRET_KEY'), ], ``` Then add the Widget into your Blade template — this usually goes into public facing forms such as registration, forgot password, contact us, etc. ``` ``` Then add their script outside the body of your base template ``` ``` ### Step 3 — Create a Rule class and use it on your form validations This sample rule class below provides a way to ignore `required` validation on the Turnstile field if the `config('services.turnstile.enabled')` is set to `false`. ```