Instagram and Optimizing Favicons
Something interesting and cool happened with photo sharing service Instagram in the last week. No, I’m not talking about Facebook buying them for $1,000,000,000.00. I’m referring to Instagram co-founder Mike Krieger, and the talk he gave at AirBNB entitled "Scaling Instagram." In his presentation, Mike discusses the technical hurdles faced by going from 0 to 30 million users in 2 years. Very cool indeed.
As all good presentations are, the slides contain minimal text, allowing the speaker to drive the conversation. Unfortunately this reduces the value of the slides when viewed in isolation since the bulk of the presentation’s content was verbal. However there is still a large amount of interesting information and I encourage you to read the slides.
One part that really interested me was when Mike was speaking about early performance and load problems Instagram had. In fact, the very first issue Mike mentions, which happened on their opening weekend, had to do with their favicon.
Instagram’s Favicon Problem
Ahhhh our friend the favicon!
While slide text is sparse, it appears that the favicon for the Instagram website was not present on opening weekend. This caused the underline Django controller to generate a bunch of errors when trying to services incoming favicon requests and that was bad, as we’ll see in a second.
There are a couple of reasons that a favicon can result in a 404. First of all, you can explicitly define the location of a favicon using a
<link> tag. It is possible that the
<link> pointed at a non-existent favicon, resulting in a 404. Another option is not having a
<link> tag at all. By default, all modern desktop browsers will make a request to
/favicon.ico if no
<link> tag is present which explicitly defines the path to the favicon.
So what’s the problem? 404’s are bad for a few reasons. First of all, the user’s browser has made a request and waited for a response only to get nothing. Usually the body of 404 response is larger than the resource being requested. This is certainly true for favicons which are only a few kilobytes in size. Next, web servers and application frameworks can be configured to respond to 404’s in different performance-impactful ways. At a most basic level, they might log information specific to the 404 to help a developer resolve the problem. Some applications, like WordPress, try to be helpful when to request a page they does not exist. These application will try and find the page you might have meant, and redirects you to it. Suddenly a simple typo in a URL is causing extra disk I/O, database queries, and computation, all of which adversely affect response times and increase server load.
In fact, it caused Instagram such a problem that Mike states:
"Lesson #1: Don’t forget your favicon."
But optimizing your website’s favicon goes beyond just making sure you don’t forget it. Below are 5 recommendations for optimizing your favicon, plus two bonus tips, to optimize your website’s favicon.
Tip 1: Make sure it exists.
Since we know that browsers are always going to try and request a favicon, Rule #1 for favicons is to make sure it exists. Whether you include a
<link> or not, the browser is making a request for it. Even if you are able to remove any disk I/O or database queries or additional computation by your application when a 404 occurs, the size of your 404 page is going to be larger than the size of your favicon. This is adding insult to injury, since the client has to spend more time downloading more data, all of which is completely useless.
Tip 2: Make sure it is compatible.
Internet Explorer, even modern versions like
IE9, only supports favicons using the ICO file format . This sucks, since the ICO format is essentially a uncompressed BMP with a more primitive header.
Instagram doesn’t do this properly. They have a file,
/favicon.ico, but it’s actually a 683 byte GIF image as shown in the screen shot below:
Since its a GIF we can see that IE does not render Instagram’s favicon:
While a GIF version of Instagram’s favicon is smaller than the ICO, it does not work properly on any version of Internet Explorer, including IE9. (). Since over 50% of the browser market is still IE, it’s silly to waste time sending bytes to an IE client which it can’t do anything with.
One possible solution is to always use a
<link> tag to point to a favicon. When requesting an HTML page, the application could look at the
User-Agent string. Based on the browser type it could write out a
<link> tag pointing at the GIF version of the favicon for non-IE browsers and a
<link> to ICO version of the favicon for IE browsers. It is critical that this sniffing occurs for HTML pages and not when serving the actual favicon. As we have seen, using factors other than URL to determine the content to serve has an enormous negative impact on caching.
Tip 3: Make sure it is cacheable.
Speaking of caching, like all your images you should also cache your favicon. Unless you are using
<link> tags to reference the favicon, you cannot version your URLs to allow for far-future caching. This is yet another reason why you should be using
<link> tags for favicons instead of simply placing favicon.ico in the web root. In this case, consider caching for a few days to a few months, based on how often you radically alter your website’s design.
Tip 4: Make sure it is the right size.
Favicons are almost always shown at 16 pixels by 16 pixels in the browser’s address bar or browser tab. It does not make sense to use larger dimensions for a favicon.
Using the proper dimensions is not enough. The ICO file format allows for multiple copies of an image with different dimensions to exist in a single ICO file. This is because the ICO file was originally designed to store icon images for Windows and needed to support different resolutions and sizes. These larger dimensions are unused by modern web browsers and merely increase the size of the favicon.
Detecting improperly sized favicons is pretty easy. A 16×16 pixel, 256 color ICO file with no extraneous sizes should be around 1400 bytes. If your ICO is larger than that, you are probably doing something wrong.
You can use the
file command on Mac/Linux/Unix/Cygwin systems to identify ICO files containing multiple images as shown in screen shot below.
When opening multiple image ICO file in an editor like Photoshop or GIMP, the different sizes appear as separate layers as shown in the screen shot below. This allows you to remove the extraneous images and create an ICO file with a single 16×16 pixel image.
Tip 5: Make sure you use compression.
If you converted Instagram’s 683 byte GIF into a properly formatted ICO file, it would be 1406 bytes. That sounds bad, but this is not an apples-to-apples comparison. As I mentioned in my Lose The Wait: HTTP Compression post, ICO is not a natively compressed image format. This mean you can and should serve your favicon using HTTP compression. Using GZip, the 1406 byte ICO file compressed to 826 bytes. This is only about 20% larger than Instagram’s GIF-based favicon and it works across all browsers.
Bonus Tip 1: Try using a 4-bit favicon.
ICO images can have a range of color depths, from 8-bit up to 16-bit or 24-bit color. Typically favicons are 8-bit color, allowing for up to 256 distinct colors. Considering that a favicon is only 16×16 pixels, each pixel could literally be a different color!
As I wrote about in Choosing PNG8 Candidate Images and presented last year at Velocity 2011, images with smaller dimensions can have fewer colors without being noticeable to users. Reducing a 16×16 pixel, 8-bit, 256 color icon to a 16×16 pixel, 4-bit, 16 colors can produce a much smaller file with little visual distortion. Obviously the results are subjective and this works better with some favicons than others.
Below is Google’s favicon:
On the left is an 8-bit, 256 color version and on the right is a 4-bit, 16 color version. There is virtually no visible difference. The 4-bit version is resulting ICO is only 318 bytes. Applying HTTP compression takes this down to 256 bytes, a savings of 71%.
Let’s try something more complex, like Instagram’s favicon.
On the left is a 8-bit, 256 color version. On the right is a 4-bit, 16 color version. You can see some slight visual distortion, but the resulting 4-bit ICO is only 318 bytes. Applying HTTP compression takes this down to 262 bytes. That means a 4-bit HTTP compressed ICO-based Instagram favicon is 2.5 times smaller than their current GIF-based favicon! As an added benefit it works across all browsers!
As you can see, for simple favicons, converting to a 4-bit icon can achieve a large amount of savings with little visual sacrifice. This is why major sites like Yahoo’s and Wikipedia all use 4-bit, 16 color favicons.
Creating a 4-bit favicon is easy, but it various from tool to tool. Look for a way to reduce the image’s color depth. As shown in the screen shot below, GIMP provides an option for 4-bit ICO when saving the image.
Bonus Tip 2: Try inlining the favicon.
One of the downsides of favicons is that you cannot prevent their use. That was the original problem that Mike from Instagram was talking about. You cannot avoid using a favicon by not including a a
<link> tag reference; all browsers will send a request for
/favicon.ico if a
<link> reference is not present. So the browser is going to request a favicon whether you want it to or not!
Or does it?
You can embed the favicon into the HTML document using a
<link> tag and a data URI. Since it’s a data URI, you have to Base64 encode the ICO file, but then it gets gzipped since it is inside of HTML document (you using HTTP compression correctly right?). The 4-bit, 16 color, gzipped Instagram favicon is only 262 bytes. If you Base64 the Instagram favicon and gzip it, it is only 285 bytes in size. And you get the advantage of not having to make an HTTP request!
Sounds great right?
Well, as mention over on the WebPageTest Forums, there can be a few problems. First of all, only IE8 and above supports data URIs, so you are going to need to do some server-side sniffing to only embedded it for compatible browsers. Also, many browsers try to be intelligent and only load the favicon after all the other page resources have been downloaded. Embedding the favicon could potentially delay page rendering. Another downside is that you need to embed the favicon into every page, adding 285 bytes each time.
Whether this makes sense is going to vary from site to site and the browsers they use. If the majority of your visitors are new users with an empty cache, and only visit a few pages, then embedding a favicon may make your site faster. Experiment and see!
When the co-founder of a company that went from 0 to 30 million users in less than 2 years and which was just acquired by Facebook for $1 billion dollars mentions favicons as his very first lesson in performance scaling, you know they are important! Just remember this list of optimizations for your website’s favicon:
- Make sure it exists.
- Make sure it is compatible.
- Make sure it is cacheable.
- Make sure it is the right size.
- Make sure to serve it using compression.
- Using 4-bit color depth icons.
- Inlining the favicon using data URIs.
Additionally you can try:
Want to see what performance problems your website has? Unoptimzied Favicons and Favicon served without Compression are just 2 of the nearly 400 performance issues Zoompf detects when testing your web applications. You can get a free performance scan of you website now and take a look at our Zoompf WPO product at Zoompf.com today!