# Analytics Dashboard EasyStream includes a comprehensive analytics system for creators to track performance, audience insights, and growth metrics. ## Features - 📊 **Channel Overview** - Key metrics at a glance (views, watch time, subscribers, engagement) - 📈 **Time Series Charts** - Track growth over time with customizable date ranges - 🎯 **Traffic Sources** - Understand where your viewers come from - 👥 **Audience Demographics** - Geographic, device, age, and gender breakdowns - 🎬 **Top Videos** - Identify your best-performing content - 📉 **Audience Retention** - Minute-by-minute drop-off analysis - ⚡ **Real-time Stats** - Live viewer counts and recent activity - 🤖 **Automatic Tracking** - No manual instrumentation required ## Setup ### 1. Database Migration Run the migration to create analytics tables: ```bash docker-compose exec db mysql -u easystream -peasystream easystream < __install/migrations/004_add_analytics_system.sql ``` This creates: - `db_video_analytics` - Detailed event tracking - `db_channel_analytics_daily` - Daily aggregated summaries - `db_traffic_sources` - Traffic source tracking - `db_audience_retention` - Minute-by-minute retention - `db_audience_demographics` - Demographic breakdowns - `db_realtime_stats` - Cached real-time metrics ### 2. Add Tracking Script to Video Player Include the analytics tracker on your video watch page: ```html ``` The tracker will auto-initialize and begin tracking: - Video views - Watch time - Completion rate - Audience retention - Traffic sources ### 3. Set Up Daily Aggregation Cron Add a cron job to aggregate daily stats: ```bash # Run every day at 1 AM 0 1 * * * cd /srv/easystream && php app_scripts/cron/aggregate_analytics.php >> /var/log/analytics-aggregation.log 2>&1 ``` This consolidates raw analytics data into daily summaries for fast dashboard loading. ## Dashboard Access the creator dashboard at `/creator/dashboard.php` (requires authentication). ### Overview Cards - **Views (Last 30 Days)** - Total video views - **Watch Time** - Total minutes watched - **Subscribers** - New subscribers gained - **Engagement Rate** - Percentage of viewers who like/comment ### Time Series Chart Track metrics over time with adjustable date ranges (7/30/90 days): - Views - Watch Time - Unique Viewers - Likes - Comments ### Traffic Sources Pie chart showing where your viewers come from: - **Direct** - Typed URL or bookmark - **Search** - Search engines (Google, internal search) - **External** - External websites - **Suggested** - Recommendations/browse page - **Playlist** - From playlists - **Notification** - From notification clicks - **Social** - Social media platforms ### Audience Demographics Bar chart showing: - **Devices** - Desktop, mobile, tablet, TV - **Countries** - Top 10 countries - **Age Ranges** - 13-17, 18-24, 25-34, 35-44, 45-54, 55-64, 65+ ### Top Videos List of your best-performing videos by: - Views - Watch time - Likes - Comments - Shares - Completion rate ## API Endpoints ### Get Channel Overview ```http GET /api/analytics.php?action=overview&days=30 ``` **Response:** ```json { "success": true, "data": { "total_views": 15234, "total_watch_time": 45678, "total_likes": 1234, "total_comments": 567, "subscribers_gained": 89, "avg_view_duration": 180, "avg_completion_rate": 65.5, "views_last_hour": 23, "views_last_24h": 456 } } ``` ### Get Time Series Data ```http GET /api/analytics.php?action=timeseries&metric=views&days=30 ``` **Metrics:** `views`, `watch_time_minutes`, `likes`, `comments`, `shares`, `unique_viewers` **Response:** ```json { "success": true, "data": [ {"date": "2026-03-01", "value": 456}, {"date": "2026-03-02", "value": 523}, ... ] } ``` ### Get Top Videos ```http GET /api/analytics.php?action=top_videos&metric=views&limit=10&days=30 ``` **Metrics:** `views`, `watch_time`, `likes`, `comments`, `shares`, `completion` ### Get Demographics ```http GET /api/analytics.php?action=demographics&days=30 ``` **Response:** ```json { "success": true, "data": { "countries": [ {"country_code": "US", "views": 5432}, {"country_code": "UK", "views": 2345} ], "devices": [ {"device_type": "mobile", "views": 8765}, {"device_type": "desktop", "views": 6543} ], "age_ranges": [ {"age_range": "18-24", "views": 4567}, {"age_range": "25-34", "views": 6789} ] } } ``` ### Get Traffic Sources ```http GET /api/analytics.php?action=traffic_sources&days=30 ``` ### Get Audience Retention (Video-specific) ```http GET /api/analytics.php?action=retention&video_id=123&days=30 ``` **Response:** ```json { "success": true, "data": [ {"minute": 0, "viewers": 1000}, {"minute": 1, "viewers": 850}, {"minute": 2, "viewers": 720}, ... ] } ``` ### Track Event (Public endpoint) ```http POST /api/analytics.php?action=track Content-Type: application/json { "video_id": 123, "event_type": "view", "watch_duration": 180, "completion_percentage": 75.5, "minute": 3, "source_type": "search", "source_detail": "google" } ``` **Event Types:** - `view` - Video view - `like` - Like event - `comment` - Comment event - `share` - Share event - `download` - Download event - `watch_time` - Watch duration update - `completion` - Video completed ## Tracking Implementation ### Automatic Tracking The `VideoAnalyticsTracker` JavaScript class handles automatic tracking: ```javascript // Auto-initializes on video watch pages const tracker = new VideoAnalyticsTracker(videoId, { playerElement: document.querySelector('video'), trackingInterval: 10000 // Update every 10 seconds }); ``` **What gets tracked:** - View on first play - Watch time every 10 seconds - Retention (minute-by-minute) - Completion when video ends - Traffic source detection - Final progress on page unload ### Manual Tracking Track custom events: ```javascript await fetch('/api/analytics.php?action=track', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ video_id: 123, event_type: 'share', source_type: 'social', source_detail: 'twitter' }) }); ``` ### Backend Tracking Track events from PHP: ```php require_once 'f_core/f_classes/class.analytics.php'; $analytics = new VAnalytics(); // Track a view $analytics->trackEvent($video_id, 'view', [ 'usr_id' => $user_id, 'watch_duration' => 180, 'completion_percentage' => 75.5 ]); // Track traffic source $analytics->trackTrafficSource($video_id, $channel_owner_id, 'search', 'google'); // Track retention $analytics->trackRetention($video_id, $minute); ``` ## Database Schema ### db_video_analytics (raw events) | Column | Type | Description | |--------|------|-------------| | analytics_id | BIGINT | Primary key | | video_id | INT | Video ID | | usr_id | INT | Viewer user ID (if logged in) | | event_type | ENUM | view/like/comment/share/download/watch_time/completion | | watch_duration | INT | Seconds watched | | completion_percentage | DECIMAL | % of video completed | | device_type | ENUM | desktop/mobile/tablet/tv/other | | browser | VARCHAR(50) | Browser name | | os | VARCHAR(50) | Operating system | | country_code | VARCHAR(2) | ISO country code | | referrer | VARCHAR(512) | HTTP referrer | | ip_hash | VARCHAR(64) | Hashed IP address | | session_id | VARCHAR(64) | Session identifier | | created_at | DATETIME | Event timestamp | ### db_channel_analytics_daily (aggregated) | Column | Type | Description | |--------|------|-------------| | usr_id | INT | Channel owner | | date | DATE | Day | | views | INT | Total views | | watch_time_minutes | INT | Total watch time | | likes | INT | Total likes | | comments | INT | Total comments | | shares | INT | Total shares | | subscribers_gained | INT | New subscribers | | unique_viewers | INT | Distinct viewers | | avg_view_duration | INT | Average watch time | | avg_completion_rate | DECIMAL | Average completion % | ## Performance - **Raw events:** ~1-2ms per insert - **Dashboard queries:** 10-50ms (with daily aggregates) - **Real-time updates:** Cached, <5ms - **Data retention:** Raw events kept 90 days (configurable), aggregates kept indefinitely ## Privacy & Compliance - IP addresses are **hashed** (SHA-256), not stored in plaintext - User IDs only tracked for logged-in users - Session IDs are unique per browser session - GDPR-compliant: data deletion cascades on user account deletion - No third-party tracking (fully self-hosted) ## Advanced Analytics ### Custom Metrics Add custom tracking for specific features: ```javascript // Track custom interaction fetch('/api/analytics.php?action=track', { method: 'POST', body: JSON.stringify({ video_id: videoId, event_type: 'custom', custom_metric: 'chapter_viewed', custom_value: chapterNumber }) }); ``` ### A/B Testing Track experiment variants: ```php $analytics->trackEvent($video_id, 'view', [ 'experiment_id' => 'thumbnail_test', 'variant' => 'A' ]); ``` ### Revenue Tracking Integrate with monetization: ```php $sql = "UPDATE db_channel_analytics_daily SET revenue_last_24h = ? WHERE usr_id = ? AND date = CURDATE()"; ``` ## Troubleshooting ### Dashboard shows no data 1. Check analytics tracking is enabled in video player 2. Verify JavaScript console for errors 3. Check database tables exist 4. Run aggregation manually: `php app_scripts/cron/aggregate_analytics.php` ### Retention graph empty 1. Ensure video tracker is loaded on watch page 2. Check `db_audience_retention` table has data 3. Verify video ID is correct ### Real-time stats not updating 1. Check `db_realtime_stats` table 2. Ensure views are being tracked 3. Verify cache expiry (5 minutes) ## Future Enhancements - [ ] Predicted views/subscribers (ML) - [ ] Content recommendations based on analytics - [ ] Comparative analytics (vs similar channels) - [ ] Export reports (PDF/CSV) - [ ] Email digest reports - [ ] Anomaly detection (sudden drops/spikes) - [ ] A/B testing framework - [ ] Heatmaps for video engagement - [ ] Cohort analysis - [ ] Revenue analytics (monetization integration) ## Learn More - [YouTube Analytics Documentation](https://support.google.com/youtube/answer/9002587) - [Chart.js Documentation](https://www.chartjs.org/docs/) - [Web Analytics Best Practices](https://en.wikipedia.org/wiki/Web_analytics)