Skip to main content

Livestream Analytics

The social.plus Video SDK provides comprehensive analytics capabilities for tracking viewer engagement and watch time during live and recorded room playback. This feature enables you to collect valuable insights about how users interact with your video content.

Overview

Watch Session Tracking

Track viewer watch time
  • Create watch sessions for viewers
  • Separate tracking for live and recorded content

Network Resilient Sync

Reliable data collection
  • Local persistence of analytics data
  • Automatic sync with jitter delay
  • Network-aware retry logic

Key Concepts

Watch Sessions

A watch session represents a period of time during which a viewer is actively watching a room. Key characteristics:
  • Unique Session IDs: Each session has a unique identifier with prefixes indicating content type
    • room_ prefix for live room watching
    • room_playback_ prefix for recorded content

Getting Started

1

Access Room Analytics

Get the analytics instance from any AmityRoom object.
2

Create Watch Session

Create a session when a viewer starts watching.
3

Update Watch Duration

Update the session periodically with accumulated watch time.
4

Sync Sessions

Sync pending sessions when the viewer stops watching.

API Reference

AmityRoom Extension

The AmityRoom class is extended with an analytics capability:
extension AmityRoom {
    /// Get analytics instance for this room
    /// - Returns: AmityRoomAnalytics instance for tracking watch sessions
    func analytics() -> AmityRoomAnalytics
}

AmityRoomAnalytics

The main class for managing room analytics operations:
Create a new watch session for the current roomCreates a unique watch session to track viewer engagement. The session ID format depends on the room status:
  • Live rooms: room_<unique-id>
  • Recorded rooms: room_playback_<unique-id>
Parameters:
ParameterTypeRequiredDescription
startedAtDateYesThe timestamp when watching started
Returns: Promise<String> - Unique session identifierThrows: BusinessException if room is not in watchable state (not LIVE or RECORDED)
import AmitySDK

func startWatchSession(room: AmityRoom) async throws -> String {
    let analytics = room.analytics()
    let sessionId = try await analytics.createWatchSession(startedAt: Date())
    print("Watch session created: \(sessionId)")
    return sessionId
}
Update an existing watch session with durationUpdates the watch session with the current accumulated watch time. Call this periodically (recommended: every 1 second) while the viewer is actively watching.Parameters:
ParameterTypeRequiredDescription
sessionIdStringYesThe unique identifier of the watch session
durationNumberYesThe total watch duration in seconds
endedAtDateYesThe timestamp when this update occurred
Returns: Promise<void>
import AmitySDK

func updateSession(
    room: AmityRoom, 
    sessionId: String, 
    watchedSeconds: Int
) async throws {
    let analytics = room.analytics()
    try await analytics.updateWatchSession(
        sessionId: sessionId,
        duration: watchedSeconds,
        endedAt: Date()
    )
}
Sync all pending watch sessions to backendTriggers synchronization of all locally stored watch sessions that haven’t been synced yet.Returns: void
import AmitySDK

func syncAllSessions(room: AmityRoom) {
    let analytics = room.analytics()
    analytics.syncPendingWatchSessions()
    // Sync happens asynchronously with jitter delay
}
Only call syncPendingWatchSessions() when the user leaves the room or transitions from viewer to co-host. Do not call on every pause event.

Best Practices

When to create sessions:
  • Create a session when a viewer enters the room player page
  • Only create for actual viewers (not hosts or co-hosts)
  • Only create for LIVE or RECORDED rooms
  • Prevent duplicate sessions by tracking the current room ID
// ✅ Correct: Check all conditions before creating
if (isActualViewer && (room.status === 'live' || room.status === 'recorded')) {
    if (watchingRoomId !== room.roomId) {
        sessionId = await room.analytics().createWatchSession(new Date());
    }
}

// ❌ Incorrect: Creating without checks
sessionId = await room.analytics().createWatchSession(new Date());
Accurate time tracking:
  • Only count time when video is actively playing
  • Pause tracking during buffering states
  • Use accumulated time + elapsed since last resume for accurate totals
// ✅ Correct: Calculate total from accumulated + current elapsed
const totalDuration = accumulatedWatchTimeSeconds + 
    Math.floor((Date.now() - lastResumeTime.getTime()) / 1000);

// ❌ Incorrect: Using wall clock time
const totalDuration = Math.floor((Date.now() - sessionStartTime.getTime()) / 1000);
When to sync:
  • ✅ When user leaves the room player page
  • ✅ When user transitions from viewer to co-host
  • ❌ Do NOT sync on video pause
  • ❌ Do NOT sync on app background
// ✅ Correct: Sync on page exit
function onPageExit() {
    stopWatchTracking(shouldSync: true);
}

// ❌ Incorrect: Syncing on pause
function onVideoPause() {
    pauseWatchTracking();
    room.analytics().syncPendingWatchSessions(); // Don't do this!
}
Handle viewer ↔ co-host transitions:
  • When becoming a co-host: Stop tracking and sync immediately
  • When returning to viewer: Create a fresh new session
  • Never reuse session IDs across role transitions
// Viewer → Co-host
function onBecomeCoHost() {
    stopWatchTracking(shouldSync: true);
}

// Co-host → Viewer
function onReturnToViewer() {
    // Creates a completely new session
    startWatchTracking(isStreamerMode, cohostUserId, currentUserId);
}

Error Handling

Common Errors

ErrorCauseSolution
BusinessException: room is not in watchable stateAttempting to create session for room that is not LIVE or RECORDEDCheck room status before creating session