https://github.com/ghdj/laravel-visitor-tracker
A Laravel package for visitor tracking with analytics, geolocation, and bot detection - zero external dependencies
https://github.com/ghdj/laravel-visitor-tracker
analytics bot-detection gdpr laravel privacy statistics visitor-tracking zero-dependency
Last synced: about 1 month ago
JSON representation
A Laravel package for visitor tracking with analytics, geolocation, and bot detection - zero external dependencies
- Host: GitHub
- URL: https://github.com/ghdj/laravel-visitor-tracker
- Owner: GhDj
- License: mit
- Created: 2026-01-25T02:44:45.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-04-28T12:02:29.000Z (about 2 months ago)
- Last Synced: 2026-05-11T13:59:28.443Z (about 1 month ago)
- Topics: analytics, bot-detection, gdpr, laravel, privacy, statistics, visitor-tracking, zero-dependency
- Language: PHP
- Homepage:
- Size: 79.1 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Laravel Visitor Tracker
[](https://github.com/ghdj/laravel-visitor-tracker/actions/workflows/tests.yml)
[](https://packagist.org/packages/ghdj/laravel-visitor-tracker)
[](https://packagist.org/packages/ghdj/laravel-visitor-tracker)
A comprehensive visitor tracking package for Laravel applications with analytics, geolocation, and bot detection.
**🚀 Zero External Dependencies** - Uses only Laravel's built-in features and native PHP for all functionality.
## Features
- 📊 **Comprehensive Tracking** - Track page views, unique visitors, and sessions
- 🤖 **Native Bot Detection** - Detect 100+ bots/crawlers without external packages
- 📱 **Native Device Detection** - Identify browsers, platforms, and device types using regex
- 🌍 **Geolocation** - Optional IP-based location tracking (using Laravel's HTTP client)
- 🔒 **GDPR Compliant** - GDPR Safe Mode for consent-free tracking, IP anonymization, DNT support
- ⚡ **Performance** - Queue support for async tracking, statistics caching
- 📈 **Rich Statistics** - Browser, platform, device, country, referrer analytics
- 🎯 **Flexible Exclusions** - Exclude paths, IPs, user agents, status codes
- 🔧 **Zero Dependencies** - Only uses Laravel's illuminate packages
## Requirements
- PHP 8.1+
- Laravel 10.x, 11.x, or 12.x
## Installation
```bash
composer require ghdj/laravel-visitor-tracker
```
Publish the configuration file:
```bash
php artisan vendor:publish --tag="visitor-tracker-config"
```
Run the migrations:
```bash
php artisan migrate
```
## Configuration
The configuration file is located at `config/visitor-tracker.php`. Key options include:
```php
return [
// Enable/disable tracking globally
'enabled' => env('VISITOR_TRACKER_ENABLED', true),
// Paths to exclude from tracking
'exclude' => [
'paths' => ['api/*', 'admin/*'],
'methods' => ['OPTIONS', 'HEAD'],
'status_codes' => [301, 302, 404, 500],
'ips' => [],
'user_agents' => [],
],
// Bot tracking
'bots' => [
'track' => false,
'detect' => true,
'additional_patterns' => [], // Add custom bot patterns
],
// Custom parser patterns
'parser' => [
'additional_browsers' => [], // Add custom browser patterns
'additional_platforms' => [], // Add custom platform patterns
],
// Geolocation (optional - uses Laravel HTTP client)
'geolocation' => [
'enabled' => env('VISITOR_TRACKER_GEOLOCATION', false),
'provider' => 'ip-api', // ip-api (free), ipinfo, ipapi
],
// GDPR compliance
'privacy' => [
'gdpr_safe_mode' => env('VISITOR_TRACKER_GDPR_SAFE', false),
'anonymize_ip' => env('VISITOR_TRACKER_ANONYMIZE_IP', false),
'respect_dnt' => true,
],
// Data retention
'retention' => [
'days' => 90,
],
// Queue for async tracking
'queue' => [
'enabled' => env('VISITOR_TRACKER_QUEUE', false),
],
];
```
## Usage
### Middleware
Add the tracking middleware to your routes:
```php
// In routes/web.php
Route::middleware(['track-visitor'])->group(function () {
Route::get('/', [HomeController::class, 'index']);
// ... more routes
});
// Or globally in bootstrap/app.php (Laravel 11)
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\Ghdj\VisitorTracker\Middleware\TrackVisitor::class,
]);
})
```
### Using the Facade
```php
use Ghdj\VisitorTracker\Facades\VisitorTracker;
// Get statistics
$stats = VisitorTracker::stats();
// Total visitors (unique)
$totalVisitors = $stats->totalVisitors();
// Total page views
$totalPageViews = $stats->totalPageViews();
// Currently online visitors
$onlineNow = $stats->onlineVisitors();
// Today's visitors
$todayVisitors = $stats->todayVisitors();
// Visitors in last N days
$weeklyVisitors = $stats->visitorsLastDays(7);
// Most visited pages
$topPages = $stats->mostVisitedPages(10);
// Top referrers
$topReferrers = $stats->topReferrers(10);
// Browser statistics
$browsers = $stats->browserStats();
// Platform/OS statistics
$platforms = $stats->platformStats();
// Device type statistics
$devices = $stats->deviceStats();
// Country statistics (requires geolocation)
$countries = $stats->countryStats();
// Summary of all stats
$summary = $stats->summary();
```
### Using the Helper Function
```php
// Get tracker instance
$tracker = visitor();
// Get statistics
$stats = visitor()->stats()->summary();
$online = visitor_stats()->onlineVisitors();
```
### Blade Directives
```blade
Total Visitors: @totalVisitors
Total Page Views: @totalPageViews
Online Now: @onlineVisitors
Today's Visitors: @todayVisitors
```
### Working with Models
```php
use Ghdj\VisitorTracker\Models\Visitor;
use Ghdj\VisitorTracker\Models\Visit;
// Get all visitors
$visitors = Visitor::all();
// Get online visitors
$online = Visitor::online()->get();
// Get visitors excluding bots
$humans = Visitor::excludeBots()->get();
// Get authenticated visitors only
$authenticated = Visitor::authenticated()->get();
// Get visitors from date range
$recent = Visitor::between(now()->subWeek(), now())->get();
// Get visits for a specific path
$homeVisits = Visit::path('/')->get();
// Get visits with referrers
$referred = Visit::withReferrer()->get();
```
### Using Native Services Directly
```php
use Ghdj\VisitorTracker\Services\UserAgentParser;
use Ghdj\VisitorTracker\Services\BotDetector;
// Parse user agent
$parser = new UserAgentParser();
$result = $parser->parse($request->userAgent());
// Returns: ['browser' => 'Chrome', 'browser_version' => '120.0', 'platform' => 'Windows', ...]
// Detect bots
$detector = new BotDetector();
$isBot = $detector->isBot($request->userAgent());
$botName = $detector->getBotName($request->userAgent());
$category = $detector->getBotCategory($request->userAgent()); // search_engine, social_media, ai_bot, etc.
```
### Adding Custom Patterns
```php
// Add custom browser detection
$parser = new UserAgentParser();
$parser->addBrowserPatterns([
'MyCustomBrowser' => '/MyCustomBrowser\/([0-9.]+)/',
]);
// Add custom bot detection
$detector = new BotDetector();
$detector->addPatterns(['mycustombot', 'anotherbot']);
$detector->addBotNames(['mycustombot' => 'My Custom Bot']);
// Or via config
// config/visitor-tracker.php
'parser' => [
'additional_browsers' => [
'MyBrowser' => '/MyBrowser\/([0-9.]+)/',
],
],
'bots' => [
'additional_patterns' => ['mycustombot'],
],
```
### Listening to Events
```php
use Ghdj\VisitorTracker\Events\VisitorTracked;
// In EventServiceProvider or using Event facade
Event::listen(VisitorTracked::class, function (VisitorTracked $event) {
$visitor = $event->visitor;
$visit = $event->visit;
// Custom logic here
logger("New visit from {$visitor->ip} to {$visit->path}");
});
```
### Artisan Commands
```bash
# Show visitor statistics
php artisan visitor-tracker:stats
php artisan visitor-tracker:stats --detailed
# Prune old data
php artisan visitor-tracker:prune
php artisan visitor-tracker:prune --days=30
php artisan visitor-tracker:prune --force
```
### Scheduling Data Pruning
Add to your `routes/console.php` or scheduler:
```php
use Illuminate\Support\Facades\Schedule;
Schedule::command('visitor-tracker:prune --force')->daily();
```
## Behind a Reverse Proxy / CDN
If your app sits behind Cloudflare, AWS ALB, nginx, or any other reverse proxy,
you **must** configure Laravel's `TrustProxies` middleware **before** enabling
visitor tracking. Without it, every request will appear to come from the proxy's
IP address — breaking IP exclusions, geolocation accuracy, and IP anonymization.
For Laravel 11/12, in `bootstrap/app.php`:
```php
->withMiddleware(function (Middleware $middleware) {
$middleware->trustProxies(at: '*'); // Or a specific list of proxy IPs
})
```
For Laravel 10, see `app/Http/Middleware/TrustProxies.php`.
> **Tip:** trust only the proxies you actually own. Setting `at: '*'` accepts
> any `X-Forwarded-For` header, which is fine when only your proxy can reach
> the app, but unsafe if the app is also directly accessible.
## Dashboard Authentication
> **Security:** When `dashboard.enabled` is `true`, the package will refuse to
> boot unless at least one of `dashboard.token`, `dashboard.gate`, or an `auth*`
> entry in `dashboard.middleware` is configured. The check is auto-skipped in
> the `testing` environment so your test suite can exercise the controller
> directly. To bypass it intentionally elsewhere (e.g. you front the dashboard
> with a network-level access control), set
> `visitor-tracker.dashboard.allow_unprotected = true`.
The dashboard is **always protected**. Choose an authentication method based on your site:
### Option 1: Token Authentication (Sites Without Login)
For sites without user authentication, use a secret token:
```env
# Add to your .env file (NEVER commit this!)
VISITOR_TRACKER_TOKEN=your-secret-token-here
```
Enable the dashboard in `config/visitor-tracker.php`:
```php
'dashboard' => [
'enabled' => true,
'token' => env('VISITOR_TRACKER_TOKEN'),
'middleware' => ['web'], // No 'auth' needed
],
```
Access the dashboard via:
- **URL**: `/admin/visitor-tracker?token=your-secret-token-here`
- **Header**: `X-Visitor-Tracker-Token: your-secret-token-here`
- **Bearer**: `Authorization: Bearer your-secret-token-here`
### Option 2: Laravel Auth (Sites With Login)
For sites with user authentication:
```php
'dashboard' => [
'enabled' => true,
'middleware' => ['web', 'auth'],
],
```
### Option 3: Gate Authorization (Role-Based Access)
For admin-only access with Laravel Gates:
```php
// In AuthServiceProvider
Gate::define('view-visitor-stats', function ($user) {
return $user->is_admin;
});
// In config/visitor-tracker.php
'dashboard' => [
'enabled' => true,
'middleware' => ['web', 'auth'],
'gate' => 'view-visitor-stats',
],
```
## Geolocation Providers
All providers use Laravel's built-in HTTP client - no external packages required.
### ip-api.com (Free, No API Key)
```env
VISITOR_TRACKER_GEOLOCATION=true
VISITOR_TRACKER_GEO_PROVIDER=ip-api
```
### ipinfo.io
```env
VISITOR_TRACKER_GEOLOCATION=true
VISITOR_TRACKER_GEO_PROVIDER=ipinfo
VISITOR_TRACKER_GEO_API_KEY=your_api_key
```
## Queue Support
For high-traffic sites, enable queue processing:
```env
VISITOR_TRACKER_QUEUE=true
VISITOR_TRACKER_QUEUE_CONNECTION=redis
VISITOR_TRACKER_QUEUE_NAME=tracking
```
## GDPR Safe Mode
To track **anonymous aggregate statistics without requiring user consent**, enable GDPR Safe Mode:
```env
VISITOR_TRACKER_GDPR_SAFE=true
```
When enabled, the following personal data is **NOT collected**:
| Data | Status | Notes |
|------|--------|-------|
| IP Address | ❌ Not stored | Not even anonymized |
| User ID | ❌ Not stored | No link to authenticated users |
| Persistent Cookie | ❌ Not used | Session-only identification |
| Full User Agent | ❌ Not stored | Only parsed for aggregate stats |
| City / Region | ❌ Not stored | Only country-level location |
| Coordinates | ❌ Not stored | No lat/long |
> **Note on session fallback:** GDPR Safe Mode identifies visitors by Laravel's
> session ID (which lives in a session cookie that expires when the browser closes
> if you set `SESSION_LIFETIME` accordingly). If the request has no session
> available at all, the tracker falls back to a daily hash of the User-Agent
> string for aggregate counting only — this is not individually identifying but
> does group same-UA requests within a single calendar day. To get the strongest
> guarantees, ensure your tracked routes go through the `web` middleware group.
**What IS still collected** (anonymous, aggregate data):
| Data | Purpose |
|------|---------|
| Page view counts | Traffic analytics |
| Browser name | Chrome, Firefox, etc. |
| Platform name | Windows, macOS, etc. |
| Device type | Mobile, desktop, tablet |
| Country | Broad geographic distribution |
| Referrer domain | Traffic sources |
```php
// Check if GDPR safe mode is enabled
if (VisitorTracker::isGdprSafeMode()) {
// No personal data being collected
}
```
## Detected Browsers
Chrome, Firefox, Safari, Edge, Opera, Brave, Vivaldi, Samsung Browser, UC Browser, Yandex, IE, and more.
## Detected Platforms
Windows (XP through 11), macOS, iOS, Android, Linux, Ubuntu, Chrome OS, FreeBSD.
## Detected Bots
100+ bot patterns including:
- **Search Engines**: Google, Bing, Yahoo, DuckDuckGo, Baidu, Yandex
- **Social Media**: Facebook, Twitter, LinkedIn, Pinterest, Slack, Discord
- **AI/LLM**: GPTBot, ClaudeBot, Anthropic, CCBot, Perplexity
- **SEO Tools**: Ahrefs, SEMrush, Moz, Majestic
- **Monitoring**: UptimeRobot, Pingdom, DataDog, New Relic
- **HTTP Clients**: cURL, Wget, Python Requests, Postman, Axios
## Testing
```bash
composer test
```
## Code Quality
```bash
# Run code style fixer
composer format
# Run static analysis
composer analyse
```
## Why Zero Dependencies?
- **Smaller footprint** - No additional packages to install or maintain
- **Better performance** - Native regex is fast and efficient
- **Full control** - Easily extend patterns via configuration
- **Security** - Less attack surface, no supply chain concerns
- **Reliability** - Only depends on Laravel core packages
## Changelog
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
The MIT License (MIT). Please see [License File](LICENSE) for more information.