Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Visitor Fingerprint Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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.

Implementation Patterns

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.

Gotchas and Tips

  • It is a heuristic, not an identity. NAT/corporate proxies collapse many users into one fingerprint; browser auto-updates and mobile UA churn split one user into many. Never use it for authorization, "remember this device", or anything security-sensitive.
  • Privacy exposure is real. IP addresses are personal data under GDPR/CCPA. Hash with an app-key-derived salt (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.
  • Proxy configuration silently poisons the hash. If 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.
  • Too many attributes = unstable fingerprint. If every header is in the hash, fingerprints rotate on each request and dedupe never fires. Keep the attribute set small and documented in config.
  • No request in CLI/queue contexts. Guard the resolver: if (!app()->runningInConsole()) or null-check the attribute before using it in jobs and commands.
  • Config cache. After editing the attribute list or model binding, run php artisan config:clear — cached config means your change appears to do nothing.
  • Publishing after upgrades. vendor:publish skips existing files; use --force deliberately, and diff before overwriting config or migrations you've customized.
  • Debugging. Log the exact attribute array before hashing (once, locally) rather than guessing why a fingerprint differs between two requests; dump the middleware's output in tinker with a crafted Request.
  • 1.0.5 is a patch release with no documented changes. Treat it as a bugfix bump: no breaking API changes expected, but re-publish/compare config and migration stubs, re-run migrate, and re-run your suite if you extended internal classes or overrode the middleware.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mydnic/volet-feature-board-filament-plugin
wmde/email-address
refinery29/test-util
dees040/laravel-api-responses
teamzac/geocoder
ideatica/config-writer
keaton-php/pipe-dream
jacksonwebservices/laravel-user-suite
maksimru/conditional-laravel-debugbar
gismatul/nova-support-chat
gismatul/laravel-support-chat
networkrailbusinesssystems/oracle-api
alphabalex/messaging-made-easy
rawphp/warp
shootkiran/merobug
narakode/fineauth
numencode/wn-syncops-plugin
ibnnajjaar/mib-global-pay
refinery29/php-cs-fixer-config
parsnick/steak