Optimizing for Facebook Share Preview

Background Story

One of the web applications I’ve built here at work allows users to make cool t-shirt designs and then share those designs online. Since this is an intended use, we go ahead and provide some share buttons for the big social networks. One of those buttons hooks into Facebook.

I got an email from the boss recently asking if we could optimize the images that Facebook displays to the user. I had checked this at the beginning, but obviously something had changed. So when someone wants to share [their funny family reunion t-shirt design](http://t-shirts.getyourshirts.com/designs/1973;public) on Facebook, this is the first thing they see:

Bad Facebook Preview

Obviously, a “Secured by Thawte” badge is not ideal. Neither is that description which is basically disclaimer text. :( It takes paging through the first 5 of 8 images before you get to one that is actually an image unique to that t-shirt design. This could use some optimizing, but how does Facebook choose what to show?

Facebook Says …

If you read their [official recommendations](http://www.facebook.com/share_partners.php) (you’ll have to click on “How do I make sure the Share Preview works?” to see the details), you’ll see they use the standard <meta> description tag as well as introducing two new tag standards; a title meta tag and an image_src link tag. [Digg even supports](http://digg.com/tools/thumbnails) the new link tag. But how does it work? And, will it work for me?

The only way to answer this was to do some testing. Because Facebook caches each URL, I had to setup 22 different test pages to iterate through all of my initial questions and questions revealed by testing different variations. Rather than bore you with the play-by-play, let’s skip straight to the results. :)

Facebook Preview Facts

  1. Facebook sends a robot to visit the URL, with a User Agent string of
    “facebookexternalhit/1.0 (+http://www.facebook.com/externalhit_uatext.php)”
  2. If you provide a <meta> title and description tag, Facebook always displays the content you provide. If not …
    • If you don’t provide a <meta> title, Facebook will use your real <title> tag.
    • If you don’t provide a <title> tag or a <meta> title, Facebook will use your domain name (e.g. “whoisgregg.com”).
    • Title length limit is 100 characters. Description length limit is 270 characters. If you exceed the limit, Facebook chops the text exactly at the limit and adds an ellipse.
    • UTF-8 characters are supported for both title and description.
  3. If you provide a <link rel="image_src"> tag
    • Facebook ignores all the other images on the page.
    • If the image tagged is smaller than the lower limit of 50 x 50 pixels, then no image is offered at all.
  4. If you don’t provide a <link rel="image_src"> tag, Facebook scans the document for normal <img src="..."> tags and then displays;
    • up to 26 images to the user,
    • where the width and height of the image are each 50 pixels or greater (tested with images as large as 3504 x 2336)
    • in order of image dimension (smallest to largest) regardless of source order,
    • ignoring CSS declarations which would hide the image to a normal user (display:none; either inline or in the stylesheet),
    • ignoring images which are inside of CSS (inline and stylesheets), Javascript (document.write and DOM), or inside of HTML comments.
  5. If you don’t provide a <meta> description, Facebook looks for a text snippet from the page that is inside of a <p> tag and which is at least 121 characters in length. If it can’t find a matching string, it doesn’t display any snippet at all.

Facebook Share Optimization Tips

With these observations in mind, you should always provide an optimized <meta> title and description tag for each page. If your page only has one logical image, then you should also provide the <link rel="image_src"> tag.

However, if you want to give your user a choice of images, you can easily provide images just for facebook previews. Define a class in your stylesheet like img.facebook { display: none; } and then add a series of <img class="facebook" src="/path/to/img.jpg" /> pointing to images that are at least 50×50 pixels (but not much larger, so that they will appear before the other images on the page).

If you want to make sure your other images do not appear in Facebook’s Share feature (but are still visible to your regular visitors), you’ll need to change them to either CSS background images or dynamically insert them using Javascript.

Follow these tips and you’ll have users posting much more effective links:

share-optimized-2

Update 2009/05/15: Jake noticed today that Facebook is now automatically opening the preview feature anytime a person types a URL into their status. This isn’t a rarely used feature anymore.

Introducing expandUrl, redirect resolution for the rest of us

To solve a problem I describe in detail below, I recently created a new site called [expandUrl](http://expandurl.com). The expandUrl™ service does a few things very well:

* Tells you the “real” URL of any shortened URL (regardless of what service provides it).
* Gives technical types the redirect codes involved in all the redirects for any particular link.
* Discovers both canonical and shorturl data for the final expanded URL.
* Offers a fast API for quickly finding the expanded URL (and a less fast API for getting the same detailed data that is available from the web interface).

**Heard enough?** Go check it out:

expandurl

The expandUrl™ site was built to fix a specific problem I recently discovered on one of my other sites, so you can be confident that expandUrl™ has been tested on a sample set of a couple thousand real-life URLs. However, the total number of hours I’ve spent building expandUrl™ can still be counted on one hand so you are bound to discover some edge cases which I haven’t encountered.

I appreciate all bug reports to be posted below. Security concerns should also be posted here, but I will pre-moderate those until they are fixed. (Not to hide them, but to give me the opportunity to fix them before they are exploited.)

### Eating my own dog food ###

I run a site which aggregates RSS feeds from a few dozen different sources. One of the included sites accidentally let their domain name expire and had to move to a new domain name. This particular site also hosted their RSS feed with Feedburner.

When the site changed domain all the URLs were broken. You may be thinking, “Well, duh. There’s nothing you can do to fix that.” In this scenario however, the original site owner simply changed domain names. All of the old URLs would map perfectly to the new domain name:

> **Old:** http://example.com/blog/2007/04/post.html
>
> **New:** http://example.org/blog/2007/04/post.html

If I had stored the actual URLs, I could simply do a [REPLACE in the database](http://dev.mysql.com/doc/refman/5.0/en/replace.html). However, since I stored the Feedburner URLs in my database, it would be impossible for me to do so. That’s because Feedburner obfuscates the actual URL data:

> **Actual URL:** http://example.com/blog/2007/04/post.html
>
> **Feedburner URL:** http://feeds.feedburner.com/~r/exampleblog/epRL/~3/745213668/post.html

I quickly built [expandUrl](http://expandurl.com/) so that I could resolve any URL (be it a short url, tracking script, or feed redirect) to the actual URL. I then ran an automated script to determine the relative link on the old domain, replaced the old domain with the new domain, and updated the database accordingly. An hour or so later, and all those posts are now fixed.

I ran this script against the entire database of URLs to go ahead and resolve any other redirects found. I made an interesting discovery. Many of the RSS feed services will generate multiple redirect URLs for the same blog post permalink. My database had a UNIQUE index on the URL field as a means of preventing the same post from showing up multiple times, but it turned out the feed services were inadvertently circumventing that “protection.”

In the end, integrating expandUrl has cleaned over 300 duplicate URLs from my database and helped improve the future maintainability of the link data the site has collected.

If you find expandUrl™ helpful, I’d love to hear about it! :)