laravel-web-analytics maintained by nafiur
Laravel Web Analytics
A modern, fast, and self-hosted Web Traffic & Visitor Analytics Dashboard for Laravel with real-time Server-Sent Events (SSE) live streaming and Tailwind CSS styling.
⚡ Highlights & Key Features
- 🚀 Real-Time Live Stream (SSE): Live active visitor count and instant real-time traffic feed without WebSockets, Node.js, or Pusher.
- 🎨 Tailwind CSS UI with Dark Mode: Modern, responsive dashboard powered by Tailwind CSS Play CDN (zero build step / zero npm dependencies). Includes a 1-click persistent Dark/Light mode toggle.
- 📊 Comprehensive Metrics: Total Requests, Unique Visitors, Bandwidth (Data Transferred), Avg Response Time, Error Rate.
- 🌍 GeoIP & Location Provider: Automatic country/city resolution with fallback support for Cloudflare headers and
ip-api. - 🚨 Instant Error Alerts: Automatic Telegram, Slack, or Discord webhook alerts when 5xx server errors or traffic spikes occur.
- 📥 Export to CSV: Download filtered analytics logs into structured CSV format via high-performance chunked streams.
- 🧹 Automatic Log Pruning: Includes an Artisan command (
php artisan lwa:prune) to maintain a clean database and prevent disk bloat. - ⚡ Zero Latency Impact: Non-blocking telemetry tracking using Laravel's
terminate()hook, recording traffic after the HTTP response has been sent to the user. - 🗄️ Lightweight & Decoupled Storage: Stores telemetry in the
lwa_logstable without coupling to any specific User model, with GDPR-compliant IP anonymization options.
📋 Requirements
- PHP
^8.1 | ^8.2 | ^8.3 | ^8.4 - Laravel
^9.0 | ^10.0 | ^11.0 | ^12.0 | ^13.0
📦 Installation
Install the package via Composer:
composer require nafiur/laravel-web-analytics
Publish configuration, migration, and views:
php artisan vendor:publish --provider="Nafiur\WebAnalytics\WebAnalyticsServiceProvider"
Or publish selectively:
# Publish configuration
php artisan vendor:publish --tag=laravel-web-analytics-config
# Publish migrations
php artisan vendor:publish --tag=web-analytics-migrations
# Publish views (optional, to customize dashboard UI)
php artisan vendor:publish --tag=web-analytics-views
Run database migrations to create the lwa_logs table:
php artisan migrate
🚀 Setup & Middleware Registration
To start capturing web traffic, register the TrackWebTraffic middleware.
For Laravel 11 and Laravel 12 (bootstrap/app.php):
use Nafiur\WebAnalytics\Http\Middleware\TrackWebTraffic;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
TrackWebTraffic::class,
]);
})
->create();
For Laravel 9 and Laravel 10 (app/Http/Kernel.php):
Add the middleware to the $middlewareGroups['web'] array:
protected $middlewareGroups = [
'web' => [
// ... other middlewares
\Nafiur\WebAnalytics\Http\Middleware\TrackWebTraffic::class,
],
];
🖥️ Accessing the Dashboard
Navigate to:
https://your-domain.com/web-analytics
By default, the dashboard is protected by the ['web', 'auth'] middleware stack. You can adjust the route prefix and authorization rules in config/laravel-web-analytics.php.
Route Names
The package defines routes with the lwa_ prefix to avoid conflicts with your application routes:
| Route | Name | Description |
|---|---|---|
GET /web-analytics |
lwa_dashboard |
Main analytics dashboard (alias: lwa_index) |
GET /web-analytics/data |
lwa_data |
AJAX endpoint for real-time data |
GET /web-analytics/stream |
lwa_stream |
SSE stream for live traffic |
GET /web-analytics/export |
lwa_export |
Export analytics to CSV |
Generate URLs in your Blade templates or code:
route('lwa_dashboard', ['range' => '24h']);
route('lwa_data', ['range' => '24h']);
route('lwa_stream');
route('lwa_export', ['range' => '24h']);
⚙️ Configuration (config/laravel-web-analytics.php)
return [
/*
* Enable or disable traffic tracking globally
*/
'enabled' => env('WEB_ANALYTICS_ENABLED', true),
/*
* Database table name for storing web analytics logs
*/
'table_name' => env('WEB_ANALYTICS_TABLE_NAME', 'lwa_logs'),
/*
* Route configurations for the Analytics Dashboard
*/
'route' => [
'prefix' => env('WEB_ANALYTICS_ROUTE_PREFIX', 'web-analytics'),
'middleware' => ['web', 'auth'],
],
/*
* Real-time SSE polling interval in seconds
*/
'stream_interval' => env('WEB_ANALYTICS_STREAM_INTERVAL', 2),
/*
* Active visitor calculation window in minutes
*/
'active_visitor_window' => env('WEB_ANALYTICS_ACTIVE_WINDOW', 5),
/*
* Capture Settings (Web & API)
*/
'capture' => [
'web' => true,
'api' => env('WEB_ANALYTICS_CAPTURE_API', true),
'ajax' => true,
'bots' => env('WEB_ANALYTICS_CAPTURE_BOTS', false),
],
/*
* GeoIP & Location Provider
*/
'geoip' => [
'enabled' => env('WEB_ANALYTICS_GEOIP_ENABLED', true),
'provider' => env('WEB_ANALYTICS_GEOIP_PROVIDER', 'cloudflare'), // 'cloudflare', 'ip-api'
'maxmind_db_path' => env('WEB_ANALYTICS_MAXMIND_DB', storage_path('app/GeoLite2-City.mmdb')),
],
/*
* Alert Notifications (Spikes & 5xx Server Errors)
*/
'alerts' => [
'enabled' => env('WEB_ANALYTICS_ALERTS_ENABLED', false),
'webhook_url' => env('WEB_ANALYTICS_ALERT_WEBHOOK', null),
'channel' => env('WEB_ANALYTICS_ALERT_CHANNEL', 'telegram'), // 'telegram', 'slack', 'discord'
'telegram_bot_token' => env('WEB_ANALYTICS_TELEGRAM_BOT_TOKEN', null),
'telegram_chat_id' => env('WEB_ANALYTICS_TELEGRAM_CHAT_ID', null),
'error_rate_threshold_percentage' => env('WEB_ANALYTICS_ERROR_THRESHOLD', 10),
],
/*
* Exclude specific URL paths and file extensions from being tracked
*/
'ignored_paths' => [
'livewire/*',
'broadcasting/auth',
'admin/web-analytics*',
'*.css',
'*.js',
'*.png',
'*.jpg',
'*.jpeg',
'*.gif',
'*.svg',
'*.webp',
'*.woff*',
'*.ico',
],
/*
* IP Anonymization for privacy compliance (GDPR)
*/
'anonymize_ip' => env('WEB_ANALYTICS_ANONYMIZE_IP', false),
/*
* Number of days to retain logs
*/
'retention_days' => env('WEB_ANALYTICS_RETENTION_DAYS', 30),
];
🧹 Database Maintenance (Pruning)
To keep your database lean, run the included prune command:
# Prune logs older than configured retention days (default 30)
php artisan lwa:prune
# Or specify custom days
php artisan lwa:prune --days=14
Schedule it in your routes/console.php (Laravel 11+) or app/Console/Kernel.php:
use Illuminate\Support\Facades\Schedule;
Schedule::command('lwa:prune')->daily();
📥 Exporting Reports
Click the Export to CSV button on the dashboard or directly access:
GET /web-analytics/export?range=24h
Supported ranges: 1h, 6h, 24h, 7d, 30d.
🛡️ Security & Authorization
To restrict dashboard access to specific user roles or permissions, update config/laravel-web-analytics.php:
'route' => [
'prefix' => 'web-analytics',
'middleware' => ['web', 'auth', 'can:view-analytics'],
],
🤝 Contributing
Contributions, issues, and feature requests are welcome! Feel free to check the issues page.
📝 License
This project is licensed under the MIT License - see the LICENSE file for details.