aryehraber/statamic-captcha
An addon for Statamic that adds CAPTCHA protection to forms, helping block spam and automated submissions. It offers simple configuration and server-side validation, making it easy to secure contact and other Statamic forms.
composer require aryehraber/statamic-captcha, then publish the config: php artisan vendor:publish --tag=statamic-captcha-config (fall back to --provider="AryehRaber\Captcha\ServiceProvider" if the tag misses). You get config/statamic/captcha.php, which is the single source of truth for the default provider, per-provider credentials, render attributes, and verify URLs.
Set the provider and keys in .env rather than editing config: the file maps a provider key to a providers array (hcaptcha, recaptcha, recaptcha_v3, turnstile, and as of v1.18.0 fcaptcha). Copy the exact env var names out of the published stub — new providers get their own key/secret pair, so don't assume FCAPTCHA_KEY/FCAPTCHA_SECRET without checking.
First use case: open the template for one Statamic form (resources/views/forms/contact.antlers.html or whatever form:create renders) and drop the tag inside the form:
{{ form:create in="contact" }}
<input type="email" name="email">
{{ captcha }}
<button type="submit">Send</button>
{{ /form:create }}
Submit it. Verification happens through Statamic's form submission lifecycle, so a failure surfaces in the normal error bag — render it with {{ errors:captcha }} next to the tag.
Where to look first when something misbehaves: config/statamic/captcha.php (provider + verify URL), the addon's src/ provider classes (how each provider posts the token and parses the response), then the published views if you need to control markup.
{{ captcha }} in templates and switch CAPTCHA_PROVIDER per environment. Use the providers' documented always-pass test keys in local/staging rather than conditioning the tag out — conditional rendering is what causes "works on my machine, fails in prod" bugs.resources/views/partials/captcha.antlers.html so you have one place to add theme, lang, size, color, custom id/class, and your own fallback copy. Every form then includes the partial instead of repeating attributes.form:create (registration, password reset, contact-form-in-a-Blade-view): drop the same tag into the Antlers user form templates and confirm the submission event actually triggers verification — the integration point is Statamic's form events, so anything that bypasses those events bypasses the captcha.Http:: with the configured verify_url) and validate the returned success flag plus hostname/action for v3.phpunit.xml set the captcha env to a test-key configuration, and Http::fake() the verify URL with a canned success/failure body so submission tests are deterministic and CI never calls a third party.{{ if errors:captcha }} block adjacent to the widget and scroll/focus it on failure.form:create when rolling this out.fcaptcha block in v1.18.0), run php artisan config:clear. A stale cached config with no fcaptcha entry produces a null secret and a generic verification failure.config/statamic/captcha.php against the package stub and merge the new provider block by hand; don't blindly re-publish over your customisations.{{ captcha }} a unique id; duplicate DOM ids break the provider scripts, and some providers only initialise the first element they find.verify_url rather than code changes — that's also the lever if you need to point at an alternate host.script-src and frame-src entries for whichever provider you enable, or the widget silently fails to render.providers array is the abstraction: a new provider (as with FCaptcha in v1.18.0) is config keys plus a verify call. If you need a service that isn't supported, model it on the closest existing provider's config shape rather than forking the package.How can I help you explore Laravel packages today?