A few years ago, after seeing the cover images on several other blogs. I felt inspired to do the same. Including a cover
image for content when it’s linked externally just adds a little pizazz, drawing a little
more attention and making it look a little more polished.
If you haven’t heard of it before, link unfurling is the process of parsing the details of a posted link and extracting
the relevant information to enrich the preview of that link. That includes things like website names, page titles,
descriptions, authors, and (importantly for me) cover images.
When unfurling links, the fallback approach most social platforms take is to extract title, cover, and description
from the content directly. So for a very simple HTML page with an image:
<html><head><title>My Blog Post</title></head><body> My blog content! Here, have a picture of a puppy:
<imgsrc="https://picsum.photos/id/237/800/600" /></body></html>
You may get a link preview like this:
There are a couple of problems with this:
Not all platforms will pull out the picture of the dog from the content, they may just show the title
If you have multiple images in your body, unfurlers will just take the first one, even if it’s not the one you want to
show in the preview
Thankfully we can provide some guidance to unfurlers, through the use of <meta> HTML tags.
Instead of relying on each social platform to correctly and consistently unfurl our link based on the body of the
content, we can use the Open Graph protocol to declare the page title, description, author, and cover
image which will be used for showing a preview of the page.
Slack’s API docs do a great job of
illustrating how unfurling works with Open Graph and which specific meta tags are used to populate each piece of data.
I put together a simple image template, exported an image for each of my past posts, and made sure I had the relevant
<meta> tag in the head for each post. Here’s a look at the cover image for the post you’re reading right now:
I shipped it, called it a day and moved on. Only, when I came back to test it a little later in the day, I realised that
it wasn’t working at all on Slack. In fact, none of the Open Graph meta tags were working, my links had no preview at
all.
I started by inspecting my compiled HTML pages and confirmed that I did indeed have all the necessary meta tags. I
previewed my blog post links on LinkedIn, Twitter, Facebook and saw that they were all working. Even when previewing
my page on https://metatags.io/, my blog links looked correct for all platforms, including Slack!
Completely confused by what in the world was going on, I started a simple Python HTTP server locally and exposed it
through ngrok. I pasted the new public link into Slack, and inspected the request in the ngrok
web portal.
Turns out, Slack includes the Range HTTP header
when unfurling links which asks the server to respond with a particular byte range of the full response, in this case
Slack is asking for the first 32kB of the response.
I plugged my ngrok link into several other social platforms where my unfurling was working, and comparing Slack with
them highlighted a pretty obvious difference. Slack was by far the most restrictive with its content fetching, limiting
itself to a measly 32kB, followed by Facebook at 512kB, Twitter at 1MB, and then LinkedIn at a whopping 3MB.
info_outline
Twitter doesn’t actually include a Range header, but as far as I can tell, it only parses the
first 1MB of content from the response. If you’re a Twitter engineer and reading this, save some bytes and throw a
header on those requests.
Inspecting the raw HTML from my blog post, and the position of the Open Graph meta tags finally made it clear why Slack
unfurling wasn’t working while other platforms were. I’ve represented the length HTML response in red, and then the
position of the meta tags as the blue line.
My blog, which is hosted on Vercel, was being a good little compliant HTTP server and responding with the first 32kB of
the HTML page, which didn't contain the meta tags. It turns out that Gatsby was inserting a lot of CSS into the head of
my page (to ensure that content looks correct on first load) and then inserting the meta tags below that, pushing the
meta tags outside of that 32kB window.
Adding a custom html.js file to my Gatsby setup allowed me to ensure that <meta> and <title> tags in the HTML
<head> are always positioned before other tags
(code).
With this change, the position of the Open Graph meta tags are well within the first 32kB of the HTML response.
And with that small change to positioning, my links were
workinginSlack!