Skip to main content
Ant Media Server provides built-in analytics capabilities to track viewer behavior, stream performance, and player events. This guide covers analytics collection, event types, and implementation.

Analytics Overview

The analytics system collects events from both server-side and client-side sources to provide comprehensive insights into streaming performance and viewer engagement.

Event Sources

  • Server-side: Automatically generated by Ant Media Server
  • Client-side: Sent from player applications via REST API

Analytics Logger

The AnalyticEventLogger (src/main/java/io/antmedia/analytic/AnalyticEventLogger.java) processes all analytics events through dedicated REST endpoints.

Player Analytics Events

Play Events

Track when viewers start, pause, and stop playback:

Event Types

playStartedFirstTime
  • Triggered once when user first starts playing
  • Useful for counting unique views
  • Sent from client player
playStarted
  • Triggered when playback starts or resumes
  • Generated on both server and client side
  • Applies to WebRTC, HLS, and VoD
playPaused
  • Triggered when viewer pauses playback
  • Client-side event only
playEnded
  • Triggered when playback ends
  • Generated on both server and client side

Send Play Events

// Play started first time
fetch('https://your-server.com/LiveApp/rest/v2/events/play', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    event: 'playStartedFirstTime',
    streamId: 'stream123',
    protocol: 'webrtc',
    subscriberId: 'user-uuid-12345',
    token: 'jwt-token-if-secured'
  })
});

// Play paused
fetch('https://your-server.com/LiveApp/rest/v2/events/play', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    event: 'playPaused',
    streamId: 'stream123',
    protocol: 'hls',
    subscriberId: 'user-uuid-12345'
  })
});

Watch Time Events

Track how long viewers watch and which parts of content they consume:

Watch Time Metrics

  • watchTimeMs: Duration viewer watched (in milliseconds)
  • startTimeMs: Position in video where watching started
  • timeMs: Unix timestamp when event occurred

Understanding Watch Time

If you receive:
{
  "startTimeMs": 10000,
  "watchTimeMs": 5000
}
This means: User watched for 5 seconds, covering the 10-15 second segment of the video.

Send Watch Time Events

// Track watch time
fetch('https://your-server.com/LiveApp/rest/v2/events/watch-time', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    event: 'watchTime',
    streamId: 'stream123',
    protocol: 'webrtc',
    watchTimeMs: 5000,      // Watched for 5 seconds
    startTimeMs: 10000,     // Starting at 10 seconds into video
    subscriberId: 'user-uuid-12345',
    token: 'jwt-token-if-secured'
  })
});

Periodic Watch Time Tracking

Implement periodic tracking in your player:
let lastReportTime = 0;
const REPORT_INTERVAL = 10000; // Report every 10 seconds

function reportWatchTime(player) {
  const currentTime = player.getCurrentTime() * 1000; // Convert to ms
  const watchDuration = currentTime - lastReportTime;
  
  if (watchDuration >= REPORT_INTERVAL) {
    fetch('https://your-server.com/LiveApp/rest/v2/events/watch-time', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({
        event: 'watchTime',
        streamId: currentStreamId,
        protocol: 'webrtc',
        watchTimeMs: watchDuration,
        startTimeMs: lastReportTime,
        subscriberId: userId
      })
    });
    
    lastReportTime = currentTime;
  }
}

// Call periodically
setInterval(() => reportWatchTime(player), 5000);

Securing Analytics Endpoints

Protect analytics endpoints from abuse:

Enable JWT Authentication

Configure in Application Settings:
{
  "secureAnalyticEndpoint": true,
  "jwtSecretKey": "your-secret-key-here"
}

Generate JWT Token

// Example using jsonwebtoken library
const jwt = require('jsonwebtoken');

const token = jwt.sign(
  {
    streamId: 'stream123',
    type: 'play'
  },
  'your-secret-key-here',
  { expiresIn: '1h' }
);

// Include token in analytics events
fetch('https://your-server.com/LiveApp/rest/v2/events/play', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    event: 'playStarted',
    streamId: 'stream123',
    token: token  // Include JWT token
  })
});

Analytics Event Structure

Base Event Fields

All analytics events (src/main/java/io/antmedia/analytic/model/AnalyticEvent.java) include:
{
  "event": "event-type",
  "timeMs": 1646567890000,
  "app": "LiveApp",
  "streamId": "stream123",
  "logSource": "client",
  "token": "jwt-token",
  "subscriberId": "user-id"
}
  • event: Event type identifier
  • timeMs: Unix timestamp in milliseconds (auto-set if not provided)
  • app: Application name (auto-set by server)
  • streamId: Stream identifier
  • logSource: “client” or “server”
  • token: JWT token for secured endpoints
  • subscriberId: Unique viewer/subscriber identifier

Play Event Fields

Additional fields for play events (src/main/java/io/antmedia/analytic/model/PlayEvent.java):
{
  "protocol": "webrtc",
  "clientIP": "192.168.1.100"
}
  • protocol: Streaming protocol (webrtc, hls, dash, rtmp)
  • clientIP: Client IP address (auto-set by server)

Watch Time Event Fields

Additional fields for watch time events (src/main/java/io/antmedia/analytic/model/WatchTimeEvent.java):
{
  "watchTimeMs": 5000,
  "startTimeMs": 10000
}
  • watchTimeMs: Duration of watch session in milliseconds
  • startTimeMs: Video position where viewing started

Server-Side Analytics Events

Ant Media Server automatically generates these events:

Publish Events

publishStarted
  • When a stream starts publishing
  • Includes stream metadata
  • Logged automatically
publishEnded
  • When a stream stops publishing
  • Includes stream duration
  • Logged automatically
publishStats
  • Periodic publishing statistics
  • Bitrate, resolution, codec info
  • Logged during active streams

Viewer Count Events

viewerCount
  • Periodic viewer count snapshots
  • Per-stream viewer metrics
  • Broken down by protocol type

Key Frame Events

keyFrameStats
  • Key frame interval statistics
  • Important for ABR and streaming quality

Analytics Data Storage

Analytics events are logged and can be:

File-based Logging

Events are logged to application log files:
Analytics: {"event":"playStarted","streamId":"stream123","protocol":"webrtc",...}

Custom Analytics Processing

To process analytics events:
  1. Parse Log Files: Extract analytics JSON from logs
  2. Kafka Integration: Stream analytics to Kafka for processing
  3. Database Storage: Store events in your analytics database
  4. Real-time Processing: Process events as they arrive

Implementing Analytics in Players

WebRTC Player Example

class AnalyticsTracker {
  constructor(streamId, appName, subscriberId) {
    this.streamId = streamId;
    this.appName = appName;
    this.subscriberId = subscriberId;
    this.baseUrl = `https://your-server.com/${appName}/rest/v2/events`;
    this.firstPlay = true;
    this.watchStartTime = 0;
  }
  
  async sendEvent(endpoint, data) {
    try {
      await fetch(`${this.baseUrl}/${endpoint}`, {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
          streamId: this.streamId,
          subscriberId: this.subscriberId,
          protocol: 'webrtc',
          ...data
        })
      });
    } catch (error) {
      console.error('Analytics error:', error);
    }
  }
  
  onPlayStarted() {
    if (this.firstPlay) {
      this.sendEvent('play', {event: 'playStartedFirstTime'});
      this.firstPlay = false;
    }
    this.sendEvent('play', {event: 'playStarted'});
    this.watchStartTime = Date.now();
  }
  
  onPlayPaused() {
    this.sendEvent('play', {event: 'playPaused'});
    this.reportWatchTime();
  }
  
  onPlayEnded() {
    this.reportWatchTime();
    this.sendEvent('play', {event: 'playEnded'});
  }
  
  reportWatchTime() {
    const watchTimeMs = Date.now() - this.watchStartTime;
    if (watchTimeMs > 0) {
      this.sendEvent('watch-time', {
        event: 'watchTime',
        watchTimeMs: watchTimeMs,
        startTimeMs: this.watchStartTime
      });
    }
  }
}

// Usage
const analytics = new AnalyticsTracker('stream123', 'LiveApp', 'user-uuid');
player.on('play', () => analytics.onPlayStarted());
player.on('pause', () => analytics.onPlayPaused());
player.on('ended', () => analytics.onPlayEnded());

HLS Player Example

// Using hls.js with analytics
const hls = new Hls();
const analytics = new AnalyticsTracker('stream123', 'LiveApp', 'user-uuid');
const video = document.getElementById('video');

hls.loadSource('https://your-server.com/LiveApp/streams/stream123.m3u8');
hls.attachMedia(video);

video.addEventListener('play', () => analytics.onPlayStarted());
video.addEventListener('pause', () => analytics.onPlayPaused());
video.addEventListener('ended', () => analytics.onPlayEnded());

// Report watch time every 10 seconds
setInterval(() => {
  if (!video.paused) {
    analytics.reportWatchTime();
    analytics.watchStartTime = Date.now();
  }
}, 10000);

Analytics Best Practices

  1. Use Subscriber IDs: Assign unique IDs to track individual viewer behavior
  2. Secure Endpoints: Enable JWT authentication in production
  3. Report Periodically: Send watch time events every 10-30 seconds
  4. Handle Errors: Implement retry logic for failed analytics requests
  5. Track First Plays: Use playStartedFirstTime for unique view counts
  6. Include Protocol: Always specify the streaming protocol
  7. Batch Events: Consider batching events in high-volume scenarios
  8. Privacy Compliance: Ensure analytics collection complies with privacy regulations

Analytics Queries and Reporting

Common Analytics Questions

Total Unique Views
# Count playStartedFirstTime events
grep 'playStartedFirstTime' application.log | wc -l
Average Watch Time
# Sum watchTimeMs from watch-time events
grep 'watchTime' application.log | \
  jq -r '.watchTimeMs' | \
  awk '{sum+=$1; count++} END {print sum/count}'
Concurrent Viewers
# Get current viewer count from system resources
curl -s http://localhost:5080/rest/v2/system-resources-info | \
  jq '.localWebRTCViewers + .localHLSViewers + .localDASHViewers'
Most Watched Segments
  • Aggregate startTimeMs values from watch time events
  • Create histogram of video positions
  • Identify popular segments

Integration with Analytics Platforms

Google Analytics

Forward events to Google Analytics:
// Send to GA4
gtag('event', 'play_started', {
  'stream_id': streamId,
  'protocol': 'webrtc'
});

Custom Analytics Pipeline

  1. Collect: Gather events via REST API
  2. Process: Parse and normalize event data
  3. Store: Save to time-series database (InfluxDB, TimescaleDB)
  4. Visualize: Create dashboards (Grafana, Kibana)
  5. Alert: Set up alerts on metrics (viewer drops, error rates)

Build docs developers (and LLMs) love