# Analytics

When using our app's SDK, it can be useful to gain deeper insights into what's happening within the SDK itself. This document serves as a guide to the analytics events available through Firework Android SDK API.

## Firework Analytics

Before we dive into the analytics events, let's take a moment to review how to register and unregister for analytics tracking.

:exclamation: **Note that not unregistering from the analytics API can lead to memory leaks**

**Registering and unregistering for firework analytics**

{% tabs %}
{% tab title="Kotlin" %}

<pre class="language-kotlin"><code class="lang-kotlin"><strong>override fun onCreate(savedInstanceState: Bundle?) {
</strong>    super.onCreate(savedInstanceState)
    FireworkSdk.analytics.register(this)
}

override fun onDestroy() {
    super.onDestroy()
    FireworkSdk.analytics.unregister(this)
}
</code></pre>

{% endtab %}

{% tab title="Java" %}

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    FireworkSdk.INSTANCE.getAnalytics().register(this);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    FireworkSdk.INSTANCE.getAnalytics().unregister(this);
}
```

{% endtab %}
{% endtabs %}

#### Now let's see how to subscribe to the specific analytics event

In general, when you want to register for a specific event you simply define a function with `FwAnalyticCallable` like below:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
@FwAnalyticCallable
fun onSpecificEvent(event: SpecificEventType) {
    // Do whatever you want with the event
}
```

{% endtab %}

{% tab title="Java" %}

```java
@FwAnalyticCallable
void onSpecificEvent(SpecificEventType event){

}
```

{% endtab %}
{% endtabs %}

To register for the specific event simply add the '@FwAnalyticCallable' annotation to your function, and pass in the desired event type as a parameter. This gives you the flexibility to register for any analytics event, making it easy to capture and analyse the specific data points you need for your app.

## Supported events

### Video Lifecycle Playback Tracking

If the host app needs to monitor events that occur during video playback, the Firework SDK offers a simple solution. The SDK enables the host app to easily observe and track events for each video that is played by the user.

:exclamation:The Lifecycle Playback Event is triggered every time the video plays, even if there's just one video in the playlist on a loop. It pertains to the playback status of the video itself. If you need non-repetitive callbacks for data analytics, please refer to Video Analysis Events Tracking.

:exclamation:**`PlayerLifecycleAnalyticsEvent`** is a parent event for other playback events.\
If host app subscribes to this event, it will receive all playback event that are available.

Here is the list of available playback events:

1. **OnImpression**: sent when the video is viewed in full-screen player or compact story block.
2. **OnPrepared**: sent when the video is prepared for playing but has not started yet.
3. **OnBuffering**: sent when video is buffering.
4. **OnIdle**: sent when video is buffered and prepared fully but has not started to play.
5. **OnRepeat**: sent when video is repeated.
6. **OnEnded**: sent when video is finished. It is not sent when the user swipes to the next video, it's only sent when the video reaches to the end of the playback progress.
7. **OnError**: sent when video cannot be played due to an error.
8. **OnSeek**: sent when video playback is moved to a new position.
9. **OnVideoSizeChanged**: sent when the dimension of the video has been changed.
10. **OnPlaybackProgressChanged**: sent during the payback and contains current progress value in seconds.
11. **OnFirstQuartile**: sent when the first 25% of the video has passed
12. **OnSecondQuartile**: sent when the first 50% of the video has passed
13. **OnThirdQuartile**: sent when the first 75% of the video has passed
14. **OnLast90PercentOfTheVideo**: sent when the first 90% of the video has passed
15. **OnStarted**: sent when the content starts for the first time in the player.
16. **OnPaused**: sent when the content is paused.
17. **OnResumed**: When the content is resumed.

Example of subscribing to the playback event

{% tabs %}
{% tab title="Kotlin" %}

```kts
@FwAnalyticCallable
fun onPlaybackEvent(event: PlayerLifecycleAnalyticsEvent) {
    when (event) {
        is PlayerLifecycleAnalyticsEvent.OnBuffering,
        is PlayerLifecycleAnalyticsEvent.OnEnded,
        is PlayerLifecycleAnalyticsEvent.OnError,
        is PlayerLifecycleAnalyticsEvent.OnIdle,
        is PlayerLifecycleAnalyticsEvent.OnPlaybackProgressChanged,
        is PlayerLifecycleAnalyticsEvent.OnImpression,
        is PlayerLifecycleAnalyticsEvent.OnPrepared,
        is PlayerLifecycleAnalyticsEvent.OnFirstQuartile,
        is PlayerLifecycleAnalyticsEvent.OnLast90PercentOfTheVideo,
        is PlayerLifecycleAnalyticsEvent.OnSecondQuartile,
        is PlayerLifecycleAnalyticsEvent.OnThirdQuartile,
        is PlayerLifecycleAnalyticsEvent.OnRepeat,
        is PlayerLifecycleAnalyticsEvent.OnSeek,
        is PlayerLifecycleAnalyticsEvent.OnVideoSizeChanged,
        is PlayerLifecycleAnalyticsEvent.OnStarted,
        is PlayerLifecycleAnalyticsEvent.OnPaused,
        is PlayerLifecycleAnalyticsEvent.OnResumed -> Log.i("fw-analytics-playback", event.videoInfo.toString())
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
@FwAnalyticCallable
void onPlaybackEvent(PlayerLifecycleAnalyticsEvent event){
if(event instanceof PlayerLifecycleAnalyticsEvent.OnPrepared
        || event instanceof PlayerLifecycleAnalyticsEvent.OnBuffering
        || event instanceof PlayerLifecycleAnalyticsEvent.OnEnded
        || event instanceof PlayerLifecycleAnalyticsEvent.OnError
        || event instanceof PlayerLifecycleAnalyticsEvent.OnIdle
        || event instanceof PlayerLifecycleAnalyticsEvent.OnPlaybackProgressChanged
        || event instanceof PlayerLifecycleAnalyticsEvent.OnPrepared
        || event instanceof PlayerLifecycleAnalyticsEvent.OnFirstQuartile
        || event instanceof PlayerLifecycleAnalyticsEvent.OnLast90PercentOfTheVideo
        || event instanceof PlayerLifecycleAnalyticsEvent.OnSecondQuartile
        || event instanceof PlayerLifecycleAnalyticsEvent.OnThirdQuartile
        || event instanceof PlayerLifecycleAnalyticsEvent.OnRepeat
        || event instanceof PlayerLifecycleAnalyticsEvent.OnSeek
        || event instanceof PlayerLifecycleAnalyticsEvent.OnVideoSizeChanged
        || event instanceof PlayerLifecycleAnalyticsEvent.OnStarted
        || event instanceof PlayerLifecycleAnalyticsEvent.OnPaused
        || event instanceof  PlayerLifecycleAnalyticsEvent.OnResumed){
    Log.i("fw-analytics-playback", event.getVideoInfo().toString());
}
}
```

{% endtab %}
{% endtabs %}

### Video Analytics Events Tracking

We also provide data analytics callbacks that adhere to the VAST protocol. Unlike the **`PlayerLifecycleAnalyticsEvent`**, these callbacks will not repeatedly activate for the same video data analytics events during automatic playback, unless the user manually switches to a previous or next video.

:exclamation:For example, if a playlist video is looping, this callback is only triggered the first time the playlist plays.

Here is the list of video analysis events:

1. **OnImpression**: sent when the first frame of the creative is displayed.
2. **OnStarted**: this event is used to indicate that an individual creative within the ad was loaded and playback began..
3. **OnFirstQuartile**: the creative played for at least 25% of the total duration
4. **OnSecondQuartile**: the creative played for at least 50% of the total duration
5. **OnThirdQuartile**: the creative played for at least 75% of the total duration
6. **OnLast90PercentOfTheVideo**: the creative played for at least 90% of the total duration
7. **OnEnded**: sent when the creative played to the end at normal speed..
8. **OnClickMute:** sent when the user activated the mute control and muted the creative.
9. **OnClickUnmute**: sent when the user activated the mute control and unmuted the creative.
10. **OnClickToFullScreen**: sent when the user activated a control to extend the video player to the edges of the viewer’s screen
11. **OnClickToQuitFullScreen**: sent when the the user activated the control to close or enter into pip mode
12. **OnClickToPlay**: sent when the user clicked the start control and start the creative from beginning.
13. **OnClickToPause**: sent when the user clicked the pause control and stopped the creative.
14. **OnClickToResume**: sent when the user activated the resume control after the creative had been stopped or paused.

Example of subscribing to the playback event

{% tabs %}
{% tab title="Kotlin" %}

```
    @FwAnalyticCallable
    fun onVideoAnalytics(event: VideoAnalyticsEvent) {
        when (event){
            is VideoAnalyticsEvent.OnImpression,
            is VideoAnalyticsEvent.OnStarted,
            is VideoAnalyticsEvent.OnFirstQuartile,
            is VideoAnalyticsEvent.OnSecondQuartile,
            is VideoAnalyticsEvent.OnThirdQuartile,
            is VideoAnalyticsEvent.OnLast90PercentOfTheVideo,
            is VideoAnalyticsEvent.OnEnded,
            is VideoAnalyticsEvent.OnClickMute,
            is VideoAnalyticsEvent.OnClickUnMute,
            is VideoAnalyticsEvent.OnClickToPlay,
            is VideoAnalyticsEvent.OnClickToPause,
            is VideoAnalyticsEvent.OnClickToResume,
            is VideoAnalyticsEvent.OnClickToFullScreen,
            is VideoAnalyticsEvent.OnClickToQuitFullScreen->
                Log.d("Video Analysis" ,"Video id: ${event.videoInfo?.id}}")
        }
    }
```

{% endtab %}
{% endtabs %}

### Share Button Analytics Events Tracking

**ShareButtonAnalyticsEvent**: This event will be called when the share button on the video player page is being called by the user. All the description about the `VideoInfo` is true here as well.

```kotlin
@FwAnalyticCallable
fun onShareButtonClicked(event: ShareButtonAnalyticsEvent) {
    Log.i("fw-analytics-share", event.videoInfo.toString())
}
```

You can simply use the `VideoInfo` object to obtain more details.

### CTA Button Analytics Events Tracking

**CtaButtonClickAnalyticsEvent:** This event will be called when the CTA button is pressed by the user. By default, the SDK will open the CTA url in the default browser of the phone, however, if you set the SDK to handle CTA action in the ViewOptions `true` the SDK will not do anything and just report that CTA\_clicked event to the host app.\
All the description about the `VideoInfo` is true here as well.

```kotlin
@FwAnalyticCallable
fun onCtaButtonClicked(event: CtaButtonClickAnalyticsEvent) {
    Log.i("fw-analytics-cta", event.label + " " + event.actionUrl)

    if (!isCtaHandledBySDK) {
        CtaModalActivity.start(this, event)
    }
}

val playerOptions = PlayerOption.Builder()
    .sdkHandleCtaButtonClick(true) // This value here determines whether the SDK should handle the CTA click or not
    .build()
    
ViewOptions
        .Builder()
        .playerOption(playerOptions)
        .ctaOption(ctaOptions)
        .build()
```

### Livestream Analytics Events Tracking

**LivestreamAnalyticEvent:** There are multiple events which may lead to this callback:

```kotlin
    @FwAnalyticCallable
    fun onLivestreamEvent(event: LivestreamAnalyticEvent) {
    when (event) {
        is LivestreamAnalyticEvent.UserSentChatMessage -> {
            Log.i("fw-analytics-livestream", "User sent chat message: $event")
        }

        is LivestreamAnalyticEvent.UserJoined -> {
            Log.i("fw-analytics-livestream", "User joined: $event")
        }

        is LivestreamAnalyticEvent.UserLeft -> {
            Log.i("fw-analytics-livestream", "User left: $event")
        }

        is LivestreamAnalyticEvent.UserSentLike -> {
            Log.i("fw-analytics-livestream", "User sent like: $event")
        }
    }
}
```

#### Capturing events in smaller scopes

*As you can see in the example code below it is possible to register only for `OnStarted` event instead of registering for all events.*

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
@FwAnalyticCallable
fun onStartedEvent(event: PlayerLifecycleAnalyticsEvent.OnStarted) {
    Log.i("fw-analytics-playback", "OnStarted ${event.videoInfo}")
}
```

{% endtab %}

{% tab title="Java" %}

```java
@FwAnalyticCallable
void onStartedEvent(PlayerLifecycleAnalyticsEvent.OnStarted event){
    Log.i("fw-analytics-playback", "OnStarted"+event.getVideoInfo());
}
```

{% endtab %}
{% endtabs %}

## Events and Callback Payload

All playback analytics events and callback for shopping/livestream contains the following info:

```kotlin
    val videoInfo: VideoInfo // information about the video
```

**VideoInfo** object contains the following information:

```kotlin
val id: String, // content id
val caption: String, // content caption (title)
val duration: Double, // duration in seconds
val badge: String?, // text of the video badge
val playerHeight: Int?, // content width
val playerWidth: Int?, // content height
val hasCta: Boolean, // true if the video has "call to aciton" button
val isAd: Boolean // true if the video is an Ad video
val hashtags: List<String>, // Hashtags list added to the video
val feedType: String, // The feed resource type
val channelId: String? // Channel ID if the feed resource has one
val playlistId: String? // Playlist ID if the feed resource has one
val feedId: String, // Widget instance ID - see "Identifying Widget Source" section below
val videoType: VideoType, // Type of video content (ShortVideo, Ad, or Livestream variants)
val autoPlay: Boolean? // Define if the video is played automatically
```

**VideoType**

The `videoType` field indicates the type of video content:

```kotlin
sealed interface VideoType {
    object ShortVideo : VideoType   // Regular short video
    object Ad : VideoType           // Advertisement video

    sealed interface Livestream : VideoType {
        object Idle : Livestream      // Scheduled livestream (not yet started)
        object Live : Livestream      // Currently live
        object Replay : Livestream    // Livestream replay
        object Completed : Livestream // Completed livestream
    }
}
```

## Identifying Widget Source Using feedId

When using multiple Firework widgets (such as `FwVideoFeedView` or `FwStoryBlockView`) in your application, you may need to identify which specific widget instance generated an analytics event. The `feedId` field in `VideoInfo` serves this purpose.

### Understanding feedId

The `feedId` is a unique identifier (UUID) generated for each widget instance. It corresponds to the widget's internal `embedInstanceId` and remains consistent throughout the widget's lifecycle.

### Accessing Widget feedId

Both `FwVideoFeedView` and `FwStoryBlockView` expose a public `feedId` property:

**FwVideoFeedView:**

```kotlin
val videoFeedView = findViewById<FwVideoFeedView>(R.id.videoFeedView)
videoFeedView.init(viewOptions)

// Access the widget's feedId
val widgetFeedId = videoFeedView.feedId
```

**FwStoryBlockView:**

```kotlin
val storyBlockView = findViewById<FwStoryBlockView>(R.id.storyBlockView)
storyBlockView.init(fragmentManager, lifecycleOwner, viewOptions)

// Access the widget's feedId
val widgetFeedId = storyBlockView.feedId
```

### Matching Events to Widgets

When receiving analytics events, compare the `feedId` from `VideoInfo` with your widget's `feedId` to determine the event source:

```kotlin
class MyActivity : AppCompatActivity() {
    
    private lateinit var videoFeedView1: FwVideoFeedView
    private lateinit var videoFeedView2: FwVideoFeedView
    private lateinit var storyBlockView: FwStoryBlockView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        FireworkSdk.analytics.register(this)
        
        // Initialize your widgets
        videoFeedView1 = findViewById(R.id.videoFeedView1)
        videoFeedView2 = findViewById(R.id.videoFeedView2)
        storyBlockView = findViewById(R.id.storyBlockView)
        
        // ... init widgets with their respective ViewOptions
    }

    @FwAnalyticCallable
    fun onPlaybackEvent(event: PlayerLifecycleAnalyticsEvent) {
        val eventFeedId = event.videoInfo?.feedId ?: return
        
        when (eventFeedId) {
            videoFeedView1.feedId -> {
                Log.d("Analytics", "Event from VideoFeedView #1: $event")
                // Handle events from first video feed
            }
            videoFeedView2.feedId -> {
                Log.d("Analytics", "Event from VideoFeedView #2: $event")
                // Handle events from second video feed
            }
            storyBlockView.feedId -> {
                Log.d("Analytics", "Event from StoryBlockView: $event")
                // Handle events from story block
            }
            else -> {
                Log.d("Analytics", "Event from unknown widget: $event")
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        FireworkSdk.analytics.unregister(this)
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.firework.com/firework-for-developers/android-sdk/integration-guide/analytics.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
