chrome/browser/page_load_metrics/observers/README.md
Page load metrics can be tracked in chromium by implementing the
PageLoadMetricsObserver
interface, which provides callbacks that indicate when various paint, document,
and user interaction events happen during the course of a page load.
This document provides a detailed guide to implementing a PageLoadMetricsObserver.
For a quick introduction, you may wish to read the implementation basics
section below, browse the PageLoadMetricsObserverInterface,
and look over existing PageLoadMetricsObserver implementations.
You can refer to AssertPageLoadMetricsObserver for context and assumptions that callbacks can be rely on.
PageLoadMetricsObservers can track web vitals like time to Largest Contentful Paint and other per-page metrics such as time to first user input in UMA or UKM.
You can implement a PageLoadMetricsObserver to:
DataSaverSiteBreakdownMetricsObserverHttpsEngagementPageLoadMetricsObserverAndroidPageLoadMetricsObserver[TOC]
If you have additional questions or needs not covered in this document, please contact [email protected].
The rest of this document assumes familiarity with the page load lifecycle in Chrome. Key concepts are explained briefly here:
For more detailed information, see the comments in the navigation section of
WebContentsObserver,
as well as the navigation-related entries in
Truths and Not Truths.
Page load metrics are tracked by implementing the PageLoadMetricsObserver
interface. A new instance of each PageLoadMetricsObserver implementation is
instantiated for each page load. PageLoadMetricsObserver instances are created
and owned by the page load metrics infrastructure. A PageLoadMetricsObserver’s
lifetime starts when a main frame navigation is initiated, and ends when one of
the following cases is encountered:
WebContents (a WebContents is essentially a browser tab) is destroyedPageLoadMetricsObserver in question responds to the resulting OnEnterBackForwardCache callback with STOP_OBSERVING.PageLoadMetricsObserver lifetimes, for a WebContents with 3 page loadsAbove, we show example PageLoadMetricsObserver (PLMO) lifetimes for a
WebContents with three main-frame navigations, shown in blue, green, and
yellow, with time starting on the left, and ending on the right.
WebContents, in blue, is
instantiated when its navigation starts, and is destroyed when the next
navigation in the WebContents commits (the yellow load).WebContents is closed. The
commit of the yellow navigation causes the PLMO for the previously committed
load, in blue, to be destroyed.PageLoadMetricsObserver lifetimes within a WebContents often overlap. In
particular, if there is a committed load in a WebContents, the lifetime of its
associated PageLoadMetricsObserver overlaps with the lifetime of subsequent
navigations, for the period from the subsequent load’s navigation start until
the next navigation commits. We see this for the blue and yellow loads in the
example above.
PageLoadMetricsObserver callback life cyclePageLoadMetricsObserver (PLMO) implementation is instantiated when a
navigation starts. At this time, the OnStart callback is invoked.OnRedirect may be invoked one or more times, for each server-side redirect.
Note that content-triggered redirects, such as meta refreshes or a JS-based
navigations, are separate distinct page loads, and do not cause OnRedirect
to be invoked.OnCommit is invokedOnFailedProvisionalLoad is
invoked, and the PLMO is destroyed.OnComplete callback is invoked
just before the PLMO is destroyed (due to e.g. a new page load committing, the
associated WebContents being destroyed, etc).Returning to the example above, callbacks are invoked in the following order:
PageLoadMetricsObservers for the blue load are
instantiated, and OnStart is invoked on them.OnCommit is invoked for the blue load’s PLMOs.OnStart is invoked for them.OnFailedProvisionalLoad is invoked for the
green load’s PLMOs. PLMOs for the green navigation are then destroyed.OnStart is invoked on them.OnComplete is invoked for the blue load’s PLMOs.
OnCommit is then invoked for the yellow load’s PLMOs.OnComplete is invoked for the yellow load’s PLMOs.Additionally, the following callbacks may be invoked during the lifetime of a
PageLoadMetricsObserver:
OnHidden and OnShown are invoked as the associated WebContents is
hidden or shown (e.g. when the user switches tabs).FlushMetricsOnAppEnterBackground callback is invoked to signal to
observers that any metrics buffered in memory should be persisted. Once
FlushMetricsOnAppEnterBackground is invoked, the application may be killed
without subsequent notification. Note that FlushMetricsOnAppEnterBackground
may be invoked multiple times for a single page load if Chrome transitions
from the foreground to background to foreground to background without being
killed. Note that this callback is only invoked if the entire Chrome
application is backgrounded. It is not invoked if the user e.g. switches
between tabs within Chrome.OnLoadedResource is invoked as each resource on the page finishes loading.OnFirstContentfulPaint are invoked as
the associated page load timing events occur.OnUserInput is invoked as user input events are received.OnLoadingBehaviorObserved is invoked as certain page loading behaviors are
observed. See the section on loading behaviors below for additional information.OnEnterBackForwardCache is invoked if the page will enter the Back/Forward
cache. Observers may return STOP_OBSERVING from this callback if they do
not wish to continue logging after a page has entered the BFCache, and this
is the default implementation for PageLoadMetricsObserver (it will also
call OnComplete at this time).OnRestoreFromBackForwardCache is invoked when the page is restored from
the Back/Forward cache. This callback is invoked with a NavigationHandle
which will have a different navigation ID to the original page load's.
Whether metrics should be logged using this new navigation ID, or the
original page load's ID, depends on the desired interpretation of the
metrics.PageLoadMetricsObservers?Only provisional loads that meet the following criteria are tracked:
PageLoadMetricsObserver::ShouldObserveScheme().In addition, when a load commits, additional criteria are applied at commit time. Only page loads that meet the earlier provisional criteria, as well as the following criteria at commit time, are tracked after commit:
Note that the provisional criteria is applied again at commit time, as navigation attributes such as the URL may have changed between the time a provisional load is started and the time it commits.
Loads that finish and received HTTP response headers but did not commit do not
invoke the OnFailedProvisionalLoad callback. These are special case
navigations, such as downloads and HTTP 204/205 responses, which complete
successfully but do not result in a committed load.
If a page load is filtered due to the above criteria, no subsequent callbacks
will be invoked for the associated PageLoadMetricsObservers for that page load.
Because not every load meets the commit-time criteria, some
PageLoadMetricsObservers will see calls to OnStart and OnRedirect but no
other callbacks.
We intend to allow teams to add custom PageLoad UMA metrics that relax these
constraints as needed. For instance, we could add support for tracking just NTP
loads, or chrome:// URLs. If you are interested in tracking metrics using a
different set of constraints, please reach out to [email protected].
PageLoadMetricsEmbedder::RegisterObservers
method in page_load_metrics_initialize.cc.See https://chromium-review.googlesource.com/c/chromium/src/+/2294392 for an
example end-to-end change that adds a new PageLoadMetricsObserver.
By default, page loads that spend time in the background during the period between navigation start and an event occurring are not included in core page load metrics. Backgrounded pages are often throttled and thus their metrics can be less useful/actionable for understanding page load performance.
For instance, the PageLoad.PaintTiming.NavigationToFirstContentfulPaint UMA
only includes samples for page loads that were in the foreground for the entire
period from navigation to first contentful paint. Page loads that were in the
background for any period of time between navigation start and first contentful
paint are excluded.
Thus, it is recommended that observers not record samples for metrics that occur when a page load is in the background.
An observer that does not want to track any metrics for events that occur after
the page has been backgrounded can implement OnHidden to return STOP_OBSERVING,
and OnStart to return STOP_OBSERVING if the started_in_foreground parameter
is false.
Observers that track some background metrics can determine if an event happened
completely in the foreground using the WasStartedInForegroundOptionalEventInForeground
method. See existing page load metrics observer implementations for examples.
Observers that wish to track metrics for pages that spend time in the background
can log metrics for those cases by checking that
WasStartedInForegroundOptionalEventInForeground returns false, and using a
separate histogram with a .Background suffix. For example,
PageLoad.PaintTiming.NavigationToFirstContentfulPaint.Background includes page
loads that were in the background at some point in time between navigation start
and first contentful paint. In practice, we have not found .Background
histograms to be very useful, other than to track the percentage of page loads
that spend time in the background. Observers are discouraged from logging
background histograms unless there is a clear reason to do so.
Most observers add their histograms under the PageLoad.Clients.* prefix. For
example, PageLoad.Clients.DataReductionProxy.PaintTiming.NavigationToFirstContentfulPaint
tracks PageLoad.PaintTiming.NavigationToFirstContentfulPaint for the subset of
page loads loaded through the data reduction proxy. It is recommended that
observers add metrics under PageLoad.Clients, as this allows other UMA users
to more easily discover these metrics while browsing metrics with the
PageLoad.* prefix.
If your metrics are not likely to be useful to other UMA users interested in page load metrics, you may wish to use a different naming scheme for your metrics. If you have questions, reach out to [email protected].
On the Android platform, once the Chrome application goes into the background,
it may be killed without subsequent notification. To avoid data loss, observers
that buffer metric information in memory may wish to implement the
FlushMetricsOnAppEnterBackground callback to persist metrics when Chrome goes
into the background.
Considerations
OnComplete callback should consider also
implementing the FlushMetricsOnAppEnterBackground callback.FlushMetricsOnAppEnterBackground may also receive
an OnComplete callback.FlushMetricsOnAppEnterBackground may be invoked multiple times for a single
page load if Chrome transitions from the foreground to background to foreground
to background without being killed.PageLoadMetricsObserver examplesObservers that wish to avoid tracking metrics for some page loads can do so by
returning ObservePolicy::STOP_OBSERVING from observer callbacks that return an
ObservePolicy. For example, an observer that wishes to only track metrics for
page loads that match certain criteria at commit, such as the hostname of the
committed URL, can implement the OnCommit callback. If an observer returns
STOP_OBSERVING, no subsequent callbacks will be invoked on the observer.
SignedExchangePageLoadMetricsObserver is an observer that performs page load filtering in the OnCommit callback, tracking only page loads for signed exchanges.
Considerations
PageLoadMetricsObservers that want to track pages with certain attributes known in Blink, for example, whether the page is service worker controlled or whether the page loaded a parser blocking script inserted via document.write, can do so using loading behaviors in the WebLoadingBehaviorFlag Blink public enum.
To track pages with a certain loading behavior, a PageLoadMetricsObserver can implement the OnLoadingBehaviorObserved callback, or check the metadata.behavior_flags field of the PageLoadExtraInfo structure that is passed to various PageLoadMetricsObserver callbacks.
ServiceWorkerPageLoadMetricsObserver is an observer that tracks metrics for page loads that are controlled by a service worker, as indicated by the WebLoadingBehaviorServiceWorkerControlled loading behavior flag.
Considerations
WebLoadingBehaviorDocumentWriteBlock loading behavior may be observed after first contentful paint occurs.OnLoadingBehaviorObserved callback.OnLoadingBehaviorObserved. DocumentWritePageLoadMetricsObserver is an observer that uses this logging strategy.If your observer wants to track a new loading behavior, you can add it to the WebLoadingBehaviorFlag enum and add instrumentation in Blink to notify the page load metrics infrastructure when the new loading behavior is observed. See the changes to FrameLoader.cpp in this change for an example change that adds instrumentation to track a new loading behavior.
Observers can track aborted page loads. A page load abort occurs when some event occurs that causes the page load to be terminated. Note that page load abort tracking is somewhat experimental and is subject to change.
Aborts can occur before or after commit. Observers can track aborts that happen before commit by implementing the OnFailedProvisionalLoad callback, and aborts that happen after commit by implementing the OnComplete callback. The current convention is to log aborts that occur before commit using the .BeforeCommit histogram suffix, and after commit using a suffix such as .AfterCommit.BeforePaint.
To determine whether an abort occurred, observers can use the PageLoadMetricsObserverDelegate API with the page_load_metrics::GetPageAbortInfo utility function. Observers should check whether the reason field of the PageAbortInfo structure has a value other than ABORT_NONE. The time until the page load was aborted is available in the time_to_abort field of the PageAbortInfo structure.
Some observer implementers may wish to track statistics aggregated across multiple page loads. Since a PageLoadMetricsObserver’s lifetime is bound to a single page load, a separate object with a longer lifetime must be used to track these statistics.
HttpsEngagementPageLoadMetricsObserver is an observer that tracks statistics aggregated across page loads. The observer forwards information about a page load to the HttpsEngagementService, which is responsible for aggregating statistics and logging aggregated metrics.