# Analytics Platform - HOWTO Guide ## Table of Contents 1. [What is This Project?](#what-is-this-project) 2. [Features Overview](#features-overview) 3. [Architecture](#architecture) 4. [Installation](#installation) 5. [Configuration](#configuration) 6. [Required Background Tasks](#required-background-tasks) 7. [Tracking Setup](#tracking-setup) 8. [How It Works](#how-it-works) 9. [Database Structure](#database-structure) 10. [Artisan Commands](#artisan-commands) 11. [API Documentation](#api-documentation) 12. [Maintenance](#maintenance) --- ## What is This Project? This is a **self-hosted web analytics platform** built with Laravel 11. It provides privacy-focused website analytics similar to Google Analytics or Plausible, allowing you to track visitor behavior, conversions, and engagement on your websites without relying on third-party services. ### Key Capabilities - Real-time visitor tracking - Goal and conversion tracking - Custom event tracking - Funnel analysis - Automated alerts and notifications - Custom dashboards - Export analytics data - API access for integrations --- ## Features Overview ### 1. **Visitor Tracking** - Automatic page view tracking - Session management (30-minute timeout) - Device, browser, and OS detection - Geolocation (country, region, city) - Bot filtering - UTM parameter tracking (campaign, source, medium, etc.) - Time on page measurement ### 2. **Analytics Reports** - **Audience**: Geographic distribution, technology breakdown, languages - **Acquisition**: Traffic sources, referrers, campaigns - **Behavior**: Popular pages, landing pages, exit pages - **Events**: Custom event tracking with categories and labels - **Conversions**: Goal completions with revenue tracking ### 3. **Goals (4 Types)** - **URL Destination**: Track when users visit specific pages - **Event Match**: Track custom events - **Duration**: Sessions longer than X seconds - **Pages Per Session**: Sessions with X or more pages ### 4. **Advanced Features** - **Funnels**: Multi-step conversion tracking - **Segments**: Custom visitor segments for filtered reporting - **Alerts**: Automated notifications when metrics exceed thresholds - **Annotations**: Add notes to specific dates for context - **Custom Dashboards**: Drag-and-drop widget management ### 5. **Data Management** - Automatic daily aggregation for performance - Configurable data retention (default: 365 days) - CSV export - API access with token authentication --- ## Architecture ### Technology Stack - **Backend**: Laravel 11, PHP 8.2+ - **Frontend**: Blade templates, Alpine.js, Tailwind CSS - **Database**: SQLite (default), MySQL/PostgreSQL compatible - **Queue System**: Database-backed (Redis/SQS optional) - **Build Tool**: Vite ### Data Flow ``` Client Website (tracking script) ↓ POST /api/collect CollectController (validates & queues) ↓ Queue Job ProcessTrackingPayload (processes data) ↓ Stores in DB Raw Tables (visitors, sessions, page_views, events) ↓ Daily aggregation (02:00 AM) Aggregated Tables (daily_aggregates, page_daily_aggregates) ↓ Used by Dashboard & Reports (hybrid: aggregates + real-time) ``` --- ## Installation ### Development Setup ```bash # Clone the repository cd /path/to/analytics # Install dependencies and setup composer setup # This runs: # - composer install # - Creates .env from .env.example # - php artisan key:generate # - php artisan migrate --force # - npm install # - npm run build # Start development environment (runs 4 processes) composer run dev ``` This starts: - Web server: `http://localhost:8000` - Queue worker (processes tracking data) - Log viewer (Pail) - Vite dev server (hot module reload) ### Production Setup ```bash # Install dependencies composer install --no-dev --optimize-autoloader # Generate application key php artisan key:generate # Run database migrations php artisan migrate --force # Build frontend assets npm ci npm run build # Set proper permissions chmod -R 755 storage bootstrap/cache chown -R www-data:www-data storage bootstrap/cache ``` --- ## Configuration ### Environment Variables Copy `.env.example` to `.env` and configure: ```env # Application APP_NAME="Analytics Platform" APP_ENV=production APP_DEBUG=false APP_URL=https://yourdomain.com # Database DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=analytics DB_USERNAME=your_user DB_PASSWORD=your_password # Queue (use 'redis' for better performance) QUEUE_CONNECTION=database # Mail (for alerts and notifications) MAIL_MAILER=smtp MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_FROM_ADDRESS=noreply@yourdomain.com MAIL_FROM_NAME="${APP_NAME}" # Cache (use 'redis' for better performance) CACHE_STORE=database # Session SESSION_DRIVER=database SESSION_LIFETIME=120 ``` ### Web Server Configuration #### For Standard Setup (public/ folder) Point your web server document root to the `public/` directory. #### For Shared Hosting (engine/ + public_html/) If your hosting has separate folders: - `engine/` - Laravel application files - `public_html/` - Public web root **Modify `public_html/index.php`:** ```php usePublicPath(__DIR__); $app->handleRequest(Request::capture()); ``` --- ## Required Background Tasks ### 1. Queue Worker (CRITICAL) **Purpose**: Processes tracking data from websites Without this, tracking events are queued but never persisted to the database. ```bash # Start queue worker php artisan queue:work database --tries=3 --timeout=60 ``` **Production Setup**: Use a process supervisor **Using Supervisor** (recommended): ```ini # /etc/supervisor/conf.d/analytics-queue.conf [program:analytics-queue] process_name=%(program_name)s_%(process_num)02d command=php /path/to/analytics/artisan queue:work database --tries=3 --timeout=60 autostart=true autorestart=true stopasgroup=true killasgroup=true user=www-data numprocs=1 redirect_stderr=true stdout_logfile=/path/to/analytics/storage/logs/queue-worker.log stopwaitsecs=3600 ``` Then run: ```bash sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start analytics-queue:* ``` **Using systemd**: ```ini # /etc/systemd/system/analytics-queue.service [Unit] Description=Analytics Queue Worker After=network.target [Service] Type=simple User=www-data WorkingDirectory=/path/to/analytics ExecStart=/usr/bin/php /path/to/analytics/artisan queue:work database --tries=3 --timeout=60 Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ``` Enable and start: ```bash sudo systemctl enable analytics-queue sudo systemctl start analytics-queue ``` ### 2. Task Scheduler (CRITICAL) **Purpose**: Runs scheduled tasks (aggregation, purging, alerts) Add to crontab: ```bash # Edit crontab crontab -e # Add this line * * * * * cd /path/to/analytics && php artisan schedule:run >> /dev/null 2>&1 ``` This executes: - **Daily at 02:00 AM**: `analytics:aggregate` - Rolls up data into daily aggregates - **Daily at 03:00 AM**: `analytics:purge --force` - Deletes old raw data - **Every hour**: `analytics:check-alerts` - Evaluates alerts and sends notifications Without the scheduler: - Reports will be slower (no aggregated data) - Old data will accumulate and bloat the database - Alerts will never trigger --- ## Tracking Setup ### 1. Create a Website 1. Register/login to the analytics platform 2. Navigate to **Websites** → **Add Website** 3. Enter website name and domain 4. Copy the tracking ID (e.g., `abc123def456`) ### 2. Install Tracking Script Add this script to your website's HTML (before ``): **Option 1: JavaScript Snippet** ```html ``` **Option 2: Self-hosted Script** ```html ``` **Option 3: No-JavaScript Fallback** ```html ``` ### 3. Track Custom Events ```javascript // Track a custom event ta('event', 'button_click', { category: 'engagement', label: 'signup_button', value: 1 }); // Track a purchase ta('event', 'purchase', { category: 'ecommerce', value: 99.99 }); ``` ### 4. SPA Support For single-page applications (React, Vue, etc.), the tracker automatically detects route changes via `pushState` and `popstate`. You can also manually track page views: ```javascript // Manual page view tracking ta('pageview'); ``` --- ## How It Works ### Tracking Process 1. **Client-side**: Tracking script loads on visitor's browser 2. **Collection**: Script sends tracking data to `/api/collect` 3. **Validation**: `CollectController` validates tracking ID and domain 4. **Queueing**: Tracking payload is queued as `ProcessTrackingPayload` job 5. **Processing**: Queue worker picks up job and: - Creates/updates **Visitor** record (with geolocation) - Creates/retrieves **AnalyticsSession** (30-min timeout) - Records **PageView** or **Event** - Evaluates active **Goals** and records conversions - Updates session metrics (duration, bounce status) 6. **Aggregation**: Daily at 02:00 AM, raw data is rolled up into aggregates 7. **Reporting**: Dashboard queries combine aggregated + real-time data ### Session Logic - **Session Start**: First page view from a visitor - **Session Timeout**: 30 minutes of inactivity - **Session Duration**: Time between first and last page view - **Bounce**: Session with only 1 page view - **Exit Page**: Last page viewed in session ### Goal Evaluation Goals are evaluated in real-time during tracking: 1. **URL Destination**: Matches current page URL - Exact: URL must match exactly - Starts with: URL must start with pattern - Contains: URL must contain pattern - Regex: URL must match regex pattern 2. **Event Match**: Matches event name (and optionally category) 3. **Duration**: Session duration exceeds threshold 4. **Pages Per Session**: Page count exceeds threshold ### Data Aggregation Raw tracking data is aggregated daily to improve query performance: **Daily Aggregates** (per website, per day): - Total visitors (unique) - Total sessions - Total page views - Bounce count - Total session duration **Page Daily Aggregates** (per website, per page, per day): - Page views - Unique page views - Total time on page - Bounce count **Query Strategy**: - Historical dates: Query aggregated tables - Today: Query raw tables - Results are merged for complete picture --- ## Database Structure ### Core Tables | Table | Description | |-------|-------------| | `users` | User accounts | | `websites` | Tracked websites with settings | | `visitors` | Unique visitors with device/location info | | `analytics_sessions` | User sessions with UTM data | | `page_views` | Individual page visits | | `events` | Custom events with metadata | | `goals` | Conversion goal definitions | | `goal_conversions` | Goal completion records | | `funnels` | Funnel definitions | | `segments` | Custom visitor segments | | `alerts` | Alert rule definitions | | `alert_notifications` | Triggered alert records | | `annotations` | Date annotations | | `dashboard_widgets` | Custom dashboard layouts | | `daily_aggregates` | Pre-computed daily metrics | | `page_daily_aggregates` | Per-page daily metrics | ### Data Retention - **Raw Data**: Retained for 365 days (configurable per website) - **Aggregated Data**: Retained indefinitely - **Purge Schedule**: Daily at 03:00 AM via `analytics:purge` --- ## Artisan Commands ### Analytics Commands #### 1. Aggregate Data ```bash php artisan analytics:aggregate [options] Options: --date=YYYY-MM-DD Aggregate specific date (default: yesterday) --website=ID Aggregate specific website (default: all) # Examples php artisan analytics:aggregate php artisan analytics:aggregate --date=2026-03-20 php artisan analytics:aggregate --website=1 ``` **Important**: Cannot aggregate today's data (prevents incomplete aggregations) #### 2. Purge Old Data ```bash php artisan analytics:purge [options] Options: --website=ID Purge specific website (default: all) --force Skip confirmation prompt # Examples php artisan analytics:purge --force php artisan analytics:purge --website=1 ``` Deletes raw data older than retention period (default: 365 days). #### 3. Check Alerts ```bash php artisan analytics:check-alerts ``` Evaluates all active alerts and triggers notifications. ### Queue Commands ```bash # Process queue jobs php artisan queue:work database --tries=3 # List failed jobs php artisan queue:failed # Retry failed job php artisan queue:retry {job-id} # Retry all failed jobs php artisan queue:retry all # Flush failed jobs php artisan queue:flush ``` ### Cache Commands ```bash # Clear application cache php artisan cache:clear # Clear config cache php artisan config:clear # Clear route cache php artisan route:clear # Clear view cache php artisan view:clear # Cache config for production php artisan config:cache php artisan route:cache php artisan view:cache ``` --- ## API Documentation ### Authentication Generate API token in dashboard: **Profile** → **API Tokens** → **Create Token** Include in requests: ```bash Authorization: Bearer YOUR_API_TOKEN ``` ### Endpoints #### GET /api/v1/websites List all websites ```bash curl -H "Authorization: Bearer YOUR_TOKEN" \ https://analytics.yourdomain.com/api/v1/websites ``` #### GET /api/v1/websites/{id}/stats Get website statistics ```bash curl -H "Authorization: Bearer YOUR_TOKEN" \ "https://analytics.yourdomain.com/api/v1/websites/1/stats?from=2026-03-01&to=2026-03-22" ``` Query Parameters: - `from` (required): Start date (YYYY-MM-DD) - `to` (required): End date (YYYY-MM-DD) #### GET /api/v1/websites/{id}/pages Get page analytics ```bash curl -H "Authorization: Bearer YOUR_TOKEN" \ "https://analytics.yourdomain.com/api/v1/websites/1/pages?from=2026-03-01&to=2026-03-22&limit=20" ``` #### GET /api/v1/websites/{id}/referrers Get referrer data #### GET /api/v1/websites/{id}/events Get event data #### GET /api/v1/websites/{id}/visitors Get visitor data --- ## Maintenance ### Daily Tasks (Automated) These run automatically via cron (see [Task Scheduler](#2-task-scheduler-critical)): - **02:00 AM**: Data aggregation - **03:00 AM**: Old data purging - **Every hour**: Alert evaluation ### Weekly Tasks (Manual) #### Check Queue Status ```bash # Check if queue worker is running ps aux | grep "queue:work" # Check failed jobs php artisan queue:failed # Retry failed jobs php artisan queue:retry all ``` #### Monitor Disk Space ```bash # Check database size du -h database/database.sqlite # Check storage usage du -sh storage/ ``` #### Review Logs ```bash # Check application logs tail -f storage/logs/laravel.log # Check queue worker logs (if using supervisor) tail -f storage/logs/queue-worker.log ``` ### Monthly Tasks #### Database Optimization **SQLite**: ```bash sqlite3 database/database.sqlite "VACUUM;" ``` **MySQL**: ```sql OPTIMIZE TABLE visitors, analytics_sessions, page_views, events, daily_aggregates, page_daily_aggregates; ``` #### Review Data Retention Check if retention settings are appropriate: 1. Navigate to **Website Settings** 2. Review **Data Retention** setting (default: 365 days) 3. Adjust based on compliance requirements ### Backup Strategy #### Database Backup **SQLite**: ```bash # Copy database file cp database/database.sqlite backups/database-$(date +%Y%m%d).sqlite # Compress gzip backups/database-$(date +%Y%m%d).sqlite ``` **MySQL**: ```bash mysqldump -u user -p analytics > backups/analytics-$(date +%Y%m%d).sql gzip backups/analytics-$(date +%Y%m%d).sql ``` #### Application Backup ```bash # Backup entire application tar -czf analytics-backup-$(date +%Y%m%d).tar.gz \ --exclude=node_modules \ --exclude=vendor \ --exclude=storage/logs \ /path/to/analytics ``` ### Troubleshooting #### Tracking Not Working 1. **Check queue worker is running**: ```bash ps aux | grep "queue:work" ``` 2. **Check failed jobs**: ```bash php artisan queue:failed ``` 3. **Check tracking domain matches**: - Ensure website domain in dashboard matches actual domain - Domain validation is case-insensitive but must match 4. **Check browser console**: - Look for CORS errors - Verify tracking script loads 5. **Check logs**: ```bash tail -f storage/logs/laravel.log ``` #### Dashboard Shows No Data 1. **Check if aggregation ran**: ```bash php artisan analytics:aggregate --date=yesterday ``` 2. **Check date range** - today's data may not appear if only querying aggregates 3. **Verify tracking is working** - check raw tables: ```sql SELECT COUNT(*) FROM page_views WHERE created_at > datetime('now', '-1 hour'); ``` #### Alerts Not Triggering 1. **Check cron is running**: ```bash grep CRON /var/log/syslog ``` 2. **Manually run alert check**: ```bash php artisan analytics:check-alerts ``` 3. **Check mail configuration**: ```bash php artisan tinker >>> Mail::raw('Test', function($msg) { $msg->to('test@example.com')->subject('Test'); }); ``` #### High Disk Usage 1. **Run aggregation** (if not running): ```bash php artisan analytics:aggregate ``` 2. **Purge old data**: ```bash php artisan analytics:purge --force ``` 3. **Adjust retention settings** in website configuration --- ## Performance Optimization ### 1. Use Redis for Queue & Cache ```env QUEUE_CONNECTION=redis CACHE_STORE=redis SESSION_DRIVER=redis REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 ``` ### 2. Database Indexing Ensure migrations have run (indexes are included): ```bash php artisan migrate ``` ### 3. Cache Configuration In production: ```bash php artisan config:cache php artisan route:cache php artisan view:cache ``` ### 4. Enable OPcache Add to `php.ini`: ```ini opcache.enable=1 opcache.memory_consumption=256 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=10000 opcache.revalidate_freq=2 ``` ### 5. Queue Workers Run multiple queue workers for high traffic: ```bash # Run 3 workers php artisan queue:work database --tries=3 & php artisan queue:work database --tries=3 & php artisan queue:work database --tries=3 & ``` Or use supervisor with `numprocs=3`. --- ## Security Considerations ### 1. Environment File - Never commit `.env` to version control - Use strong `APP_KEY` (generated automatically) - Set `APP_DEBUG=false` in production ### 2. Database Credentials - Use strong passwords - Restrict database user permissions - Use separate database user for application ### 3. HTTPS - Always use HTTPS in production - Update `APP_URL` to use `https://` - Tracking script requires HTTPS for secure cookies ### 4. CORS - CORS is enabled for `/api/collect` and `/api/t/{id}.js` - Only these endpoints are publicly accessible - Dashboard requires authentication ### 5. Rate Limiting - Tracking endpoints have rate limiting - API endpoints have Sanctum rate limiting - Adjust in `app/Http/Middleware` if needed --- ## Support & Resources ### Documentation - Laravel 11: https://laravel.com/docs/11.x - Alpine.js: https://alpinejs.dev - Tailwind CSS: https://tailwindcss.com ### Logs - Application: `storage/logs/laravel.log` - Queue Worker: Check supervisor/systemd logs ### Common Paths - **Application**: `/path/to/analytics` - **Public**: `/path/to/analytics/public` - **Storage**: `/path/to/analytics/storage` - **Database**: `/path/to/analytics/database/database.sqlite` - **Logs**: `/path/to/analytics/storage/logs/` --- ## Quick Reference ### Essential Commands ```bash # Development composer run dev # Start dev environment # Queue php artisan queue:work database # Start queue worker php artisan queue:failed # List failed jobs php artisan queue:retry all # Retry failed jobs # Analytics php artisan analytics:aggregate # Aggregate yesterday's data php artisan analytics:purge --force # Purge old data php artisan analytics:check-alerts # Check alerts # Cache php artisan cache:clear # Clear cache php artisan config:cache # Cache config (production) # Maintenance php artisan down # Enable maintenance mode php artisan up # Disable maintenance mode ``` ### Cron Entry ```cron * * * * * cd /path/to/analytics && php artisan schedule:run >> /dev/null 2>&1 ``` ### Supervisor Config ```ini [program:analytics-queue] command=php /path/to/analytics/artisan queue:work database --tries=3 autostart=true autorestart=true user=www-data ``` --- **Last Updated**: 2026-03-22 **Laravel Version**: 11.50.0 **PHP Version**: 8.2+ (Compatible with 8.3)