jeffersongoncalves/laravel-visitor-fingerprint
A Laravel package for generating and managing visitor fingerprints, letting you recognize returning visitors and track unique sessions without relying only on cookies. Simple to install and integrate, with a clean API for storing fingerprint data and extending behavior in any Laravel app.
This package gives each visitor a stable, reproducible fingerprint derived from request attributes (user agent, IP, headers, language) so you can correlate anonymous traffic with a later authenticated user without depending on cookies alone.
Minimal setup:
composer require jeffersongoncalves/laravel-visitor-fingerprint
# Publish config (and migrations if you persist fingerprints)
php artisan vendor:publish --tag=visitor-fingerprint-config
php artisan vendor:publish --tag=visitor-fingerprint-migrations
php artisan migrate
The service provider is auto-discovered. Then attach the shipped middleware to the web group (site-wide capture) or to individual routes (surgical capture):
// bootstrap/app.php (Laravel 11+) or app/Http/Kernel.php
$middleware->web(append: [
\JeffersonGoncalves\VisitorFingerprint\Http\Middleware\VisitorFingerprint::class,
]);
Look first at: the published config file (it defines which attributes feed the hash, whether records are persisted, and the model/table names), then the middleware, then the model/migration. First use case: fingerprint marketing-page visits anonymously, then attach that fingerprint to the user on registration or login so you can attribute signups to a pre-auth browsing history.
Read the fingerprint in a controller or listener. The middleware resolves and binds the fingerprint early, so downstream code can just ask for it:
$fingerprint = request()->attributes->get('visitor_fingerprint');
// or the package's facade/helper, per the README
Attach on authentication. Use the Login / Registered events rather than stuffing logic into controllers:
Event::listen(Login::class, function (Login $event) {
$event->user->visitorFingerprints()->firstOrCreate([
'fingerprint' => request()->attributes->get('visitor_fingerprint'),
]);
});
Persist with upsert semantics, not blind inserts. A fingerprint per request will explode your table; either enable package-side dedupe or call updateOrCreate on a unique fingerprint index and bump last_seen_at / hits.
Use it as a rate-limit and abuse key. On api routes the fingerprint gives you a cookie-free throttle key:
RateLimiter::for('api-by-fingerprint', fn ($request) =>
Limit::perMinute(60)->by($request->attributes->get('visitor_fingerprint') ?: $request->ip())
);
Analytics queries. Group by fingerprint for unique-visitor counts, and join to your users pivot to answer "how many sessions before signup". Add a reporting-only index on (fingerprint, created_at).
Swap the generator for domain needs. Bind your own implementation of the package's generator contract (or set the class in config) when you need tenant-scoped or header-supplemented fingerprints, and keep the middleware untouched.
Testing. Use $this->withHeaders([...]) to drive deterministic fingerprints, and withoutMiddleware() where the fingerprint is irrelevant to the test at hand.
hash_hmac), keep raw IPs out of the table if you can, and document retention. Add a prune command or model Prunable so fingerprints age out.TrustProxies isn't configured, every visitor behind a load balancer hashes with the balancer's IP. Verify with $request->ip() versus the fingerprint attribute on a staging request.if (!app()->runningInConsole()) or null-check the attribute before using it in jobs and commands.php artisan config:clear — cached config means your change appears to do nothing.vendor:publish skips existing files; use --force deliberately, and diff before overwriting config or migrations you've customized.Request.migrate, and re-run your suite if you extended internal classes or overrode the middleware.How can I help you explore Laravel packages today?