Open source July 2026
Laracaptcha

Laracaptcha

Laracaptcha

Laracaptcha is a driver-based captcha for Laravel. One API for Cloudflare Turnstile and Google reCAPTCHA v2/v3: you switch providers by changing one env variable, with no code changes.

Installation

composer require edulazaro/laracaptcha

Set your driver and keys in .env:

CAPTCHA_DRIVER=turnstile

TURNSTILE_KEY=0x4AAA...
TURNSTILE_SECRET=0x4AAA...

# Or for reCAPTCHA (v2 / v3):
# CAPTCHA_DRIVER=recaptcha_v2
# RECAPTCHA_KEY=...
# RECAPTCHA_SECRET=...

Optionally publish the config:

php artisan vendor:publish --tag=laracaptcha-config

In a form

Drop the widget component inside any form. It renders the right markup and loads the provider script for the configured driver:

<form method="POST" action="/register">
    @csrf
    ...
    <x-laracaptcha::widget />
    <button type="submit">Register</button>
</form>

For reCAPTCHA v3 the widget is invisible and tokens are generated on submit. You can tag the action:

<x-laracaptcha::widget action="register" />

Validating the token

The token field name depends on the provider (cf-turnstile-response for Turnstile, g-recaptcha-response for reCAPTCHA) so get it dynamically rather than hardcoding it:

use EduLazaro\Laracaptcha\Rules\Captcha;
use EduLazaro\Laracaptcha\Facades\Captcha as CaptchaFacade;

$request->validate([
    CaptchaFacade::responseField() => ['required', new Captcha],
]);

The rule includes replay protection: a token that already passed once is rejected. Configurable through prevent_reuse and reuse_ttl.

Verifying manually

use EduLazaro\Laracaptcha\Facades\Captcha;

$result = Captcha::verify($token, $request->ip());

$result->success;    // bool
$result->score;      // float|null (reCAPTCHA v3)
$result->errorCodes; // array

To use a specific driver regardless of the default:

Captcha::driver('recaptcha_v3')->verify($token);

Testing

use EduLazaro\Laracaptcha\Facades\Captcha;

$fake = Captcha::fake();                 // all verifications pass
$fake = Captcha::fake(success: false);   // all verifications fail
$fake = Captcha::fake(score: 0.9);       // pass with a score

$fake->attempts(); // recorded [token, ip] pairs

No HTTP requests are made while faked.

Dev keys

Cloudflare publishes always-pass test keys for local development:

Sitekey 1x00000000000000000000AA
Secret 1x0000000000000000000000000000000AA

built and maintained by Edu Lazaro · MIT license