Improving Our Website Performance Using Chrome DevTools and Raygun

Over the past eight months, we've been pushing hard, creating as many pages as possible for our site at Raygun.com. As we added and replaced more and more pages, I became curious about the potential site performance impact.

As we already had a Real User Monitoring tool setup on the website, I figured I should take a look at the performance section to check metrics like page load speed and average load time.

After taking a look at our performance dashboard, I could see that we had room for improvement. Our average load time was 5.21s. After making some improvements, I was able to reduce the average load time by up to 31.3%.

In this article, I'll write about the steps I took to make these improvements, the benchmarks I took and the tools I used.

What triggered the performance investigation?

These were the initial stats that triggered me to look into some performance optimizations:

Initial stats

An average load time of 5.21s was a worry, we're aiming for 3s or less, so I decided to do something about it.

Measurement

Firstly, I needed to decide what I wanted to measure, this would be the basis of my tests and would define the success of our site performance improvements.

Using our Real User Monitoring tool, I wanted to measure the following:

  • Median load time: The Median response time is what half of your customers experience (or faster). This is important because performance makes money – 40% of users will leave a website that takes more than 3 seconds to load!
  • Average load time: The site's average page load time. It is measured by collecting load times at regular intervals across the date range. The load times are then added up and divided by the number of load times collected
  • P90 load time: Represents what 90% of your users will experience for load times
  • P99 load times: Medians are great, but we also need to appreciate the upper limit. I chose to track the P99 load time which is the time taken for slowest users of your site

Ideally, our changes will show improvements in all these metrics, however, my primary focus is on improving the Median and Average load times.

Using Chrome DevTools I wanted to measure the time taken for the DOM content to load and also the overall Load time of the page. The reason why I chose to measure both these values is for twofold:

  1. The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading
  2. The Load trigger fires once all the additional logic on the page is complete. An example would be JavaScript's .onLoad() function or jQuery's .ready(). The reason why I want to track this value is that it will match up with what Raygun reports back so we will see a correlation between the data

Success

Now that we have some metrics to base our measurements from, we now need to define success.

Reducing the overall page load time is my biggest goal. But, if I can also get improvements on the DOMContentLoaded time, this would ensure the best user experience for our users.

Browsers

Knowing what to measure is only the first step, now we need to decide in which environments to test our metrics. Thankfully our Real User Monitoring tool enables us to find out which browsers our users are using. After reviewing this, I can see that Chrome, Chrome Mobile, and Firefox are our top three browsers. These became the focus of the tests.

Browser stats

I've decided to test the following:

  • Chrome
  • Chrome with Fast 3G
  • Chrome with Slow 3G
  • Firefox
  • Firefox with Regular 3G

These environments should be enough to measure the improvements in multiple browsers and multiple devices.

Pages

The performance updates that I wanted to make would affect most pages on the website, but I had to decide which pages to measure. I decided to test two pages:

  1. Our homepage (/) – as this is the first page new users will see when they visit the site. Your homepage should be as fast as possible to ensure a good first impression
  2. The new Javascript language page (/languages/javascript) – as was a recently created page that needed optimizing

Baseline

Before making any performance improvements, I needed to get some baseline figures to compare my improvements. To make the measurements more reliable I decided to take each measurement multiple times with the cache disabled, then take the median of each metric and use that as the baseline.

My initial tests gave me the following results for my two pages:

Chrome

HomepageJS Language page
DOM content loadLoadDOM content loadLoad
2.974.323.364.52
2.373.713.394.77
2.353.243.654.54
2.74.043.264.6
2.483.823.284.19
Median2.5743.8263.3884.524

Chrome with Fast 3G

HomepageJS Language page
DOM content loadLoadDOM content loadLoad
6.99.218.8712.34
6.299.788.9411.25
6.288.588.912.37
Median6.499.198.90333333311.98666667

Chrome with Slow 3G

HomepageJS Language page
DOM content loadLoadDOM content loadLoad
23.2336.4931.7841.21
22.4831.5831.5943.78
21.9534.1332.4240.55
Median22.5533333334.0666666731.9341.84666667

Firefox

HomepageJS Language page
DOM content loadLoadDOM content loadLoad
1.163.781.853.55
1.723.72.54.37
1.914.022.363.75
Median1.5966666673.8333333332.2366666673.89

Firefox With Regular 3G

HomepageJS Language page
DOM content loadLoadDOM content loadLoad
2.238.383.0913.34
2.178.663.0513.5
Median2.28.523.0713.42

Performance Improvements

Now that we have our baseline figures for our tests we can now get started on our performance updates. Using Raygun's Insights feature, I was able to easily see what needed improvement with additional information on how to fix it.

The first thing I noticed was the that we weren't properly caching static assets on the website. Our site is built in ASP.NET, so this was just a matter of updating the Web.config file so that it includes the <clientCache> element inside the <staticContent> element. I could then assign how long I wanted the assets to be cached for, along with what mode you want to use. I added the following snippet to our <staticContent> element to make our static assets stay alive for seven days, for more information you can check out the documentation here.

To test that the asset caching is working as expected, I opened up the network tab inside Chrome DevTools then loaded up the homepage. I selected an image and took a look at the response headers.

DevTools Network tab

As you can see, we have the Cache-Control set to max-age=604800.

If you do the math, 604800s / 60 / 60 / 24 = 7 days, the calculation seemed to match the values I set in the <clientCache> element, so I could move on to our next improvement.

Adding Font Files

The next thing I noticed was that all our fonts were loaded in via the Google Fonts API. Serving these locally will reduce the amount of network traffic and improve page load speed (note: this depends on how fast your server is).

As an added benefit, if for some reason the fonts.googleapis.com API went down, our font files would still get served. Localizing font files can be tedious, but thankfully there are some great open source tools out there to automate some of the processes for us.

I used the Google webfonts helper tool, but there are many others out there similar to this, such as this bash script coded by Clemens Lang.

After adding the font files and @font-face styles to the solution and running grunt, I needed to test that my changes worked. I loaded up my local version of the homepage and the current production version of our homepage and did a side by side comparison. I then checked the console to make sure there were no 404 errors.

Localize the run_prettify.js Script

My last change was to localize the run_prettify.js script that we use to style our code snippets.

Previously, this was loaded in via the rawgit CDN so localizing it was a straightforward process. I visited the CDN URL and saved the file to my computer, added it to the project solution, and updated the run_prettify.js references.

To test this, I loaded up one of our documentation pages and checked to see if there were any errors in the console and if the styles still worked.

JavaScript snippet for rg4js

Testing Improvements

Now that I've made the changes, it's time to test them and see what the results look like and if we have improved our site performance overall.

I took the same amount of measurements for our second test, I then compared the median load times before and after, which would reveal the improvements gained.

Here are the figures I got back from my second round of tests with the cache disabled:

Chrome

HomepageJS Language page
DOM content loadLoadDOM content loadLoad
2.263.183.364.26
2.273.193.364.26
2.273.173.394.28
2.443.343.424.32
2.493.413.444.33
Median2.3463.2583.3944.29

Chrome With Fast 3G

HomepageJS Language page
DOM content loadLoadDOM content loadLoad
6.388.79.2911.61
6.338.649.1311.45
6.318.629.3711.67
Median6.348.6533333339.26333333311.57666667

Chrome With Slow 3G

HomepageJS Language page
DOM content loadLoadDOM content loadLoad
23.631.7632.3441.93
23.7231.8932.3641.77
23.6731.8532.1641.73
Median23.6633333331.8333333332.2866666741.81

Firefox

HomepageJS Language page
DOM content loadLoadDOM content loadLoad
12.881.422.73
1.143.221.673.12
1.153.071.712.75
Median1.0966666673.0566666671.62.866666667

Firefox With Regular 3G

HomepageJS Language page
DOM content loadLoadDOM content loadLoad
1.947.882.8512.77
1.957.912.0612.45
Median1.9457.8952.45512.61

With this second round of tests, I also wanted to test the speed improvements gained from enabling caching of static content. So, I decided to also get some figures with the cache enabled.

Unfortunately, because I didn't take measurements from before with the cache enabled we aren't going to see accurate comparisons but at least this will give me a rough idea on the impact adding <clientCache> to our Web.config file had on our website.

Here are the figures I got back from my second round of tests with the cache enabled:

Chrome

HomepageJS Language page
DOM content loadLoad
1.031.45
1.051.57
1.081.58
1.262.28
1.361.64
Median1.1561.704

Chrome With Fast 3G

HomepageJS Language page
DOM content loadLoad
1.452.77

Chrome With Slow 3G

HomepageJS Language page
DOM content loadLoad
2.845.65

Comparisons

Now that we have taken our measurements we can now compare both sets of data. I'm looking for exactly how much faster we have made these pages.

Chrome

HomepageJS Language page
DOM content loadLoad
Before2.5743.826
After2.3463.258
Speed Improvement %8.86%14.85%

With Cache Enabled

HomepageJS Language page
DOM content loadLoad
Before2.5743.826
After1.1561.704
Speed Improvement %55.09%55.46%

Page Speed in Chrome With Fast 3G

HomepageJS Language page
DOM content loadLoad
Before6.499.19
After6.348.653333333
Speed Improvement %2.31%5.84%

With Cache Enabled

HomepageJS Language page
DOM content loadLoad
Before6.499.19
After1.452.77
Speed Improvement %77.66%69.86%

Chrome With Slow 3G

HomepageJS Language page
DOM content loadLoad
Before22.5533333334.06666667
After23.6633333331.83333333
Speed Improvement %-4.92%6.56%

With Cache Enabled

HomepageJS Language page
DOM content loadLoad
Before6.499.19
After1.452.77
Speed Improvement %77.66%69.86%

Firefox

HomepageJS Language page
DOM content loadLoad
Before1.5966666673.833333333
After1.0966666673.056666667
Speed Improvement %31.32%20.26%

Firefox With Regular 3G

HomepageJS Language page
DOM content loadLoad
Before2.28.52
After1.9457.895
Speed Improvement %11.59%7.34%

Summary

As you can see from the comparisons above, our site performance looks to have improvements!

The numbers that increased were likely caused by the localization of assets (lesson learned!) and we see it only effects the DOM content load. So, basically when the browser is fetching all the required assets and rendering the page.

As for the numbers that decreased, our improvements had a more significant impact on Firefox compared to Chrome. Overall I noticed general speed improvements across all pages and devices.

Looking at the comparison of our cached pages, we see some pretty significant improvements. Seeing an average of 65% decrease in overall page load time is relatively substantial.

The page profiling tool in Chrome DevTools allowed me to break down the improvements and get more granular information. The results show improvements in almost all areas, as shown below:

Homepage

BeforeAfter

JS Language page

BeforeAfter

Note: Look at the individual metrics for comparison to exclude idle time

Wrap up

After making these changes, the two performance dashboards that represent the entire website show speed improvements across all measurements:

  • Median load time reduced by 25ms.
  • Average load time reduced by 90ms.
  • P90 load time reduced by 98ms.
  • P99 load time reduced by 20.13s.

Overall, I'm happy with the optimizations. However, there is still room for improvement and lessons learned along the way.

Next time, I plan to ensure image optimization on all pages. I'll also look at combining scripts, minification on all CSS and JavaScript assets, and making optimizations to the script and style order.


If you have any other recommendations for page optimizations, get in touch with me on Twitter and let me know what you think.