Website Analytics

Website analytics is off by default. When enabled, the package records a lightweight, privacy-first page visit for each request, with no cookies and no client-side script.

Turn it on in production

Website analytics has no code to add: the TrackPageVisit middleware is auto-registered on the web middleware group when analytics is enabled. Turn it on in your production environment, not just a local .env:

RANETRACE_ENABLED=true
RANETRACE_WEBSITE_ANALYTICS_ENABLED=true

To try it during development, set the same flags in your local .env.

Privacy model

Analytics is privacy-first by design: no cookies, no fingerprinting, no cross-site tracking. Visitors are identified only by salted, one-way HMAC hashes that never leave your data:

  • user_agent_hash: the user agent, hashed.
  • session_id_hash: a daily-rotating session identifier, hashed.

Raw identifiers are never stored, and the hashes are never shared across sites.

What each visit captures

  • Path, referrer, and UTM parameters (source, medium, campaign, term, content).
  • Device type (mobile, tablet, desktop) and browser.
  • A human-probability score and country code.

Bot traffic is filtered with CrawlerDetect plus extra bot patterns and the human-probability score, so automated hits do not pollute your numbers.

Configuration

From config/ranetrace.php:

RANETRACE_WEBSITE_ANALYTICS_ENABLED=true
RANETRACE_WEBSITE_ANALYTICS_THROTTLE_SECONDS=30

Excluded paths

Publish the config to skip paths you do not want tracked. Excluded paths match the first URL segment, so adding admin excludes every /admin/* route:

// config/ranetrace.php
'website_analytics' => [
    'excluded_paths' => [
        'horizon', 'nova', 'telescope', 'admin', 'filament',
        'api', 'debugbar', 'storage', 'livewire',
        // add your own paths
    ],
],

Custom request filter

For filtering logic beyond a path list, implement the RequestFilter contract and register it in the published config:

use Illuminate\Http\Request;
use Ranetrace\Laravel\Analytics\Contracts\RequestFilter;

class InternalTrafficFilter implements RequestFilter
{
    public function shouldSkip(Request $request): bool
    {
        return (bool) $request->header('X-Internal-Client');
    }
}
// config/ranetrace.php
'request_filter' => \App\Analytics\InternalTrafficFilter::class,

Testing your setup

php artisan ranetrace:test-analytics

Disabling

RANETRACE_WEBSITE_ANALYTICS_ENABLED=false

With the feature off, the middleware records nothing.