Navigation Timing API: How to Profile Page Loads Efficiently

Share this article

Page load time is one of the most important aspects of user experience on the web. When pages load too slowly, users quickly become frustrated and take their business elsewhere. Unfortunately, troubleshooting a slow page load is not typically a straightforward process because many factors contribute to the overall time. For example, a page’s load time can be influenced by the user’s browser, network conditions, server load, and application code, among other things. Thankfully, the Navigation Timing API can help us do so with ease. As a developer, methods for gathering data on these various factors has been limited in the past. For many developers, the JavaScript Date object has long been the standard for gathering performance data. For example, the following code measures load time by comparing timestamps once the page’s load event handler is invoked.

var start = new Date();

window.addEventListener("load", function() {
  var elapsed = (new Date()).getTime() - start.getTime();
}, false);
There are several problems with this approach. First, JavaScript time is notoriously inaccurate. Second, using the Date object introduces overhead and clutters the application code. Third, the Date object can only measure the execution time once the code is running in the browser. The Date object cannot provide any data regarding the page load process involving the server, network, etc.

Cue Navigation Timing API

In order to provide more accurate and comprehensive page load data, the W3C has proposed the Navigation Timing API. The proposed API provides more detailed timing information throughout the page load process. Unlike the Date object, the navigation timing API can provide measurements related to DNS lookup, TCP connection establishment, page redirects, time spent building the DOM, and various other metrics. Navigation timing is also built directly into the browser, meaning that no additional overhead is created.

Detecting Support

The Navigation Timing API is currently only supported in Internet Explorer 9+, Firefox, and Chrome. Therefore, support for the API should be detected before attempting to use it. The API is defined in the window object as “window.performance.timing”. The following function detects whether or not the API is supported.
function supportsNavigationTiming() {
  return !!(window.performance && window.performance.timing);
}

Recorded Events

The API records the time when numerous milestones in the page load process occur. Each of these events is stored as a property of the “window.performance.timing” object. The following list describes each event. If a given event does not occur (for example a page redirect), then its value is zero. Note: Mozilla claims that the events occur in this order.
  • navigationStart ― This represents the time immediately after the browser finishes prompting to unload the previous document. If there is no previous document, then “navigationStart” is equal to “fetchStart” (see next item). This is the beginning of the page load time as perceived by the user.
  • fetchStart ― “fetchStart” represents the time immediately before the browser begins searching for the URL. The search process involves checking application caches, or requesting the file from the server if it is not cached.
  • domainLookupStart ― The “domainLookupStart” value corresponds to the time immediately before the DNS lookup for the URL occurs. If no DNS lookup is required, then the value is the same as “fetchStart”.
  • domainLookupEnd ― This value represents the time immediately after the DNS lookup occurs. If a DNS lookup is not required, then the value is the same as “fetchStart”.
  • connectStart ― This denotes the time immediately before the browser connects to the server. This value is equal to “domainLookupEnd” if the URL is a cached or local resource.
  • connectEnd ― Once the connection to the server is established, the “connectEnd” time is set. If the URL is a cached or local resource, then this value is the same as “domainLookupEnd”.
  • secureConnectionStart ― If the HTTPS protocol is used, “secureConnectionStart” is set to the time immediately before the secure handshake begins. If the browser does not support HTTPS, this value should be undefined.
  • requestStart ― “requestStart” represents the time just before the browser sends the request for the URL. The API does not define a “requestEnd” value.
  • redirectStart ― “redirectStart” represents the start time of a URL fetch that initiates a redirect.
  • redirectEnd ― If any redirects exist, “redirectEnd” represents the time after the last byte of the last redirect response is received.
  • responseStart ― This corresponds to the time immediately after the browser receives the first byte of the response.
  • responseEnd ― This represents the time immediately after the browser receives the last byte of the response.
  • unloadEventStart ― This represents the time immediately before the previous document’s “unload” event is fired. If there is no previous document, or if the previous document is from a different origin, then this value is zero.
  • unloadEventEnd ― This represents the time immediately after the previous document’s “unload” event is fired. If there is no previous document, or if the previous document is from a different origin, then this value is zero. If there are any redirects that point to a different origin, then “unloadEventStart” and “unloadEventEnd” are both zero.
  • domLoading ― “domLoading” represents the time immediately before the “document.readyState” value is set to “loading”.
  • domInteractive ― “domInteractive” corresponds to the time immediately before the “document.readyState” value is set to “interactive”.
  • domContentLoadedEventStart ― This represents the time immediately before the DOMContentLoaded event is fired.
  • domContentLoadedEventEnd ― This represents the time immediately after the DOMContentLoaded event is fired.
  • domComplete ― The “domComplete” value represents the time immediately before the “document.readyState” value is set to “complete”.
  • loadEventStart ― This value represents the time immediately before the window’s load event is fired. If the event hasn’t been fired yet, the value is zero.
  • loadEventEnd ― This represents the time immediately after the window’s load event is fired.  If the event hasn’t been fired, or is still running, then the value is zero.
The Navigation Timing API also defines an interface for determining how a user landed on a particular page. The “window.performance” object also contains a “navigation” object, which contains two properties — “type” and “redirectCount”. The “type” property provides the method by which the user navigated to the current page. The following list describes the values that “type” can hold.
  • If the user navigates to a page by typing a URL, clicking a link, submitting a form, or through a script operation, then the value of “type” is zero.
  • If the user reloads/refreshes the page, then “type” is equal to one.
  • If the user navigates to a page via history (back or forward buttons), then “type” is equal to two.
  • For any other circumstances, “type” is equal to 255.
The “redirectCount” property contains the number of redirects taken to the current page. If no redirects occurred, or if any of the redirects were from a different origin, then “redirectCount” is zero. The following example shows how the navigation data is accessed.
var navigation = window.performance.navigation;
var navType = navigation.type;
var redirectCount = navigation.redirectCount;

Making Sense of the Data

The Navigation Timing API is useful for calculating certain components of page load time. For example, the time taken to perform a DNS lookup can be calculated by subtracting “timing.domainLookupStart” from “timing.domainLookupEnd”. The following example calculates several useful metrics. “userTime” corresponds to the total page load delay experienced by the user. The “dns” and “connection” variables represent the times taken to perform DNS lookup and connect to the server, respectively. The total time taken to send a request to the server and receive the response is stored in “requestTime”. Finally, the total time to complete the document fetch (including accessing any caches, etc.) is stored in “fetchTime”. Notice that the setTimeout() function is called from within the window load event handler. This ensures that the navigation timing data is not used until immediately after the load event finishes. If the timing data were to be accessed from the load event handler, the value of “timing.loadEventEnd” would be zero.
window.addEventListener("load", function() {
  setTimeout(function() {
    var timing = window.performance.timing;
    var userTime = timing.loadEventEnd - timing.navigationStart;
    var dns = timing.domainLookupEnd - timing.domainLookupStart;
    var connection = timing.connectEnd - timing.connectStart;
    var requestTime = timing.responseEnd - timing.requestStart;
    var fetchTime = timing.responseEnd - timing.fetchStart;

    // use timing data
  }, 0);
}, false);
The Navigation Timing API can be used in conjunction with Ajax calls to report actual user data back to a server. This is useful because it allows developers to see how the page behaves for users in the real world. The data can also be used to create a visualization of the page load process
. In fact, Google Analytics already incorporates navigation timing into its reports.

Things to Remember

  • The JavaScript Date object cannot accurately measure page load data because it has no knowledge of the request prior to running in the browser.
  • The Navigation Timing API is built directly into the browser, and provides more detailed timing measurements.
  • The API also tracks how users navigate to a page.
  • Navigation timing data can be sent to servers for analysis.

Frequently Asked Questions (FAQs) about Profiling Page Loads with the Navigation Timing API

What is the Navigation Timing API and how does it work?

The Navigation Timing API is a web standard that provides data which can be used to measure the performance of a web page. It works by capturing various timestamps during the loading of a web page, from the start of the navigation to the completion of the load event. These timestamps can then be used to calculate metrics such as page load time, time to first byte, and time to interactive.

How can I use the Navigation Timing API to profile page loads?

To use the Navigation Timing API to profile page loads, you can access the window.performance.timing object in your JavaScript code. This object contains properties that represent various timestamps during the loading of the current page. By subtracting these timestamps from each other, you can calculate various performance metrics.

What are some common metrics that can be calculated using the Navigation Timing API?

Some common metrics that can be calculated using the Navigation Timing API include page load time, time to first byte, time to interactive, and DNS lookup time. These metrics can provide valuable insights into the performance of your web page and help you identify areas for improvement.

Why is the Navigation Timing API not working in Chrome?

If the Navigation Timing API is not working in Chrome, it could be due to a number of reasons. One possible reason is that the API is not supported in the version of Chrome you are using. Another possible reason is that the window.performance.timing object is not available in the context where your code is running. You should check the browser compatibility and the context of your code to troubleshoot this issue.

How can I use the Navigation Timing API in different browsers?

The Navigation Timing API is a web standard and is supported in most modern browsers. However, the implementation of the API may vary slightly between different browsers. You should always check the browser compatibility and test your code in different browsers to ensure it works as expected.

What is the difference between the Navigation Timing API and the PerformanceNavigation interface?

The Navigation Timing API and the PerformanceNavigation interface are related but they serve different purposes. The Navigation Timing API provides data that can be used to measure the performance of a web page, while the PerformanceNavigation interface provides methods and properties that can be used to understand the type of navigation that caused the current page to load.

How can I use the Navigation Timing API to measure the time to first byte?

To measure the time to first byte using the Navigation Timing API, you can subtract the responseStart timestamp from the requestStart timestamp. This will give you the time it took for the first byte of the response to be received after the request was sent.

What is the type property in the PerformanceNavigation interface?

The type property in the PerformanceNavigation interface is an integer that represents the type of navigation that caused the current page to load. It can have one of three values: 0 for navigation triggered by clicking on a hyperlink, 1 for navigation triggered by reloading the page, and 2 for navigation triggered by moving forward or backward through the history.

How can I use the Navigation Timing API to measure the DNS lookup time?

To measure the DNS lookup time using the Navigation Timing API, you can subtract the domainLookupStart timestamp from the domainLookupEnd timestamp. This will give you the time it took for the DNS lookup to complete.

What is the unloadEventStart and unloadEventEnd in the Navigation Timing API?

The unloadEventStart and unloadEventEnd properties in the Navigation Timing API represent the timestamps when the previous document’s unload event started and ended, respectively. These properties can be used to measure the time it took for the previous document to unload.

Colin IhrigColin Ihrig
View Author

Colin Ihrig is a software engineer working primarily with Node.js. Colin is the author of Pro Node.js for Developers, and co-author of Full Stack JavaScript Development with MEAN. Colin is a member of the Node.js Technical Steering Committee, and a hapi core team member. Colin received his Bachelor of Science in Engineering, and Master of Science in Computer Engineering from the University of Pittsburgh in 2005 and 2008, respectively.

Intermediateux
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week