SDKs
Android (Kotlin / Java)
Native Android SDK for phones, tablets, and Android TV. Works with ExoPlayer, Media3, and any custom player.
Requirements
- Android API 21+ (Lollipop, 5.0+)
- Kotlin 1.9+ recommended; Java 17 also supported
- AndroidX
Install — Gradle
In your app module’s build.gradle:
dependencies {
implementation 'com.tapemetric:analytics:1.0.0'
}Or in build.gradle.kts:
dependencies {
implementation("com.tapemetric:analytics:1.0.0")
}Version catalog (libs.versions.toml)
[versions]
tapemetric = "1.0.0"
[libraries]
tapemetric-analytics = { module = "com.tapemetric:analytics", version.ref = "tapemetric" }Permissions
The SDK declares its required permissions in its own manifest, so no changes to your AndroidManifest.xml are needed:
INTERNET— required to send eventsACCESS_NETWORK_STATE— used to skip flushes when offline
The SDK never requests location, contacts, advertising IDs, phone state, or device identifiers.
Initialize
Configure once in your Application class:
import android.app.Application
import com.tapemetric.analytics.Tapemetric
import com.tapemetric.analytics.TapemetricConfig
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
Tapemetric.configure(
this,
TapemetricConfig(
apiKey = "tm_live_yourkey",
debug = BuildConfig.DEBUG
)
)
}
}Don’t forget to register your Application in AndroidManifest.xml:
<application
android:name=".MyApp"
... >
</application>Identify users
import com.tapemetric.analytics.PlanType
// After login
Tapemetric.identify(
userId = "user_123",
plan = PlanType.SVOD,
traits = mapOf("country" to "IN")
)
// On logout
Tapemetric.reset()Track playback
import com.tapemetric.analytics.TrackContent
import com.tapemetric.analytics.PlaybackState
val content = TrackContent(
contentId = "aashiqana_s04e12",
contentType = "series",
contentTitle = "Aashiqana",
season = 4,
episode = 12
)
// On play
Tapemetric.trackPlayStart(content, PlaybackState(positionSec = 0.0))
// On pause / resume
Tapemetric.trackPause(PlaybackState(positionSec = 124.5))
Tapemetric.trackResume(PlaybackState(positionSec = 124.5))
// On bitrate change
Tapemetric.trackBitrateChange(2400, PlaybackState(positionSec = 200.0, bitrateKbps = 2400))
// On end
Tapemetric.trackComplete(PlaybackState(positionSec = 1320.0, durationSec = 1320.0))
// On error
Tapemetric.trackError(code = "NETWORK_ERROR", message = "Failed to load manifest", fatal = true)Track revenue
Tapemetric.trackPurchase(
amountInr = 199.0,
plan = PlanType.SVOD,
orderId = "order_xyz",
contentId = "pvr_premiere_2026" // optional, for TVOD
)ExoPlayer integration
val exoPlayer = ExoPlayer.Builder(this).build()
val content = TrackContent(contentId = "aashiqana_s04e12", contentType = "series")
var bufferStartedAt: Long = 0
exoPlayer.addListener(object : Player.Listener {
override fun onPlaybackStateChanged(state: Int) {
val pos = exoPlayer.currentPosition / 1000.0
when (state) {
Player.STATE_READY -> Tapemetric.trackPlayStart(content, PlaybackState(pos))
Player.STATE_BUFFERING -> bufferStartedAt = System.currentTimeMillis()
Player.STATE_ENDED -> Tapemetric.trackComplete(PlaybackState(pos))
}
}
override fun onIsPlayingChanged(isPlaying: Boolean) {
val pos = exoPlayer.currentPosition / 1000.0
if (isPlaying && bufferStartedAt > 0) {
// Buffer ended
Tapemetric.trackBuffer(
durationMs = (System.currentTimeMillis() - bufferStartedAt).toInt(),
playback = PlaybackState(pos)
)
bufferStartedAt = 0
}
if (isPlaying) Tapemetric.trackResume(PlaybackState(pos))
else Tapemetric.trackPause(PlaybackState(pos))
}
override fun onPlayerError(error: PlaybackException) {
Tapemetric.trackError(
code = error.errorCodeName,
message = error.message ?: "unknown",
fatal = true
)
}
})Java interop
Every public API is annotated @JvmStatic, so calling from Java is the same minus Kotlin defaults:
import com.tapemetric.analytics.Tapemetric;
import com.tapemetric.analytics.TapemetricConfig;
import com.tapemetric.analytics.TrackContent;
import com.tapemetric.analytics.PlaybackState;
Tapemetric.configure(this, new TapemetricConfig("tm_live_yourkey",
"https://ingest.tapemetric.com", 10000L, 50, false));
TrackContent content = new TrackContent(
"aashiqana_s04e12", "series", "Aashiqana", 4, 12
);
Tapemetric.trackPlayStart(content, new PlaybackState(0.0, null, null));Android TV
The SDK auto-detects Android TV via UI_MODE_TYPE_TELEVISION and reports device_type as tv on every event. No extra config required.
ProGuard / R8
The SDK ships its own consumer-rules.pro — your app’s ProGuard config doesn’t need any Tapemetric-specific keep rules.
Tapemetric.configure() registers a ProcessLifecycleOwner observer that flushes events when the app goes to background. This means events make it to our servers even if the user kills the app from the recents tray.Source and issues
SDK source: github.com/tapemetric/analytics-android. File issues there or email sdk@tapemetric.com.