Monitoring Page Performance

Real User Monitoring page load waterfall

Performance metrics for views

RUM view events collect extensive performance metrics for every single page view. Datadog recommends analyzing the performance metrics in the following ways:

  • Dashboards: provides you with a high-level view of your application’s performance. For example, the out-of-the-box Performance Overview dashboard can be filtered on default attributes collected by RUM to surface issues impacting a subset of users. This dashboard can be cloned and customized to your specific needs. All RUM performance metrics can be used in dashboard queries.
  • RUM waterfall: accessible for every single RUM view event in the RUM Explorer, it lets you troubleshoot the performance of a specific page view. It shows how your website assets and resources, long tasks, and frontend errors affect performance for your end users, at the page level.

Core web vitals

Note:The core web vitals metrics are available in Datadog from the @datadog/browser-rum package v2.0.0+.

Google’s Core Web Vitals are a set of three metrics designed to monitor a site’s user experience. These metrics focus on giving you a view of load performance, interactivity, and visual stability. Each metric comes with guidance on the range of values that translate to good user experience. Datadog recommends monitoring the 75th percentile for these metrics.

Core Web Vitals summary visualization
MetricFocusDescriptionTarget value
Largest Contentful PaintLoad performanceMoment in the page load timeline in which the largest DOM object in the viewport (as in, visible on screen) is rendered.<2.5s
First Input DelayInteractivityTime elapsed between a user’s first interaction with the page and the browser’s response.<100ms
Cumulative Layout ShiftVisual stabilityQuantifies unexpected page movement due to dynamically loaded content (for example, third-party ads) where 0 means no shifts happening.<0.1

Notes:

  • First Input Delay and Largest Contentful Paint are not collected for pages opened in the background (for example, in a new tab or a window without focus).
  • Metrics collected from your real users page views can differ from those calculated for pages loaded in a fixed environment like Synthetics Browser tests.

All performance metrics

AttributeTypeDescription
view.time_spentnumber (ns)Time spent on the current view.
view.largest_contentful_paintnumber (ns)Moment in the page load timeline in which the largest DOM object in the viewport (as in, visible on screen) is rendered.
view.first_input_delaynumber (ns)Time elapsed between a user’s first interaction with the page and the browser’s response.
view.cumulative_layout_shiftnumberQuantifies unexpected page movement due to dynamically loaded content (for example, third-party ads) where 0 means no shifts happening.
view.loading_timenumber (ns)Time until the page is ready and no network request or DOM mutation is currently occurring. More info.
view.first_contentful_paintnumber (ns)Time when the browser first renders any text, image (including background images), non-white canvas, or SVG. For more information about browser rendering, see the w3c definition.
view.dom_interactivenumber (ns)The moment when the parser finishes its work on the main document. More info from the MDN documentation
view.dom_content_loadednumber (ns)Event fired when the initial HTML document is completely loaded and parsed, without waiting for non-render blocking stylesheets, images, and subframes to finish loading. More info from the MDN documentation.
view.dom_completenumber (ns)The page and all the subresources are ready. For the user, the loading spinner has stopped spinning. More info from the MDN documentation
view.load_eventnumber (ns)Event fired when the page is fully loaded. Usually a trigger for additional application logic. More info from the MDN documentation
view.error.countnumberCount of all errors collected for this view.
view.long_task.countnumberCount of all long tasks collected for this view.
view.resource.countnumberCount of all resources collected for this view.
view.action.countnumberCount of all actions collected for this view.

Monitoring single page applications (SPA)

For single page applications (SPAs), the RUM SDK differentiates between initial_load and route_change navigation with the loading_type attribute. If a click on your web page leads to a new page without a full refresh of the page, the RUM SDK starts a new view event with loading_type:route_change. RUM tracks page changes using the History API.

Datadog provides a unique performance metric, loading_time, which calculates the time needed for a page to load. This metric works for both initial_load and route_change navigation.

How loading time is calculated

To account for modern web applications, loading time watches for network requests and DOM mutations.

  • Initial Load: Loading Time is equal to whichever is longer:

    • The difference between navigationStart and loadEventEnd.
    • Or the difference between navigationStart and the first time the page has no activity. Read How page activity is calculated for details.
  • SPA Route Change: Loading Time is equal to the difference between the user click and the first time the page has no activity. Read How page activity is calculated for details.

How page activity is calculated

Whenever a navigation or a click occurs, the Browser RUM SDK tracks the page activity to estimate the time until the interface is stable again. The page is deemed to have activity by looking at network requests and DOM mutations. The page activity ends when there are no ongoing requests and no DOM mutation for more than 100ms. The page is determined to have no activity if no requests or DOM mutation occurred in 100ms.

The criteria of 100ms since last request or DOM mutation might not be an accurate determination of activity in the following scenarios:

  • The application collects analytics by sending requests to an API periodically or after every click.

  • The application uses “comet)” techniques (that is, streaming or long polling), and the request stays on hold for an indefinite time.

To improve the accuracy of activity determination in these cases, specify excludedActivityUrls, a list of resources for the Browser RUM SDK to exclude when computing the page activity:

DD_RUM.init({
    ...
    excludedActivityUrls: [
        // Exclude exact URLs
        'https://third-party-analytics-provider.com/endpoint',

        // Exclude any URL ending with /comet
        /\/comet$/
    ]
})

Hash SPA navigation

The RUM SDK automatically monitors frameworks that rely on hash (#) navigation. The SDK watches for HashChangeEvent and issues a new view. Events coming from an HTML anchor tag which do not affect the current view context are ignored.

Add your own performance timing

On top of RUM’s default performance timing, you may measure where your application is spending its time with greater flexibility. The addTiming API provides you with a simple way to add extra performance timing. For example, you can add a timing when your hero image has appeared:

<html>
  <body>
    <img onload="DD_RUM.addTiming('hero_image')" src="/path/to/img.png" />
  </body>
</html>

Or when users first scroll:

document.addEventListener("scroll", function handler() {
    //Remove the event listener so that it only triggers once
    document.removeEventListener("scroll", handler);
    DD_RUM.addTiming('first_scroll');
});

Once the timing is sent, the timing is accessible as @view.custom_timings.<timing_name>, for example: @view.custom_timings.first_scroll. You must create a measure before graphing it in RUM Analytics or in dashboards.

Note: For Single Page Applications, the addTiming API issues a timing relative to the start of the current RUM view. For example, if a user lands on your application (initial load), then goes on a different page after 5 seconds (route change) and finally triggers addTiming after 8 seconds, the timing will equal 8-5 = 3 seconds.

Further Reading