Website analytics
Website analytics is off by default. When enabled, the package records a lightweight, privacy-first page visit for each request: no cookies, no fingerprinting, no consent banner.
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.
Keeping bots out of your numbers
Bot traffic is filtered server-side, before a visit is ever recorded: CrawlerDetect, extra bot patterns, a client-hints consistency check that catches a request claiming to be Chrome while its headers say otherwise, and a minimum human-probability score (default 70). That runs on every request and needs nothing added to your pages.
For the automation those signals believe, there is an optional beacon:
RANETRACE_WEBSITE_ANALYTICS_BEACON_ENABLED=true
The beacon rides the @ranetraceErrorTracking directive you already have in your layout, and sends back one opaque token per visit, so only the visits a real, visible browser actually rendered are counted. Nothing about the visitor is collected or stored: the token says a browser rendered the page and nothing else.
Two things to know before you turn it on. It writes through the queue, so the beacon needs a real queue driver rather than sync. And it must stay off on pages served from a full-page cache, where every visitor would receive the same token.
Whether you run the beacon or not, Ranetrace's traffic pages say how many visits were kept out, so a quiet day and a filtered day never look the same.
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.