GuidesAPI ReferenceRelease Notes
HomeLog InHome
Guides

Migrate on Android

Heads up:

Preliminary pre-release documentation, subject to change without notice. The full list of properties on each event isn't published yet.

Updated on September 16, 2026.

The unified schema ships as a major version on Android. Removed enum entries are deleted rather than deprecated, so an exhaustive when over the analytics enums stops compiling until you handle the new shape.

This page is written to be followed by a developer or a coding agent. Read Ask before you change these before you change code.

Read first: Migrate to the unified events schema holds the mapping tables this page assumes. This page adds only what's specific to Android. The old value to new value pairs are only on that page, so don't change code from this page alone.

API reference: Android

Before you start

  • Wait for the SDK version. The unified schema ships in Android 2.0.x. Don't start the code changes until you're upgrading to that line.
  • Accept both schema versions. Your pipeline needs to accept api_scheme_version "2" and "2.1" while older SDK versions in the field still emit legacy events.
  • Nothing is aliased. Old names aren't mapped to new ones anywhere in the SDK, so anything you miss goes silent rather than failing.
  • The full list of properties on each event isn't published yet. Treat a mapping that isn't listed as unknown, not as unchanged. Don't run this as an unattended automated pass.
  • React Native and Flutter wrappers forward raw JSON, so the payload changes reach them unchanged. Their typed layers need the same mapping as native Kotlin.

Ask before you change these

Don't make these changes without a person. The mapping tables say what the payload does now, not what your app should do about it. Compile-break rows in Fix what stops compiling are in scope. Rows below are not, even when they fail the build. Don't map a removed event to the nearest surviving case to make when compile.

ChangeWhy a person decides
story_completedIt now means one Story finished, not a completed playlist. Code that treated it as playlist completion needs remaining_unread_count = 0, which is a logic change.
Removed events with no replacementForced play and pause, and cta_dismissed, are gone. Dropping the feature that depended on them is a product decision. search_suggestions_shown is gone. For suggestion click-through, count search_suggestions_clicked against search_opened.
Call to action metricscta_shown counts once per start rather than once per appearance, so thresholds and rates built on the old counting need rebasing.
Search attributionSearch identifiers ride every player event in the session, so counting logic has to move to unique search_session_id.
Cross-platform comparisons around shareThe extra background pair on Android is by design, so reconciling it is an analysis decision.

Step 1: Find the affected code

The result of this step is a list of files to change, not a change.

  1. Search your app for each string in the table below.
  2. Search each Legacy cell in Migrate to the unified events schema: value remap, exit triggers, start triggers, renamed events, removed events, removed properties, and renamed properties.
  3. Search your dashboards, saved segments, and warehouse queries for the same strings. Code and reporting break independently, and reporting breaks silently.

The compiler won't catch string reads. Comparing eventAction.value, a category value, or a property name against a string literal keeps compiling and silently sees a different value. Review those by hand.

Search forWhy it matters
onEventTriggeredHandlers that read the payload
event_category, event_actionCode that branches on event identity
.value on an analytics enumString reads the compiler can't check
EventActionName, EventCategoryTypeEnums with deleted and lowercased entries
AnalyticsPropsContainer, AnalyticsGeo, AnalyticsPage, AnalyticsWscInternal, PlaybackActionMethodRemoved types
playback_play, playback_pause, ad_playback_play, ad_playback_pauseRenamed events
container_data_load, search_click, video_orientation_changedRenamed events
forced_playback_play, forced_playback_pauseRemoved, no replacement. Report the call site. See Ask before you change these.
cta_visible, cta_dismissedRemoved. cta_dismissed has no replacement. See Ask before.
moments_playlist_start, moments_playlist_exit, casting_started, casting_ended, pip_enabled, pip_disabledRemoved events
search_suggestions_shownRemoved. For suggestion click-through, count search_suggestions_clicked against search_opened. See Ask before.
Stories completed, Moments Container, Swipe DownValues that don't recase 1:1. See the shared trigger tables.
current_mode, next_modeReplaced by a single viewing_mode string
origin_widget_id, labels_expression, container_idMoved referring and tab fields
next_video_id with a trailing spaceThe legacy key is fixed, so remove any workaround
Title Case string literals compared against property valuesSearch the Legacy column of the shared value remap. Don't recase and assume a match.

Step 2: Fix what stops compiling

There are no deprecation shims. An exhaustive when that stops compiling is the signal that an event you depended on is gone. If a compile error matches Ask before you change these, stop and report it.

New types you'll need to handle: AnalyticsPropsTab, AnalyticsCtaConfig, AnalyticsCustomActionButtonConfig, AnalyticsLoopSettings, AnalyticsFollowedEntity, BlazeBackToLiveTrigger, TabTransitionMethod, and AnalyticsOriginNode.

There's no widget or container identifier change on Android. Widget and container IDs were already required constructor inputs, so the iOS widgetIdentifier and containerIdentifier break has no Android counterpart. The values still need to be stable placement labels, because widget metrics are grouped by them. Don't invent a new label as part of this migration.

ChangeWhat to do
Deleted EventActionName entriesHandle the removals listed in the shared reference. An exhaustive when won't compile until you do.
EventCategoryType is lowercased and extendedHandle the new tab and global categories.
AnalyticsPropsContainer is removedUse AnalyticsPropsTab.
AnalyticsGeo, AnalyticsPage, AnalyticsWscInternal are removedDelete the code that read them. They were always empty.
PlaybackActionMethod is removedNo replacement. Anything referencing the type, not just the property, stops compiling.
AnalyticsPropsAd is reshapedRead the unified content_id and content_title. playback_action_method is gone from ad properties too.
video.viewing_mode is a single stringReplace uses of current_mode and next_mode. On viewing_mode_transition it's the destination mode, and everywhere else it's the current mode.
moment_duration_viewed_percent and story_page_duration_viewed_percent are Double?Update the types that read them. They were Int?.

Step 3: Android data changes

These changes are specific to Android. The schema is the same on every platform, and what differs here is where Android reporting becomes more precise than it was. Nothing errors, so a report built on the previous behavior keeps running on the new numbers.

Values that report differently

What changedWhat it means for your numbers
Viewed percentage
  • moment_duration_viewed_percent and story_page_duration_viewed_percent used to report the playhead as a rounded integer.
  • A Viewer who watched to 40 %, backgrounded, resumed, and left at 70 % produced an exit reporting 70 for a segment of 30.
  • Exits now report the segment since the matching start, as a decimal truncated to two places.
  • Sum the segments of one session ID for total exposure.
stream_statusIt previously reported values such as LIVE. It now reports live, upcoming, and ended.
loop_number across a hide and showA navigation tab hide and show no longer increments the loop count.
moments_session_id on a tab returnReturning to a Moments tab re-embeds the player on Android. The session ID is now carried across the re-embed, matching iOS, where the return previously started a new session.
video_current_time on an auto-advanced startIt now reports the new video's position rather than the previous video's end position.
The loop and advance exitThe moment_exit describes the play that finished, carrying that loop's number, viewed_percent = 100, and navigation_type = automatic. It previously described the loop that had already started.
Tab switch event orderThe order is tab_transition, then the outgoing moment_exit with focus_lost, then the incoming moment_start. Viewed percentage is captured at the switch instant.

Android-only notes

BehaviorWhat it means
The system share chooser takes your app out of the foreground
  • The chooser is another package's activity, so a share reports moment_exit with app_background and moment_start with app_foreground around it.
  • The iOS share sheet produces neither.
  • Expect one extra background pair per share on Android when you compare session counts across platforms.
A session is process lifetimeThere's no session rotation on Android, which matters for the once-per-session load events.
Device fields are captured synchronouslyNothing to migrate. The iOS note about tech fields briefly reporting unknown doesn't apply here.
from_tab_title, to_tab_title, and tab_navigation_typeNothing to migrate. These never existed on Android, and they're listed as removed because iOS sent them.

Step 4: Verify

  1. Confirm api_scheme_version reads 2.1 in the payloads your app receives.
  2. Confirm event_category values arrive lowercase, and that your handler covers tab and global.
  3. Confirm no handler still matches a legacy value. A handler that never fires is the failure mode here, so assert on a match rather than on the absence of errors.
  4. Confirm the properties you depend on are present on the events you read them from. A missing property means it doesn't apply to that event, not that it's null.
  5. On React Native and Flutter, confirm the typed layer maps the new names and values, not only that the raw JSON arrives.

Related


Did this page help you?