My previous post was a bit negative, ranting about slow sites. So, here are two websites that load in less than 5 seconds, on a bad mobile connection. Government sites in fact.

  • the responsive news-site of Norway’s national broadcaster.
  • the responsive site of the Norwegian tax administration.

As with the last test, I tested with 300Kbit down, 150Kbit up, 300ms latency. In Chrome, Chrome Canary (improved font-loading) and Chrome Canary with blocking of fonts and javascript.

The result: they are visually readable in less than five seconds, in all three cases.


Readable in less than five seconds: and

We can see the difference in the waterfalls. The news-site does 4 requests, the previously tested news-site ( does over 40. waterfall waterfall


The moral is the same as always. Few requests, JS as late as possible, and realize that web-fonts have a cost.

TLDR: Scroll down to see sites load 2-5 times faster when Javascript and web-fonts are disabled.

For many Norwegians, Easter holiday means going to a cabin in the mountains. Which means poor network speed. To see how modern sites full of Javascript and fonts work with slow connections, I started playing around with the fantastic tool

I configured a custom connection of 300Kbit down, 150Kbit up, and 300ms latency. That is worse than 3G, but far better than the GPRS/EDGE connection that many people still get in remote areas. I also checked the “mobile useragent / resolution” checkbox to render the sites in small resolutions.

I picked five sites:

  • as a reference, I assume they do it all right.
  • I know this site loads quite a bit of JS early in the page.
  • a norwegian financial newspaper that recently launched a new responsive site. I noticed they havd 500KB of fonts, and a bit of early JS.
  • Launched their responsive site a couple of years ago. A UI without much heavy graphics, should/could load fast.
  • Launched their responsive site 1.5 years ago with great success.

Edit: I also tested two norwegian sites that load really fast

And did three tests:

  1. Regular Chrome
  2. Chrome Canary
  3. Chrome canary and blocking all requests containing “.js, .woff, .ttf”.
Not bulletproof, but seemed to work for these sites.

Not bulletproof, but seemed to work for these sites.

The idea with test 3 is to see how much faster these sites load if we strip away Javascript and fonts. Test 2 uses Chrome Canary, which will fallback to a system font if the web-font is not downloaded in three seconds.


You can see the results in the animated GIF below (0.5x speed). I know, the irony of using a 20MB GIF in a blogpost about performance…

Top: Chrome, Middle: Canary, Bottom: Canary with JS and fonts disabled. Click for larger image.

  • is readable in under 3 seconds in all cases.
  • is more than five times slower with Javascript. As far as I can tell, that is all the Javascript does.
  • is readable after 9 seconds with no fonts/js, vs 33 seconds with fonts/js. Chrome Canary helps by show the default-font in stead of nothing.
  • is readable after 12 seconds vs 26 seconds.  Note that this site uses https which adds a couple of seconds in webpagetest.
  • has a 400KB css file that for some reason is not gzipped, so it is pretty slow no matter what. Too bad. Still, disabling JS/fonts cuts 5 seconds of the loading time.

Putting Javascript at the bottom of the page when possible is one of the oldest performance rules, but still many new sites fail to do so. These sites doesn’t even need Javascript to for their main purpose. And while I understand that web-fonts is a good thing, do you really need half a megabyte of them? Following the almost eight year old performance-rules, and having a performance budget would have made these four sites load way faster.


tldr: Add this line in the head part of your html-page to do mobile webpages correctly:

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

Some facts I have learned the hard way:

  • If you do not set the viewport meta tag, iphone will report 980px width.
  • If you set width=600px, the devices will report just that: 600px.
  • If you set width=device-width, initial-scale= 0.5, the device will alter its reported with accordingly. So an iphone will say 640px, not 320px. (Yes, they report 320px even though the actual pixels is 640). An ipad will say 1536px, not 768px.
  • parameters are separated by comma (‘,’) not semicolon (‘;’), although most devices seem to accept both.

I’ve created a page for checking the values reported by CSS3 media selectors. You can also check out how the values are reported if you use initial-scale=0.5, or width=640.

Width reported on an iPad with initial-scale=0.5

Width reported on an iPad with initial-scale=0.5

Remember to check these out on a mobile device, as the viewport tag is ignored on desktop browsers.

I’m hosting in the Amazon Web Services US-EAST Region, which is located in Virginia. Since this region was partly down during a big storm this summer, I decided to move to Oregon before “Sandy” hit the east coast. In addition to avoiding potential downtime, this was something I wanted to test. How hard is it to move the whole site to another region? Without downtime.

The switch

The first step was to boot a new Ubuntu server and Mysql RDS server in Oregon. When I got the server-instances up and running in Oregon with an outdated copy of the database, it was time to do the switch. It went something like this:

  • Set in “read only” mode in Virginia.
  • Dump the database in Virginia to a file.
  • Import the file in Oregon.
  • Verify that the Oregon location (still) worked as expected.
  • Point the DNS entries to Oregon.

It can take some time before changes in dns propagate to all users, so people might hit the Virginia server some time after I switched the DNS-entry to Oreon. But since Tagdef is one of those read-intensive applications where many more people read than update, this would not affect most users.

Logging server traffic with Google Analytics

When the storm had passed, it was time to move back to Virginia. I have purchased reserved instances there, so it makes sense to continue to use that region for a while.

Since I really did not know how long the DNS-propagation took, I started logging the server-instance to Google Analytics using Non-Interaction Events.

Moving back from Oregon

By setting up custom segments in Google Analytics, it is easy to see when the switch happened, and that all the traffic was moved within an hour or two.

It’s also interesting to see the response time measured during the Oregon-switch. Since many of the servers that is used to measure uptime is located in Europe, the latency was increased when the servers were moved to the west-coast:


Since I had to set up the web-server from scratch, it cost me about three hours of labor. There are methods of moving a machine-image between regions, but it didn’t work for me.

The cost of the web-server, load balancer (for SSL termination) and database-instance running for two days: 12 dollars.

In June Google announced that Google Website Optimizer will be replaced by Google Analytics Content Experiments. With the new tool it seems hard to do a/b testing of dynamic websites, at least I haven’t figured out how to do it.

I use custom events in Google Analytics on Tagdef for various measurements, including the time spent by the server to generate the page. This event is a so called non-interaction-event, and is fired for every page.

Since you can create custom segments based on events, I decided to make my own poor man’s a/b-test:

  1. For each new visitor, assign by random if this should be the original page (a), or the modified version you want to test (b).
  2. Store this decision in a cookie, so the user gets the same experience on repeat visits.
  3. If b, Do the appropriate modifications to the page with Javascript.
  4. Send a custom event indicating if this is an a or b to Google Analytics.

The whole script can be like this:

var A_SEGMENTNAME = "OriginalPage";
var B_SEGMENTNAME = "BlueSignUpButton";
var abCookieName = "my_abtest";
var abTestSegment = $.cookie(abCookieName);
if(abTestSegment === null) {
    abTestSegment = A_SEGMENTNAME;
        if(Math.random() >= 0.5)
    abTestSegment = B_SEGMENTNAME;
    $.cookie(abCookieName, abtestSegment, { path: '/', expires: 30 });
if ( abTestSegment === B_SEGMENTNAME) {
 //Do something to modify your page

$(function() {
    _gaq.push(['_trackEvent', 'usersegment', abTestSegment, '',1, true]);

This code uses jQuery and the jQuery Cookie Plugin.

Custom segments

In order to compare the two groups of visitors, I created custom segments in Google Analytics.

Click Advanced Segments near the top of the page, and then New Custom Segment.

Remember to add segments for both the original and the variant.

Now I can explore the two segments in Google Analytics, and see if there are significant changes in metrics like pageviews/visit, and Adsense revenue.

Does this change make people use my site more, and is this different for mobile users?

Does this change make me more money?

If you have set up Goals in Analytics, you can compare the conversion rate for the two groups like more traditional a/b testing does:

Multivariate, and no overhead

This seems to me to be more flexible than the old Google Website Optimizer, as you get all the Analytics info for both segments. And you can add variations easily by extending the javascript and create more custom segments, which I think Content Experiments does not support. Also, it does not require any additional javascript downloads if your site is already using Google Analytics.

When changing an ASP.NET MVC3 application to run in integrated mode in IIS 7.5, we ran into some problems with global error handling. We wanted to catch all unhandled exception in order to log the error, and we wanted to output a custom error message.

In order to catch all unhandled exceptions, we chose to (still) use the Application_Error callback in global.asax.cs, and remove the default behavior:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
    filters.Add(new HandleErrorAttribute()); //Remove this line

When removing that filter Application_Error gets called like we want it to.  We then discovered that no matter what we outputed, we got the same old IIS “Internal server error” page.

Layers, like an onion.

It turns out there are two layers of error-handling here. First we do our job in .NET, but then IIS figures out something is wrong (since we returned HTTP 500), and slaps it’s own content in the response. After digging around, I found the answer in a blogpost: Put this line in your Application_Error method:

    Response.TrySkipIisCustomErrors = true; 

I would like to meet the guy (or girl) who came up with that name. It’s descriptive, and it seems quite honest. Set this one to true, and we’ll do our best to skip that horrible IIS error handling for you…

Despite its modest name, it worked perfectly. Now we got to log our errors, and we got to display our own content.


This last tweak has little to do with error handling in MVC, but I thought I should mention it in case anyone else experience the same behavior. When outputting our custom html, it suddenly got rendered as plain text, not interpreted as html. It turned out the content-type header was not set. To do this, set the correct content-type in Application_Error:

   Response.ContentType = "text/html";

Earlier I wrote about using Google Analytics to log the time spent generating content on One day I looked at the stats, I realized that this time had doubled:

The observant reader might point out that the time spent server-side increased by only 15 milliseconds, and that no user would ever notice this. I know, you’re right. This particular performance-hit is no big deal by itself. But if small incremental changes like this are introduced regularly without any benchmarking, it might be hard to fix the code when you discover that the server spends half a second serving each request.

Finding the culprit

The source control history confirmed that I had made several changes in the period where the performance suffered, but I couldn’t find anything that should cause this when reviewing the code (yes, I often compensate my bad memory by reading my own commits). Since this gave me no clues, I started profiling the code.

The profiler gave me the answer: I had introduced code that should write to the database in rare circumstances, but a bug caused this code to be executed on each page-request. Even though the database-write failed (so nothing showed up in the database), this doubled the total time spent serverside.

Once I discovered the bug, fixing it was trivial and resulted in 20 characters added code.

This was clearly a bug. The code I wrote did not behave as I intended it to,and it impacted the performance. But since it did not cause any malfunction for the user (or owner), it could easily have been left there without anyone noticing. This makes me wonder how many other bugs like that there might be out there, undetected.

Perhaps a good unit-test could have caught this one. But adding statistics as another layer of quality control proved to be useful, and made this error stand out once I glanced at the chart. It also demonstrated that the additional functionality did not slow the site down. Once the bug was fixed, the code went back to its earlier performance.