captchaapi/laravel
Official Laravel SDK for captchaapi.eu (EU-hosted, GDPR-friendly proof-of-work CAPTCHA). Includes Blade widget/component, server-side verification + validation rule, and optional Livewire 4 support. PHP 8.2+, Laravel 12/13.
Installation:
composer require captchaapi/laravel
php artisan vendor:publish --tag=captchaapi-config
Add credentials to .env:
CAPTCHAAPI_SITE_KEY=pk_live_...
CAPTCHAAPI_SECRET_KEY=sk_live_...
First Use Case (HTML Form):
<head>:
<x-captchaapi::widget />
data-captcha:
<form method="POST" data-captcha>
@csrf
<!-- form fields -->
</form>
$request->validate([
'captchaapi_response' => ['required', 'captcha'],
]);
First Use Case (Livewire):
WithCaptcha trait in your Livewire component:
use Captchaapi\Laravel\Concerns\WithCaptcha;
class MyComponent extends Component {
use WithCaptcha;
public function submit() {
$this->validateWithCaptcha(['field' => 'required']);
// Proceed...
}
}
<x-captchaapi::livewire-form action="submit">
<!-- form fields -->
</x-captchaapi::livewire-form>
Form Submission Workflow:
data-captcha on the <form> and validate with the captcha rule.validateWithCaptcha() in your component method and the livewire-form wrapper in your view.<x-captchaapi::error /> or manually with @error('captchaapi_response').Dynamic Form Integration:
CAPTCHAAPI_PRELOAD=eager in .env to preload the widget on page load.Multi-Step Forms:
validateWithCaptcha() in each step’s submission method. The captchaapi_response is automatically included in the validation.Conditional CAPTCHA:
if (!$shouldUseCaptcha) {
$request->validateWithoutCaptcha(['field' => 'required']);
}
Livewire Integration:
<x-captchaapi::livewire-form> instead of plain <form> to ensure proper event handling.rulesForCaptcha() to manually compose validation rules:
$this->validate(array_merge($rules, $this->rulesForCaptcha()));
Status Feedback:
<div data-captcha-status></div>
Configuration:
CAPTCHAAPI_TIMEOUT for slower networks or CAPTCHAAPI_FAIL_OPEN for sensitive actions (e.g., logins).CAPTCHAAPI_LOCALE to enforce a specific language for the widget.Testing:
FakeCaptchaapi::enable() in tests to bypass real API calls:
use Captchaapi\Laravel\Testing\FakeCaptchaapi;
beforeEach(function () {
FakeCaptchaapi::enable();
});
FakeCaptchaapi::enforceSingleUse();
Missing Widget Script:
<x-captchaapi::widget /> in your layout will cause the CAPTCHA to fail silently. Always include it in the <head> of layouts where forms are used.Livewire Event Mode:
data-captcha-mode="event" is set by using <x-captchaapi::livewire-form>. Manual forms with data-captcha will use submit mode, which may not work with Livewire’s event-driven flow.Secret Key Exposure:
CAPTCHAAPI_SECRET_KEY in client-side code. The package is designed to keep it server-side only.Double Validation in Fortify:
FakeCaptchaapi::enforceSingleUse() in tests to simulate this behavior and avoid false positives.Status Element Overrides:
data-captcha-no-color, ensure you distinguish between waiting and ready states visually, as they share the same icon by default.Validation Errors:
ValidCaptcha fails unexpectedly, check:
captchaapi_response field name in your form..env keys (CAPTCHAAPI_SITE_KEY and CAPTCHAAPI_SECRET_KEY).CAPTCHAAPI_ENABLED flag (set to false disables validation silently).Livewire Debugging:
dd($this->rulesForCaptcha()) to inspect the generated CAPTCHA rules.API Issues:
CAPTCHAAPI_FAIL_OPEN=false to block submissions during outages. Monitor logs for timeout errors.Status Element Not Updating:
<div data-captcha-status> is a direct child of the form or nearby in the DOM. The widget only styles elements with this attribute.Custom Validation Logic:
ValidCaptcha rule by creating a custom rule class:
use Captchaapi\Laravel\Rules\ValidCaptcha as BaseValidCaptcha;
class CustomValidCaptcha extends BaseValidCaptcha {
public function passes($attribute, $value) {
// Custom logic
return parent::passes($attribute, $value);
}
}
$request->validate([
'captchaapi_response' => ['required', new CustomValidCaptcha],
]);
Custom Status Styling:
data-captcha-state attribute:
[data-captcha-status][data-captcha-state="ready"] {
background-color: #d1fae5;
}
Testing Extensions:
FakeCaptchaapi:
FakeCaptchaapi::fake([
'response' => 'valid_token_123',
]);
Dynamic Configuration:
$this->app->singleton('config', function ($app) {
return array_merge(
require __DIR__.'/../config/captchaapi.php',
['timeout' => 10] // Override timeout
);
});
CAPTCHAAPI_PRELOAD:
eager to load the CAPTCHA widget immediately on page load (useful for single-page applications). Default (lazy) waits for form interaction.CAPTCHAAPI_DEBUG:
true) to log timing breakdowns in the browser console for debugging performance issues.CAPTCHAAPI_MODE:
submit or event if you need to override the default behavior (e.g., for custom form handlers). Defaults to null (auto-detects based on context).Locale Fallback:
<html lang> attribute if CAPTCHAAPI_LOCALE is not set. Ensure your app’s locale is correctly configured.How can I help you explore Laravel packages today?