Preserve Facebook Likes With Nginx
Mar 21, 2019After migrating Pandify’s URL scheme to HTTPS, I noticed that the site’s Facebook likes had disappeared! This post describes how I fixed that.
Background
When configuring the Facebook like button you specify the ‘URL to like,’ which is the URL that new likes will get attributed to:
However, the like button’s count reflects the likes for the current page’s URL, and NOT for the URL you configured the like button with. If a page’s URL changes at all, including the URL scheme, that page’s like button count will change to reflect the new URL’s like count.
At a high level, here’s what I wanted to do:
- 301 redirect HTTP to HTTPS
- Preserve Facebook likes from the non-HTTPS URL
- Allow new likes from the HTTPS URL to increase the like count
Solution
Facebook shares some insight on this issue:
…you can’t move the likes, shares or comments directly to the new URL but you can use the old URL as the canonical source for the number of likes or shares at the new URL.
There are three ways to declare the ‘canonical source’ to Facebook:
- HTTP 301 or 302 redirect
<meta property="og:url" content="..." />
<link rel="canonical" href="...">
Option #1 is a no-go because Pandify’s Nginx server redirects HTTP to HTTPS. Again, this is what causes the Facebook likes to disappear.
I want the canonical URL to be the HTTPS URL. Left with option #2, I added a <meta>
tag to Pandify’s HTML template that points to the non-HTTPS URL (which has the Facebook likes associated with it).
<!-- Preserve Facebook likes from the non-HTTPS URL. -->
<meta property="og:url" content="http://pandify.com" />
This tag tells Facebook to use the non-HTTPS URL as the ‘canonical source’ for likes. However, this doesn’t restore the likes yet, and Facebook’s Sharing Debugger shows a new problem when debugging https://pandify.com
:
Circular Redirect: We could not resolve the canonical URL because the redirect path contained a cycle.
What’s happening? Facebook’s scraper is following the <meta>
tag’s og:url
(the non-HTTPS URL) and getting redirected by Nginx to the HTTPS URL, causing a redirect loop!
My solution is to detect the Facebook scraper’s user agent and NOT redirect to the HTTPS site, but instead return 200 OK. I do this via Pandify’s Nginx server block configuration for non-HTTPS requests:
server {
listen 80;
server_name pandify.com www.pandify.com;
location / {
if ($http_user_agent ~* "facebookexternalhit") {
# Preserve Facebook likes from the non-HTTPS URL.
add_header Content-Type text/html;
# NOTE: Add other Open Graph tags to keep Facebook's Sharing Debugger happy.
return 200 '<meta property="og:url" content="http://pandify.com" />';
}
return 301 https://pandify.com$request_uri;
}
}
Voila! After restarting Nginx and forcing Facebook’s Sharing Debugger to ‘Scrape Again’ for https://pandify.com
, the likes from http://pandify.com
returned.