Measuring how Typekit Web fonts affect the user experience

Typekit is a quick and easy way to add quality Web fonts to your site, but it can also significantly impact page load times. 

“Ain’t care: I want cool fonts!” you say. Okay, if you’re willing to sacrifice a little speed for that, it might be a reasonable trade-off for your purposes.

But how much speed, exactly? In this age of quantify-everything, we have the tools available to get at least a decent approximation of what kind of impact third party scripts have on page load times. So read on to see how we can employ some real user monitoring (RUM) to tell us how long Typekit is taking to load for real users.

Good reasons to monitor Typekit load times

Implementing Typekit is as simple as any third party script, but there are two major concerns with how it loads Web fonts.

1. Typekit font loading blocks page load

The default method for including Typekit on your page is via Javascript snippet in the head of your page. This downloads and executes the scripts synchronously, meaning that while the Typekit script is doing whatever it needs to do load fonts, nothing else can happen on your page, i.e. it’s blocking your page load.

In this case, the blocking is very much intentional: It ensures that your fonts are downloaded and ready before any text on the page appears.

You actually can load the Typekit script in an asynchronous manner, but that will introduce the problem of FOUT. Dealing with FOUT is beyond the scope of this article, though Typekit provides some ways to deal with it.

2. Large font payloads can extend blocking time

The actual font files Typekit needs can also be a large download. Depending on the character sets you want to support and the font variants you’ll need — regular, bold, italic — you can easily end up with a font package adding up to 200k or more.

In some browsers, Typekit halts your page load while the entire download completes. Depending on your On a 3G connection, 200k might take 3-4 seconds to download, during which a user will see nothing but a blank page. And this will be on top of any other assets you’re already loading and/or executing.

Measuring time spent blocking

So really, the overall concern is blocking time, i.e. how long users are looking at a blank page before something loads. How do we measure this? By tapping in to Typekit’s font events, and recording timings with Google Analytics.

Add timers to the markup

First, I’ll write the code I want in the head of my page:

<script>
  MY_APP.startTiming('typekit.script');
</script>
<script onload="MY_APP.endTiming('typekit.script')" src="//use.typekit.net/znc6qnp.js"></script>

<script>
  try {
    Typekit.load({
      loading: function() {
        MY_APP.startTiming('typekit.font');
      },
      active: function() {
        MY_APP.endTiming('typekit.font');
      },
      inactive: function() {
        MY_APP.endTiming('typekit.font', 'Timed out');
      }
    });
  } catch (e) { }
</script>

I modified Typekit’s default snippet to add my timers to:

  • The Typekit script itself: Measure the initial script load and execution time.
  • Typekit’s font events (loading, active, inactive): Measure how long it takes for Typekit to load the actual fonts.

The inactive callback fires when Typekit takes longer than five seconds to load. We especially want to record a timing for this, and give it a custom label so that we can easily segment this data in Analytics.

Inactive idiosyncrasies

The inactive callback is a little misleading. Its use is intended for cases when you want to run some code when your Typekit fonts don’t load after five seconds. Under slow network conditions, however, some interesting things happen.

If the actual Web fonts package takes longer than five seconds to download:

  • inactive will fire.
  • The font package will continue to download.
  • In Chrome, Safari and IE, the page load will block until the fonts package is completely downloaded. The Typekit fonts will still be loaded.
  • In Firefox, the page will stop blocking after five seconds, but you will get FOUT when Typekit fonts finally download. Typkekit fonts will still be loaded.

So inactive is not much of a guarantee of anything, other than it took longer than five seconds to load your fonts.

The timer code

At its core, the timer code is very simple. I’ve applied some of my own style in this example, so it’s a little fatter than it could be.

(function () {
    'use strict';

    // Set up a GA queue if it's not already defined
    window._gaq = window._gaq || [];

    // Store everything in a global object for this app so we don't pollute the 
    // global namespace
    window.MY_APP = {
        // Place to store timings
        timings: {},

        // Return the timestamp in ms
        now: function () {
            // Try to use the performance API if the browser supports it.
            var performance = window.performance || {};

            // Use performance.now if it's there, otherwise fall back to old skool
            performance.now = (function () {
                return performance.now || function () { return new Date().getTime(); };
            }());

            return performance.now();
        },

        // Begin a user timing stored with the given key
        startTiming: function (key) {
            MY_APP.timings[key] = MY_APP.now();
        },

        // End a user timing with the given key and track it with GA. Accepts
        // an optional label argument for use in Analytics.
        endTiming: function (key, label) {
            var endTime = MY_APP.now(),
                timeSpent, hourInMillis;

            // Die if no start key defined
            if (!MY_APP.timings[key]) { return false; }

            // Calculate the time spent
            timeSpent = endTime - MY_APP.timings[key];

            // Make sure timeSpent is within acceptable parameters to avoid
            // junk data.
            hourInMillis = (1000 * 60 * 60);
            if (timeSpent > 0 && timeSpent < hourInMillis) {
                // Record this user timing with Google Analytics
                _gaq.push(['_trackTiming', key.split('.')[0],
                          key, timeSpent, (label || '3rd party'), 50]);
            }
        } // endTiming
    };// MY_APP

}());

startTiming simply records a start time in milliseconds. endTiming does some math and then uses the handy _userTiming in Google Analytics to record the time taken for the given load event. Let the data collection begin.

Analyzing timing data in Analytics

Great, so now we’re collecting timing data in Google Analytics. The last step is to make some sense of it. Look for the Typekit timings under Content > Site Speed > User Timings.

Table of speed timings

Cool. So now we have the data we need to make some informed decisions about our Web fonts. Here we have the average timing for the script load as well as the fonts. Clearly, the load time is significantly higher while the Typekit font package is downloading.

[Say, is that 5 ms load time for the script accurate? Not really. Time in Javascript is notoriously inaccurate as you approach zero. It seems like very low numbers mean that the script took roughly 100 ms to load. As time increases, you should start seeing more accurate values. For our purposes, this kind of monitoring is really only useful for identifying possible network issues with script serving. ]

Breaking down our data by operating system gives us some interesting info.

Table of speed timings by OS

Right away, it looks like iOS and Android users are suffering more blocking time than desktop users. Depending on your audience, you may feel a need to use system fonts for these users if that kind of blocking is unacceptable. (If you haven’t seen it, look at Strangeloop’s graphic on the effects of a 1-second delay.)

There are many other ways to use this data in Analytics that I’ll leave to you to explore.

Caveats

  • As mentioned, Javascript time is inaccurate: You should assume it will be off by at least 100 ms for any given measurement. Maybe more.
  • You’re littering up your page with timing code: It’s ugly and you’re adding bloat to your payload and execution time. (Not much, but it adds up.)

The best application of this code might be as part of a multivariate test or similar scenario, where you’re evaluating the impact of Typekit Web fonts on your site or application in a limited fashion.

So now you can get started with measuring Typekit’s impact on the user experience! And hey, why stop there? You can easily extrapolate this method to add user timings to just about any script on your page.

More reading on Web fonts

  • jrichocean

    We just ran into this bit of fun with typekit, it was kicking mobile users in the teeth. This is great info to gain a more educated insight into blocking time. Thanks