Mobile Development 10 min read

How Airbnb Instruments Android Apps to Capture User‑Centric Performance Metrics

Airbnb’s Android Page Performance Score (PPS) framework instruments fragments to collect user‑centric metrics such as TTFL, TTIL, MTH, ALT and RCLT, using a standardized logging config, LoadableView interface, and visibility algorithms, enabling detailed performance analysis and automated alerts for mobile teams.

Airbnb Technology Team
Airbnb Technology Team
Airbnb Technology Team
How Airbnb Instruments Android Apps to Capture User‑Centric Performance Metrics

Airbnb’s Page Performance Score (PPS) aggregates several user‑centric performance indicators into a single 0‑100 score. This summary describes the Android implementation of the PPS metrics.

Instrumentation Overview

Each page in the Airbnb app is represented by a Fragment. Engineers must supply a LoggingConfig that contains a unique page name drawn from a shared PageName enum, ensuring consistent identification across platforms.

// SearchFragment overrides loggingConfig with a unique PageName.
override fun loggingConfig() = LoggingConfig(
    pageName = PageName.SearchResults
)

Capturing User‑Perceived Wait Time

All views that can display a loading state implement the LoadableView interface, which defines setIsLoading(Boolean). A base helper observes changes to the loading flag and automatically logs PPS events.

// ALL views with a loading state must implement this interface and call setIsLoading.
interface LoadableView {
    fun setIsLoading(isLoading: Boolean)
}

// Abstract helper that tracks and logs the loading state of a view.
abstract class BaseLoadableViewHelper<out T : View>(protected val view: T) {
    // Observable property; logs a PPS event whenever the value changes.
    var isLoading by observable(initialValue = false) { _, oldValue, newValue ->
        logPpsLoadingEvent(view, oldValue, newValue)
    }
}

Because many loadable views reside inside RecyclerView, the framework caches visibility states and updates them only when necessary, avoiding per‑frame calculations.

Metric Implementations

First‑Paint Layout Time (TTFL)

TTFL measures the interval from fragment initialization to the first onGlobalLayout callback, i.e., when the view hierarchy has been measured, laid out, and rendered. Slow TTFL usually points to overly complex view hierarchies or heavy work on the UI thread during fragment startup.

Initial Load Time (TTIL)

TTIL records the time from fragment start until the loading indicator disappears, excluding separate media loading. For static or cached fragments TTIL equals TTFL. High TTIL suggests network latency, large payloads, missing caches, inefficient parsers, or sub‑optimal RecyclerView usage.

@Synchronized
private fun changeViewCounterForFragment(
    fragment: BaseFragment,
    loadingType: UiElementLoadingType
) {
    return when (loadingType) {
        UiElementLoadingType.Started -> {
            fragmentToLoadingMap[fragment]?.let {
                it.copy(viewCount = it.viewCount + 1)
            }
        }
        UiElementLoadingType.Ended -> {
            fragmentToLoadingMap[fragment]?.let {
                it.copy(viewCount = it.viewCount - 1)
            }
        }
    }
}

Main Thread Hang (MTH)

MTH is defined as any frame whose rendering time exceeds twice the device’s target refresh interval. The framework reads the device’s refresh rate via FrameMetrics, computes a hang threshold, and logs the excess duration whenever a frame surpasses that threshold.

Additional Load Time (ALT)

ALT measures waiting periods that occur after the initial load, such as pagination delays or the time between pressing a save button and seeing updated content. ALT starts when a view enters a loading state after TTIL and ends when the loading indicator disappears. Multiple ALT intervals can be recorded per screen.

Rich Content Load Time (RCLT)

RCLT tracks the time from when a placeholder or loading animation is shown until rich media (images, video, etc.) is fully displayed. ImageView and other rich‑media containers implement the same LoadableView API, reporting state changes to the PPS logger. Optimizations include reducing image size, improving caching, using efficient formats, and selecting high‑performance streaming libraries.

Conclusion

The Android PPS framework provides automated collection of richer, user‑centric performance metrics, enabling page‑owner alerts, systematic performance goal setting, and regression tracking. Future work includes finer‑grained measurements such as click‑response latency, better differentiation of scroll‑related performance, and built‑in optimization helpers.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

mobile developmentInstrumentationAndroidMetricsPerformance Monitoring
Airbnb Technology Team
Written by

Airbnb Technology Team

Official account of the Airbnb Technology Team, sharing Airbnb's tech innovations and real-world implementations, building a world where home is everywhere through technology.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.