Fire the call at meaningful playback milestones: video_play_started, video_25pct_reached, video_50pct_reached, video_75pct_reached, video_completed. Don't pass video ID, content title, or duration.
▸Install the Kotlin (Android) SDK
// build.gradle.kts (app module)
dependencies {
implementation("com.respectlytics:respectlytics-kotlin:3.0.0")
}
Pure Kotlin coroutines implementation. No Java dependencies, no Google Play Services dependencies. ~300KB DEX overhead — compare to roughly 3.8MB for Firebase Analytics (a measurable cold-start improvement on lower-end devices).
▸Initialize Respectlytics in Kotlin (Android)
import com.respectlytics.android.Respectlytics
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Respectlytics.configure(this, appKey = "<YOUR_APP_KEY>")
}
}
Initialize once in Application.onCreate. No additional permissions in the manifest — INTERNET is sufficient. The SDK does not request AD_ID, does not query AdvertisingIdClient, and does not declare ACCESS_NETWORK_STATE.
▸Track the event in Kotlin (Android)
import androidx.media3.exoplayer.ExoPlayer
import com.respectlytics.android.Respectlytics
class VideoMilestoneTracker(private val player: ExoPlayer) {
private var fired25 = false; private var fired50 = false
private var fired75 = false; private var firedComplete = false
fun tick() {
val duration = player.duration.takeIf { it > 0 } ?: return
val progress = player.currentPosition.toFloat() / duration
if (progress >= 0.25f && !fired25) { fired25 = true; Respectlytics.track("video_25pct_reached") }
if (progress >= 0.50f && !fired50) { fired50 = true; Respectlytics.track("video_50pct_reached") }
if (progress >= 0.75f && !fired75) { fired75 = true; Respectlytics.track("video_75pct_reached") }
if (progress >= 0.99f && !firedComplete) { firedComplete = true; Respectlytics.track("video_completed") }
}
}
Call tick() from a 1-second Handler post-loop while the video is playing. Reset flags on onMediaItemTransition.
✦Privacy & implementation notes
Tracking exact playback position generates 30+ events per minute of viewing and dilutes every other signal in your analytics pipeline. Four milestones (25, 50, 75, 100%) per video carry essentially the same product signal at 1/100th the volume.
Your CMS already stores video titles, descriptions, durations, and content categories. Joining video_completed_movie events to your CMS's view-count-per-video data answers most product questions; storing the title as analytics metadata duplicates a system of record without adding signal.
Many teams discover the com.google.android.gms.permission.AD_ID permission in their merged manifest only after Google Play flags them — usually because a transitive dependency dragged it in. Respectlytics's Kotlin SDK has no Google Play Services dependency at all, so it cannot contribute to that merge.
The SDK is implemented as pure Kotlin coroutines with no Java sources, no RxJava, and no platform channels. Events are queued in a Channel<Event> buffered to a small ring (RAM-only), drained by a coroutine that flushes every 30 seconds or on backgrounding. There is no SharedPreferences usage.
⇋How this compares to other analytics SDKs
| Video completion event | Firebase Analytics | Mixpanel | Respectlytics |
|---|---|---|---|
| Video ID as parameter | Recommended | Recommended | Forbidden (use top-N event_names) |
| Content category / genre | Recommended | Recommended | Use distinct event_name (top-N) |
| Watch duration in seconds | Recommended | Recommended | Out of scope (use milestones) |
| Per-user watch history | Yes | Yes | Out of scope (use content backend) |
| Completion *rate* by country / platform | Yes | Yes | Yes (default) |
❓Frequently asked questions
How do we know which videos are most-watched?
Your content backend already has play counts per video — that's where video-level engagement lives. Respectlytics is for product engagement at the feature level ("is the video player surface working?"). Conflating them duplicates a system of record.
Should we track exact playback position?
No — milestones (25 / 50 / 75 / 100%) carry the signal. Exact position produces a flood of low-value events that drown the milestone signal. Player-side analytics (your video player vendor's SDK) has its own per-second tracking if you genuinely need it.
What about content category breakdowns (movies, shows, shorts)?
If you have a small fixed set, distinct event names: video_completed_movie, video_completed_show. For high-cardinality categorization, use your content backend's analytics — it has the metadata you need.
Does this work for live streams?
Conceptually different. Use distinct event names — livestream_joined, livestream_left — and fire on join and leave. Milestones don't apply to live; duration is computed from join → leave timestamp difference.