Configuration, translations and events

The package works without any configuration. Change a setting in .env, or publish the config file to config/livewire-honeypot.php:

php artisan vendor:publish --tag=livewire-honeypot-config

Which settings are there

Option Env variable Default Description
field_name HONEYPOT_FIELD_NAME hp_website Plain forms only. The key their errors are reported under, and the key HoneypotService::validate() reads the bait from when a form renders its own inputs. <x-honeypot /> renders a generated name instead. Livewire forms always use hp_website
maximum_fill_seconds HONEYPOT_MAXIMUM_FILL_SECONDS 86400 Plain forms older than this are rejected as expired; 0 turns expiry off. Livewire forms never expire
minimum_fill_seconds HONEYPOT_MINIMUM_FILL_SECONDS 5 Minimum seconds between loading and submitting; 0 turns the time check off. The bait check stays on
token_length HONEYPOT_TOKEN_LENGTH 24 Length of the random part of a generated token, at least 1

A changed .env value has no effect while the config is cached. Run php artisan config:clear, or php artisan config:cache again on the server.

token_min_length was removed in 1.4.0. It is ignored when a published config still contains it.

Changing the messages

English, Dutch, German, French and Spanish are included. Laravel picks the language from the application locale. To change a text, publish the files:

php artisan vendor:publish --tag=livewire-honeypot-translations

They land in lang/vendor/livewire-honeypot/{locale}/validation.php.

Key English text Used for
spam_detected Spam detected. The bait was filled or missing, or the start time or token is invalid
submitted_too_quickly Form submitted too quickly. The form was submitted within minimum_fill_seconds
form_expired This form has expired. Please try again. A plain form was older than maximum_fill_seconds
honeypot_label Leave this field empty Label of the hidden field. Avoid words like “website” or “email”, which trigger browser autofill

Content Security Policy

A Content Security Policy (CSP) is a response header that tells the browser which styles and scripts it may run. By default the bait field is hidden with an inline style attribute. A policy without 'unsafe-inline' in style-src blocks that attribute, and the field becomes visible.

When a nonce is available, <x-honeypot /> hides the field through a <style nonce="..."> block instead. A nonce is a random value that your CSP header allows for one response. The component takes it from Laravel’s Vite integration:

use Illuminate\Support\Facades\Vite;

// In your CSP middleware
Vite::useCspNonce();

Or pass a nonce yourself through the nonce attribute. With spatie/laravel-csp 3, the nonce is app('csp-nonce'):

<x-honeypot :nonce="app('csp-nonce')" />

The class name and the style block are the same on every render, so a Livewire update never replaces the style block. Render the form with the page itself, not lazily: a Livewire update request can carry a different nonce than the page’s policy.

Changing the HTML

php artisan vendor:publish --tag=livewire-honeypot-views

The view lands in resources/views/vendor/livewire-honeypot/components/honeypot.blade.php.

A published view no longer gets fixes from package updates. After an update, compare it with resources/views/components/honeypot.blade.php in the package. Since 1.4.0 the view only holds markup; the values it uses ($inLivewire, $token, $baitName, $errorBagKey, $cspNonce, $hiddenClass, $hiddenCss) come from Darvis\LivewireHoneypot\View\Components\Honeypot. Publish it again if you published it before 1.4.0.

Logging blocked submissions

Darvis\LivewireHoneypot\Events\SpamBlocked is dispatched right before a submission is rejected. An event is a message other code in your application can listen for.

Property Value
reason SpamBlocked::FIELD_FILLED (field_filled), SUBMITTED_TOO_QUICKLY (submitted_too_quickly), INVALID_PAYLOAD (invalid_payload) or EXPIRED (expired)
ip IP address of the request, or null
component Class name of the Livewire component, or null for a plain form

app/Providers/AppServiceProvider.php:

use Darvis\LivewireHoneypot\Events\SpamBlocked;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;

public function boot(): void
{
    Event::listen(function (SpamBlocked $event) {
        Log::info('Honeypot blocked a submission', [
            'reason' => $event->reason,
            'ip' => $event->ip,
            'component' => $event->component,
        ]);
    });
}

Every blocked submission now adds a line to your default log, storage/logs/laravel.log in a new application. The package itself writes nothing to the log.

Many submitted_too_quickly lines from different visitors can mean that minimum_fill_seconds is too high for a short form. Many field_filled lines that look human point to autofill; see Troubleshooting.