The Right Stuff: Breaking the PageSpeed Barrier with Bootstrap
by November 18, 2013

Filed under: Performance Monitoring

AppNeta no longer blogs on DevOps topics like this one.

Feel free to enjoy it, and check out what we can do for monitoring end user experience of the apps you use to drive your business at

I recently had the pleasure to listen to Ilya Grigorik give a talk at Velocity in NYC on Breaking the 1000ms Mobile Barrier. During the talk, Ilya used PageSpeed Insights to demonstrate that several high profile websites had overlooked some very simple and common optimizations and resulted in poor PageSpeed scores. For the unfamiliar, Pagespeed Insights is a web based tool created by Google that analyzes the content of a web page, then generates suggestions to make that page faster.

After Ilya’s talk ended, I started to think more about why performance always seems to be an afterthought with developers. As I pondered this thought, I kept coming back to the following question:

How hard is it to get a perfect PageSpeed Insights score?

It can’t be that hard, right? Well…there is only one way to find out!

Breaking the PageSpeed Barrier

To answer this question, I’ve decided to keep things as simple as possible, yet realistic. So I selected the following constraints based on what I would consider to be a simple website:

  1. Use Amazon EC2 to host
  2. Use a m1.small instance running Ubuntu 12.04 64-bit
  3. Use Apache as a webserver with mod_pagespeed
  4. Use an off the shelf Bootstrap example that depends on external CSS
    and JS (including jQuery)
  5. Modify the Bootstrap example to add a single image (26kb in size)

I picked Apache over Nginx simply because I’m more familiar with setting it up and configuring it. I choose the Bootstrap example because I felt it is composed of the many elements you’ll find on a modern website. These elements include several exteral CSS and JS dependencies (3 CSS & 3 JS), a top oriented navigation bar, and a decent amount of content. Plus, Bootstrap is widely used across the web, so why not look at how we can make it faster?

Going the Distance

I broke the experiment into several steps, where I would:

  1. Get the current PageSpeed score
  2. Pick a single failed optimization from the list of suggested improvements
  3. Research and implement a change to overcome the failed optimization
  4. Rinse and repeat until success

Easy enough, so let’s get started!

1. Bootstrap off the shelf

Let’s begin by generating a PageSpeed score from the off the shelf Bootstrap example. This will act as a baseline for the rest of the test.


Mobile Score

Desktop Score


Bootstrap off the shelf 77 90 833 ms

So it seems Bootstrap scores much better in desktop then mobile, along with a DOMContentLoaded of 833ms. Not to shabby to start off with, so let’s see how we can improve.

2. Enable mod_pagespeed

UPDATE: Below is a mod_pagespeed configuration that will get you a perfect PageSpeed score for this Bootstrap example (without any manual work)! A big thanks to all the folks at Google for providing feedback to this article (read the original discussions here and here)!

    ModPageSpeed on
    ModPagespeedRewriteLevel CoreFilters
    ModPagespeedEnableFilters prioritize_critical_css
    ModPagespeedEnableFilters defer_javascript
    ModPagespeedEnableFilters sprite_images
    ModPagespeedEnableFilters convert_png_to_jpeg,convert_jpeg_to_webp
    ModPagespeedEnableFilters collapse_whitespace,remove_comments

For the first optimization, we’re simply going to enable the Apache PageSpeed module and let it do all the hard work for us! Well think again, because enabling PageSpeed with its default set of filters only gives a boost of 3 points for both mobile and desktop.




Mobile Score

Desktop Score


Enable mod_pagespeed 80 93 660 ms


Not much score improvement, but mod_pagespeed did automatically concatenate all our CSS and apply cache control to both CSS and JS, so that’s kind of nice.

It looks like we’re gonna have to get under the hood and get our hands dirty with some good old manual optimizations. So let’s start with some low hanging fruit.

3. Minify CSS

Bootstrap fortunately ships with minified copies of most of it’s CSS, with the exception of theme.css. So we’ll be using the trusty old yuicompressor to get the job done!

$ cp bower_components/bootstrap/dist/css/bootstrap.min.css app/styles/
$ cp bower_components/bootstrap/dist/css/bootstrap-theme.min.css app/styles/
$ yui-compressor app/styles/theme.css -o app/styles/theme.min.css


Mobile Score

Desktop Score


Minify CSS 80 94 843 ms

This change is very straightforward, but doesn’t yield many points. So let’s continue onto the next one.

Enter The Fold

Welcome to The Fold. No not the band, but that imaginary line in a website that divides the top 600 pixels of content a user first sees from the rest of the content they will eventually scroll to.


In the world of The Fold, anything “below the fold” is considered a second-class citizen. And according to Google, things below the fold need to be eliminated from blocking our need for speed.

So optimizing for above the fold is basically:

  1. Prioritize the delivery of any content that is “above the fold”. This ensures the minimal amount of time for content to be rendered in the browser, and ultimately should make users happy.
  2. Defer everything else, especially anything that will block rendering for “below the fold” content.

Let’s get started, shall we?

4. Remove render-blocking Javascript

After reading over Google’s recommendations for removing render-blocking Javascript, it’s clear that we have way to much Javascript to simply inline it all, so we will have to use their inline Javascript snippet to defer the loading.

Immediately, there is a problem. If I defer the loading of all the Javascript files, how can I guarantee that they are loaded in order? Both holder.js and bootstrap.js have a dependency on jquery.js, and loading them out of order will result in broken Javascript. So I’m forced to manually concatenate (and minify) all the Javascript files before we defer the loading:

$ cat jquery.js bootstrap.js holder.js > all.js
$ yui-compressor all.js -o all.min.js
$ ls -alh
total 476K
drwxrwxr-x 2 ubuntu ubuntu 4.0K Nov 11 03:06 .
drwxrwxr-x 5 ubuntu ubuntu 4.0K Nov 11 02:58 ..
-rw-rw-r-- 1 ubuntu ubuntu 161K Nov 11 02:58 all.js
-rw-rw-r-- 1 ubuntu ubuntu 127K Nov 11 03:06 all.min.js
-rw-rw-r-- 1 ubuntu ubuntu  58K Nov  9 01:27 bootstrap.js
-rwxrwxr-x 1 ubuntu ubuntu  13K Nov  9 01:26 holder.js
-rw-rw-r-- 1 ubuntu ubuntu 2.4K Nov  9 01:25 html5shiv.js
-rw-rw-r-- 1 ubuntu ubuntu  91K Nov  9 01:26 jquery.js
-rw-rw-r-- 1 ubuntu ubuntu 4.0K Nov  9 01:25 respond.min.js

Now we simply include the defer loading snippet into our HTML and see what happens…


Mobile Score

Desktop Score


Remove render blocking JS 91 98 286 ms


Not only did our scores jump considerably, but our time to first render (DOMContentLoaded) has improved significantly! However, it looks like defer loading has some side effects, so let’s dig deeper.

5. Leverage browser caching

As a side effect of deferring the loading of Javascript, we are no longer getting the automagic browser caching from mod_pagespeed. So sounds like we need to get a bit hands on with Apache.


  • The HTML Boilerplate has a fantastic example of expires headers for
    cache control.
  • Make sure you’re using a cache busting file name scheme so users
    get served new files.
  • You should also read this article by Steve Souders.


Mobile Score

Desktop Score


Leverage browser caching 92 98 231 ms


Only a slight score improvement in mobile, but we’re now tied with Google’s PageSpeed score!

6. Optimize CSS Delivery

Unfortunately, none of Google’s suggestions would help us out much here. So now the only thing left is to remove render blocking CSS.

To frame the situation, external CSS is network bound and the network is slow. Thus, we want to remove this dependency so we can render our above the fold content as fast as possible.

To overcome this hurdle, we’re going to attempt to leverage an extremely experimental technique I learned from Addy Osmani and Paul Kinlan that goes something like this:

  1. Run a Javascript bookmarklet to detect and list CSS that is “above the
  2. Inline the “above the fold” CSS directly into the HTML
  3. Defer loading the rest of the “below the fold” CSS using a simple, yet
    not cross browser compatible solution by Paul Irish

NOTE: For more technical detail on this method, visit the links below:

Like before, let’s concatenate all our CSS, minify and see what happens.

$ cat bootstrap.css bootstrap-theme.css theme.css > all.css
$ yui-compressor all.css -o all.min.css
$ ls -alh
total 516K
drwxrwxr-x 2 ubuntu ubuntu 4.0K Nov 11 04:31 .
drwxrwxr-x 5 ubuntu ubuntu 4.0K Nov 11 04:29 ..
-rw-rw-r-- 1 ubuntu ubuntu 134K Nov 11 04:31 all.css
-rw-rw-r-- 1 ubuntu ubuntu 110K Nov 11 04:31 all.min.css
-rw-rw-r-- 1 ubuntu ubuntu 118K Nov  9 01:24 bootstrap.css
-rw-rw-r-- 1 ubuntu ubuntu  96K Nov 11 02:21 bootstrap.min.css
-rw-rw-r-- 1 ubuntu ubuntu  17K Nov  9 01:24 bootstrap-theme.css
-rw-rw-r-- 1 ubuntu ubuntu  15K Nov 11 02:21 bootstrap-theme.min.css
-rw-rw-r-- 1 ubuntu ubuntu  199 Nov  9 01:23 theme.css
-rw-rw-r-- 1 ubuntu ubuntu  158 Nov 11 02:24 theme.min.css



Mobile Score

Desktop Score


Remove render blocking CSS 100 100 151 ms

Did you hear the sonic boom?




Mobile Score

Desktop Score


1 Bootstrap off the shelf 77 90 833 ms
2 Enable mod_pagespeed 80 93 660 ms
3 Minify CSS 80 94 843 ms
4 Remove render blocking JS 91 98 286 ms
5 Leverage browser caching 92 98 231 ms
6 Remove render blocking CSS 100 100 151 ms

For the given constraints of this experiment, I have been able to achieve a perfect PageSpeed score. Over the course of this experiment, I’ve made the following observations:

  • PageSpeed optimizations directly result in an improved time to first render. This can have a significant impact for a mobile site.
  • Only installing mod_pagespeed is not enough. If anything, it’s only the beginning when it comes to tuning performance for your website. It offers an impressive list of configurable filters that you should read about.
  • Asset concatenation is useful for reducing the number of HTTP requests, DNS lookups, and overall round trip times (RTT).
  • Asset minfication is a must and it’s useful for reducing payload size.
  • Browser caching is a must. Seriously, do it.
  • The defer loading for Javascript seems safe to use. However, further experimentation is necessary to determine its effects on Javascript heavy sites, especially those that are built with Javascript MVC frameworks.
  • The defer loading for CSS is definitely not “production ready” and still needs considerable improvement.
  • Implementing any optimization should always be weighed against the many established web performance best practices.

Finally, I can’t help but think there are further improvements that can be made to my solutions. Thus, I’d like to encourage further discussion on this topic by ending on the following question:

How many of my “solutions” are actually anti-patterns? If so, how can they be improved?

Want to read more about what all this actually means to your users? Check out my post on client latency!

  • Kas Marynick

    I’m a beginner, completely untrained and this article was very helpful! Thanks!

    • @kasmarynick:disqus, glad you found the article helpful!

  • I love the way u implemented all the suggestions Pagespeed Insights suggested. Iam looking forward to do the same in my website 🙂

  • neotrope

    Thanks for this. I’ve been suffering with optimizing a custom framework built on Bootstrap 2.32 plus custom menu CSS, plus custom styles. The “render blocking” CSS stuff is where the pain and suffering comes in. It’s the old “catch 22” of CSS holds up page loading, but ahem you need the CSS to build the page (sometimes the old tables method wasn’t quite so awful now was it peeps?). Having fun right now trying to inline stuff for the above the fold css. This article helped. THANKS. 🙂

  • AJ

    Hi, great post! Seems like lots of work.

    I am a beginner and thought implementing pagespeed module on my server would give me 100/100. I already have 90/100. My hosting told me I need at least a VPS, so I have just upgraded 🙁

    Now it seems there’s more work ahead – work that I cannot carry out myself 🙁

    Can you help or point me in the right direction? I am not sure what my score will be after installing pagespeed module but I am hoping on an improvement. Load time is around 508ms at the moment but if that can be as low as your test sight then great 🙂 🙂 🙂

    • Hey @AJ,

      As far as installing mod_pagespeed goes, there are packages available for Debian/Ubuntu and CentOS/Fedora. I’m not sure what disto your hosting company provides, but you can always compile from source as well.

      More instructions can be found on the mod_pagespeed website:

  • Twoopl

    Thank you for article, can you please make this study with Startup Framework?


    Very nice and helpful article, I post linkbacks to it everytime I have the opportunity to. Thanks for sharing such good job !

  • Super-mega-helpful post! Thanks.

    I’ve solved performance problems with:
    – customizing my bootstrap <<< VERY IMPORTANT!
    – using sprites (or some special html entities instead of images)
    – a proper htaccess (bolierplate docet)
    – putting js at the bottom of the page

    • @marcopanichi:disqus, you’re welcome! glad you were able to improve performance =)

  • Tim

    Great, great article. Thank you.

    I have a question about the edit providing the mod_pagespeed configuration for a perfect score:

    Did it achieve the same awesome DOMContentLoad speed (151 ms) as your manual adjustments?

  • Vitalik Repin

    We’ve reached the 100% mobile devices Google Insight Score for by using this treek: We ensured static resources such images, styles and javascripts have proper HTTP headers to utilize browser cache.

  • harran_ali

    This is awesome
    You saved my life
    Thank you.

  • Vlad

    Really, all these things matter! I faced at one source (this one pnn soft
    ) that the page speed is slow, but the reason of this is not identified.
    Any suggestions?

    • Nick

      Your initial document load time is pretty terrible. It takes a whole second for the server to cough up the HTML.

      Part of the problem is that WordPress can be painfully slow, especially if you install a bunch of plugins. You can try to get PHP and the database to do its job faster, but for static non-personalized content (no login required, the same for every user) the answer is server side caching.

      Switch from Apache to Nginx and PHP-FPM. PHP-FPM will make PHP a little faster, but the real benefit is setting up Nginx with full page caching for pages with static content, so PHP and WordPress don’t even have to execute 99% of the time. Nginx also opens up the door to load balancing and horizontal scaling if/when traffic picks up.

      This will require full control of the server, so you can’t use shared hosting. You need at least a VPS instance where you can get root/sudo access to the server, but the difference is astounding.

      If you can’t figure this out on your own, I think managed services like Rackspace can do it for you.

  • did you made any changes on your setting recently.. I can see your pagespeed is decrease to 79-80 around.. if so, wonder how long did you use mod_pagespeed and if there is noticeable improvement in any particular area?

  • Ole e ole

    helpful article.
    After searching the internet for the best solution I have already done a page optimisation with green result also. Caching, compressing page and resources, delaying what could be delayed is the solution. So anybody who want to give a job to me let me know –

  • Great and informative post.

    I also always use GTmetrix to test my speed sites to compare with PageSpeed.

    I also recommend instead of installing a plugin enabled gzip compression
    directly on the server if the provider has enabled this or if I have a
    VPS which is what I normally use.

    Some rules in .htaccess also help.

  • jemois5

    You could detect the critical css with and then copy/paste it i to the head of the page.

  • PenguinWhispererThe .

    Very nice article. Most other sites are hiden marketing but don’t bring any real information. Thanks for writing such a useful post.

  • This is a cool post. A lot of usefull information. Thanks a lot Dan.

  • This is exactly what I need. Step by step solutions and results that come with them. Thanks!

  • Miroslav Mki Cibuľa

    Hi, is css for “remove render blocking” same for bootstrap 4 ?

  • Trésor Story

    please can you give me the code and tell me where I can put it .I am intermediate .thank you.