rattler/honeypot-bundle
A Symfony bundle that adds honeypot spam protection to forms without CAPTCHAs. Hidden fields and timing checks help flag bot submissions while keeping legitimate users friction-free. Lightweight, configurable, and easy to integrate into existing form workflows.
Before anything else: this is a Symfony bundle, not a Laravel package. There is no service provider, no config/honeypot.php, and no facade. composer require rattler/honeypot-bundle in a Laravel app will pull it in but give you nothing wired up — the bundle's HoneypotBundle class expects Symfony's Kernel/Bundle registration and the Symfony Form component. Treat this as a reference implementation of the honeypot technique, not a dependency.
// app/Rules/Honeypot.php
class Honeypot implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (filled($value)) {
$fail('Submission rejected.');
}
}
}
{{-- resources/views/contact.blade.php --}}
<div aria-hidden="true" style="position:absolute;left:-9999px;top:-9999px;">
<label for="website">Website</label>
<input type="text" name="website" id="website" tabindex="-1" autocomplete="off">
</div>
$request->validate([
'email' => ['required', 'email'],
'website' => [new Honeypot], // the honeypot field
]);
That gets you 90% of what the bundle does, in ~15 lines, with no abandoned dependency.
The bundle encodes three patterns worth understanding, whether or not you run any of its code.
1. Hidden-field honeypot. A form field that is hidden via CSS (not type="hidden") is filled by naive bots that parse the HTML and populate every input. Humans never see it, so any value in it means "bot." The bundle registers this field automatically on forms via a form type extension — convenient in Symfony, irrelevant in Laravel where you control the Blade template directly.
2. Validation-constraint rejection. The bundle ships a constraint that fails validation when the honeypot field is populated. In Laravel this maps cleanly to a custom rule (above) or a FormRequest withValidator hook. Prefer the rule — it composes with the rest of $request->validate().
3. Time-trap (adjacent pattern, not in the bundle but commonly paired). Bots submit instantly; humans take seconds. Stamp a signed timestamp into the form and reject submissions under ~2 seconds. In Laravel:
// On render: <input type="hidden" name="ts" value="{{ encrypt(now()->timestamp) }}">
$started = decrypt($request->input('ts'));
abort_if(now()->timestamp - $started < 2, 422);
Integration tips for a Laravel app:
config/honeypot.php) so you can rotate it when bots learn it.position:absolute; left:-9999px plus aria-hidden="true" and tabindex="-1" — never display:none alone, since some sophisticated bots skip non-rendered inputs.honeypot or _trap. Use something plausible (website, company, fax) so bots fill it.Bundle class, DependencyInjection/, form type extensions, service tagging — has no direct Laravel equivalent. You cannot "just install it." Budget for a rewrite, not an integration.autocomplete="off" and monitor rejection rates — a sudden spike means real users are being blocked.display:none is invisible to screen readers and to many bots — defeating the purpose. aria-hidden="true" + off-screen positioning is the safer combination. Never required a honeypot field; a human can't fill it.RateLimiter::attempt) + a real captcha only on suspicious traffic.abort(). When the client asks "why did my form fail," you'll want the evidence. Add a Log::info('honeypot_reject', [...]) line inside the rule.config:cache in a way that ties the name to a deploy. Rotation should not require a full cache clear.How can I help you explore Laravel packages today?