The Marketing Technologist.

We talk about analytics, code, data science and everything related to marketing technology. Backed by the tech geeks of Greenhouse.

Send users to your site after clicking on an animated GIF on Facebook

In 2015, Facebook begun supporting animated GIF images. An animated GIF is a graphic image that moves in a loop. Animated GIFs are commonly used by websites like Imgur, Twitter, Reddit and BuzzFeed. Businesses can use the power of animated GIFs to get people's attention. Posting one on Facebook is easy: just post the URL of the GIF into the status update box.

There's one downside: GIFs aren't very suitable for generating traffic to your website. At least, not if a user clicks or taps the GIF. The GIF automatically plays when a user scrolls by, and when someone clicks the little button in the bottom right corner of the GIF, the GIF opens in a new window. On mobile, a tap on the GIF also results in a new window playing the GIF.

In this post, I'll show you how you can use a small Node.js web application to solve this shortcoming. Although we're using Node.js in our code examples, the same concept can be easily implemented using other server side languages like C# or PHP.

So, what do we want to accomplish? We want to share an animated GIF on Facebook. When someone sees the GIF in Facebook's feed, we want to display the GIF. But when the GIF is clicked, we want it to lead to our website, not to a new window with the GIF.

For our example, we'll use this GIF:

Control the GIF

As long as we use the original URL of the GIF, the GIF will always to be shown as it is. Instead, we want the GIF to become a redirect to our website, and thus we need more control over the GIF. To do this, we will use some code to proxy the GIF request.

To proxy a request means that instead of showing an image directly, the image is loaded into your own application. That way Facebook sees the image served by your server instead of the original server.

I won't go into the specifics of writing a proxy with Node.js, but you can read about it all over the internet. With the code below, we create a small application that starts an Express web server to proxy the image using the imageUrl query string parameter.

var express = require('express');
var app = express();
var url = require('url');
var http = require('http');

// Start the Express server
app.listen(process.env.PORT || 3000)

// When someone hits facebook.gif
app.get('/facebook.gif', function(request_from_client, response_to_client){
    // Get real GIF URL from the query string (?imageUrl=...)
    var imageUrl = request_from_client.query.imageUrl;
    var image_host_name = url.parse(imageUrl).hostname
    var http_client = http.createClient(80, image_host_name);
    var image_get_request = http_client.request('GET', imageUrl, {"host": image_host_name});
    image_get_request.addListener('response', function(proxy_response){
        response_to_client.writeHead(proxy_response.statusCode, proxy_response.headers)
        proxy_response.setEncoding('binary');
        proxy_response.addListener('data', function(chunk){
            response_to_client.write(chunk, "binary");
        });
        proxy_response.addListener('end', function(){
            response_to_client.end();
        });
    });
    image_get_request.end();
});

I've got this code running in a Heroku app. You can test it for yourself replacing the imageUrl value in the query string: http://smart-facebook-image.herokuapp.com/facebook.gif?imageUrl=http://www.yoururl.com/originalGif.gif. This should just show the GIF.

Redirect to your site outside Facebook

The proxy just returns the original image, and that's exactly what we want when our image is displayed in the Facebook Feed. But if we click it, we want to open our site. So we need to find out whether the image is shown in the Feed or in a new window. Luckily, it's pretty easy to recognize the Facebook user agent. The user agent string contains visionutils or facebookexternalhit when a URL is called from within Facebook.

const agent = req.headers['user-agent'].toLowerCase();
const isFacebook = agent.indexOf('visionutils') > -1 || agent.indexOf('facebookexternalhit') > -1;

isFacebook is true when a link is opened in Facebook (a GIF in a feed) and false when it's outside Facebook (a click on the GIF). Now all we have to do is check for this value, and if it's true, redirect the user to our site.

// Redirect URL
const redirectUrl = 'http://www.yoursite.com';

if(!isFacebook) {
    // Redirect to the redirect URL
    res.writeHead(302, {
        'Location': redirectUrl,
    });
    // Close the connection
    return res.end();
}

The complete code is available on [GitHub].(https://gist.github.com/codeorelse/604ff9de4e7e5c25f111).

You can test it for yourself replacing the redirectUrl and imageUrl value in the query string, and post the URL into the status update box: http://smart-facebook-image.herokuapp.com/facebook.gif?imageUrl=http://www.yoururl.com/originalGif.gif&redirectUrl=http://www.yoururl.com. Make sure you decode the URLs before using them in the querystring. You should see the GIF appear like this:

If you want to make sure your proxy returns the correct GIF, you can use Facebook's Open Graph Object Debugger.

I noticed that the code above doesn't play well with interlaced GIFs, so that's something to keep in mind when creating and exporting your GIF animation. Facebook caches your GIFs, so you don't have to prepare your server for a big number of requests. On desktop, Facebook actually transforms your animated GIF to an MP4 video that can be played in the Feed.

Of course, using this technique only makes sense if you use animated GIFs on Facebook to get people to your site. Right now, we are testing this technique with some of our clients. As soon as we've got some insights on the performance of these GIFs, we'll share them on The Marketing Technologist.