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

Visitlog Laravel Package

sarfraznawaz2005/visitlog

Laravel package for logging and analyzing website visits. It records page views with visitor details like IP, browser, OS, device, referrer, and country, supports route exclusions via middleware, and helps track unique visitors, online users, and traffic stats.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require sarfraznawaz2005/visitlog (v6 requires Laravel 13 — see Gotchas if you're still on 10/11/12).

  • Publish and run the migration, then publish the config so you can see what's actually being recorded:

    php artisan vendor:publish --provider="Sarfraznawaz2005\VisitLog\VisitLogServiceProvider"
    php artisan migrate
    
  • Look at config/visitlog.php first. It controls whether logging is enabled, the table name, and which paths are excluded. Most "why isn't it logging / why is it logging too much" questions are answered there.

  • Register the middleware on the web group. On Laravel 11+/13 that's bootstrap/app.php:

    ->withMiddleware(function (Middleware $middleware) {
        $middleware->web(append: [
            \Sarfraznawaz2005\VisitLog\Middleware\VisitLog::class,
        ]);
    })
    

    On older skeletons it went into the web array in app/Http/Kernel.php.

  • First use case: browse a page, then confirm a row landed:

    use Sarfraznawaz2005\VisitLog\Models\VisitLog;
    
    VisitLog::latest()->first();
    

    If that returns a row with IP, URL, user agent and timestamps, you're wired up correctly and can move on to querying it.

Implementation Patterns

Global vs. selective tracking. Appending to the web group logs every browser request on the site — the right default for a marketing site or blog. For an app where you only care about a few pages, register it as a route middleware alias and attach it to specific route groups instead, so you don't write rows for every Livewire poll and asset request.

Capture user_id. The middleware runs inside the web group, so auth()->id() is available when it's appended (i.e. after StartSession/Authenticate). If you register it earlier or globally, you'll silently log null users — a common cause of "all my visits are anonymous."

Build your own read layer. Don't scatter VisitLog:: calls through controllers. Create a small VisitLogRepository or dedicated AnalyticsController with the queries you actually need:

VisitLog::query()
    ->whereBetween('created_at', [$from, $to])
    ->selectRaw('DATE(created_at) as day, COUNT(*) as visits')
    ->groupBy('day')
    ->orderBy('day')
    ->get();

Because the package stores denormalized columns (browser, OS, country, referrer), most reporting is plain groupBy work — no joins required.

Custom model for domain logic. If you need relations (user(), scopes like scopeHuman(), accessors), extend the package model rather than editing vendor code, and point your app at your subclass:

class Visit extends \Sarfraznawaz2005\VisitLog\Models\VisitLog
{
    protected $table = 'visit_logs';

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function scopeHuman($q)
    {
        return $q->where('browser', '!=', 'Unknown');
    }
}

Defer the write. The middleware writes synchronously on the request path. For high-traffic apps, either narrow the middleware to a subset of routes or dispatch a queued job from a terminate()-style listener so the insert happens after the response is flushed.

Retention as a scheduled task. Visit logs grow monotonically. Add a command and schedule it:

VisitLog::where('created_at', '<', now()->subDays(90))->delete();

Delete in chunks (->chunkById(1000, ...)) once the table is large, and make sure created_at is indexed (add your own migration if the published one doesn't).

Testing. Flip visitlog.enabled to false in phpunit.xml so your test suite doesn't write rows through every feature test, then override it per-test when you're asserting logging behaviour.

Gotchas and Tips

  • This is a major version bump for framework support only. 6.0.0 adds Laravel 13 compatibility; the public API and config surface are unchanged. Treat it as a dependency-hygiene upgrade, not a feature release — but the major number implies the constraint floor moved, so expect Laravel 10 and possibly 11 to be dropped. Run composer why-not sarfraznawaz2005/visitlog 6.0.0 before upgrading to see exactly what's blocking you.
  • Don't re-publish over existing files. vendor:publish will happily overwrite your edited config/visitlog.php. On upgrade, diff the package's config against yours rather than blindly republishing, and if you've already published migrations, leave them alone — check the package's migrations/ directory for new columns and write your own additive migration instead.
  • Config caching bites here. After changing enabled, the table name, or the exclusion list, run php artisan config:cache (or config:clear) — otherwise your changes appear to do nothing in production only.
  • Volume is the number one operational problem. One row per request, with a user-agent string, will bloat the table quickly. Exclude health checks, /horizon, /telescope, sitemaps and any JSON/API endpoints via the exclusion config, and prune on a schedule from day one.
  • Real client IPs require TrustProxies. Behind a load balancer or Cloudflare, the logged IP will be your proxy's unless you configure trusted proxies in bootstrap/app.php. This invalidates any geo or unique-visitor numbers you derive.
  • Bots inflate every metric. The package records what it's given; filter on user agent (or add a scopeHuman) in your reporting rather than expecting the middleware to do it.
  • Privacy obligations are yours. Storing IP addresses and user agents is personal data under GDPR/CCPA. Decide on anonymization (hash or truncate the IP before/after insert) and a documented retention window, and mention it in your privacy policy — the package won't do it for you.
  • Extension points are the config, the model and the middleware. If you need conditional logging (e.g. skip logged-in admins, skip tenants), write a thin middleware that checks your condition and then delegates to the package middleware — cheaper than forking it and keeps upgrades painless.
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.
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk