Dynamic OG-Tags in your statically Firebase hosted (Polymer) web app

Be an OG. Original Gangster or Open Graph Tagger.

The Problem.

You finished developing your web app, on-boarded the first people and you are now focusing on growing your user base a bit. That’s the moment you realise, holy shi…, how can I create dynamic OG-Tags so Facebook and other Platforms show different content when sharing different URLs of your page. You research a bit and you figure out that this is not possible with statically hosted websites because Javascript does not get executed by these crawlers.

You stumble upon prerender.io. You think, really, do I have to do this? You start playing around with your NGINX config files and figure out how to proxy requests from social bots to prerender.io. You kind of hate it.

Your next app is hosted on Firebase. You (again) do not think about the importance of dynamic Open Graph Meta Tags. You onboard the first users and start focusing on growth. You remember prerender.io. You think about server config files. You start scratching your head. You think f***. I cannot configure my Firebase server. You start crying. Crying is good for you. You gotta feel it to heal it.

The Solution.

He could not care less about config files.

The solution comes with using Firebase Functions, and it’s quite simple. 
Just need to add a http trigger, analyse the request, replace your meta tags and return the modified index file. Thats about it.

exports.host = functions.https.onRequest((req, res) => {
// do your stuff and return the index.html file
});

Let’s take a look at an actual implementation.

1. Add placeholder for dynamic meta tags

index.html

Let’s add some placeholder and replace them afterward with dynamic meta tags in the Firebase function.

<!doctype html>
<html lang="en">
<head>
    <!-- 
Gets replaced by URL specific meta tags via Firebase Functions
-->
<meta name="functions-insert-dynamic-meta">
<meta name="functions-insert-dynamic-og">

    <link rel="import" href="src/my-app.html">
</head>
  <body>
<my-app></my-app>
</body>
</html>

We can now reference these functions-insert-dynamic-xyz meta tags in our Firebase function. But the main reason for me to use a placeholder and not just reference </head>, is that they remind me that there is something happening with this file before it gets served.

2. Copy index.html into our functions folder

build/index.html copy tofunctions/hosting/index.html

We need to be able to reference the index.html in our functions. For that, we create a functions/hosting folder and paste the index file in there. 
I do that automated while building my app. You may include the build step in yourgulpfile.js or whatever you are using to build the app. I just add below copy action into my package.json file so I can run npm run build.

"scripts": {
"build": "polymer build && cp build/es5-bundled/index.html functions/hosting/",
},

2. Add the function

functions/index.js

In this example, we want different meta tags with each organisation.

example.com/ => Default meta tags
example.com/xyz/ => Default meta tags
example.com/organisation/red-cross => Check database for the red cross organisation and return specific meta tags

We also only want to make the effort to replace the meta tags if the user agent requesting the page is a bot. Otherwise, we don’t care much and just return the original index file with some default meta tags.

3. Add rewrites

firebase.json

Now we need to make sure, that on every request our host function gets called. For that, we need to add a rewrite entry to our firebase.json file.

"hosting": {
"rewrites": [{
"source": "/**",
"function": "host"
}]
},

That’s it. Deploy the app and enjoy the magic.

Thanks for reading.

Jalal Fathi is freelance software developer and startup founder. Passionate about web technologies and in love with Polymer. Learn more about how he can help you to create your next digital product. He works wherever he wants and tries to catch a good swell wherever he can. He wrote this bio by himself while writing in third person.