mlk9/captcha-laravel
A lightweight CAPTCHA package for Laravel that adds customizable image or math challenges to your forms. Generate and validate captchas with Blade helpers, validation rules, and config options to protect your app from spam and automated bot submissions.
Install and publish
composer require <vendor>/<package>:^3.1
php artisan vendor:publish --provider="<Vendor>\<Package>\<PackageServiceProvider>"
If the package ships migrations/assets, publish those tags too. For the new Math Captcha driver you typically do not need image/GD assets or third-party API keys.
Configure the driver
Start in config/captcha.php (or the package’s equivalent). Look for the driver/type key and set it to the math option added in v3.1.1:
'driver' => env('CAPTCHA_DRIVER', 'math'),
Keep the default as your existing driver and override per form where possible.
First use case: protect a public form without external dependencies Add the captcha to a contact or login form:
<form method="POST" action="/contact">
@csrf
@captcha('math') {{-- or the package’s Blade directive/component --}}
<button>Send</button>
</form>
Validate server-side:
$request->validate([
'captcha' => ['required', 'captcha'],
]);
Where to look first
config/captcha.php — driver names, options, session key, route middleware.Driver-per-form Keep the image/service driver for high-risk forms and use math for low-friction forms:
// config/captcha.php
'driver' => 'recaptcha',
// In a form request or controller
$request->validate([
'captcha' => ['required', 'captcha:math'],
]);
Confirm in the README whether the driver is selected via rule parameter, config override, or a separate Blade directive. Do not assume both approaches exist.
Form Request encapsulation
class ContactRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email'],
'message' => ['required', 'string'],
'captcha' => ['required', 'captcha:math'],
];
}
public function messages(): array
{
return [
'captcha.captcha' => 'Please solve the math question correctly.',
];
}
}
Blade usage Prefer the package directive/component over hand-writing hidden inputs. Math captchas usually render a question and an input; the package handles the signed/session-backed answer. If you need custom markup, inspect the rendered HTML in devtools and reuse the package’s field names and session keys rather than guessing.
AJAX/SPA refresh Math captchas are session-backed and usually one-time. For SPAs, expose or reuse the package’s refresh endpoint so a failed submission can request a new question:
await fetch('/captcha/refresh', { headers: { 'X-Requested-With': 'XMLHttpRequest' } })
.then(r => r.json())
.then(({ question, html }) => { /* replace captcha container */ });
If the package does not ship a refresh route, add a small controller that calls the driver’s regenerate method.
Combine with layered defenses Math captcha is a low-friction bot deterrent, not a complete anti-spam solution. Pair it with:
throttle middleware on the routeTesting
Configure a bypass driver in phpunit.xml or config/captcha.php under the testing environment:
<env name="CAPTCHA_DRIVER" value="null"/>
If the package provides a fake, use it:
Captcha::fake();
For tests that intentionally exercise the math driver, submit a known answer by reading the session value or by using the package’s testing helper.
Localization and accessibility Math captchas are generally more accessible than image-only captchas, but still:
lang/vendor/<package>/...).redis, database, file) and that the route has the web middleware group. The array driver will break validation across requests.php artisan config:clear
A cached config is the most common reason a new driver “doesn’t work.”math-captcha vs math will usually fall back silently to the default driver.@csrf and route throttle middleware in place.^3.1 and scan the changelog before jumping minors. Run your form/validation tests after upgrading, especially if you override the validation rule or Blade directive.How can I help you explore Laravel packages today?