Turbolinks, Google Analytics & SEO: Keeping everybody happy

The turbolinks README states “it keeps the current page instance alive and replaces only the body and the title in the head”. Hmm. Okay. But what about the meta tags and a good SEO practice of keeping the meta data unique on each page not to mention the Google Analytics pageview update?

Turns out the answer is (mostly) straightforward.

With the meta data tags, just place the header data that needs to be replaced in addition to the title tag and page body **before** turbolinks is invoked.

The application layout view:

Or in HAML:

Google Analytics is Javascript so it’s not quite as simple. This goes **after** turbolinks is invoked but you also need some additional code. A quick trip through Google search will quickly reveal some disagreement over what exactly this additional Javascript should be but here’s what’s working for me so far.

The Google Analytics partial (HAML version):

This binds to the page:change event after checking that you have the browser support and turbolinks is loaded.

The above is for turbolinks >= 2.0.0 with page:change being triggered on DOMContentLoaded. For earlier turbolink versions, you’ll want to uncomment the initial call to _gaq.push(['_trackPageview']);.


Open your application in Chrome, press F12 and navigate to the Network tab. Each time you refresh the page or click on a link you should see a gif initiated by ga.js. Once that’s working, the next test is to see if the pageviews are showing up in Google Analytics itself. You can check this by watching the Real-Time Overview window. (If you’re filtering out your own IP, don’t forget to remove the filter temporarily. ‘Nuff said.)

Since all of the browsers on my development machine are the latest versions and support pushState, I used BowserStack.com to check out the legacy conditions. Pick any out-of-date browser and OS combination, then watch the GA Real-Time page to see if the pageviews match what you’d expect.


You can use the above to force an update of the page header in the browser but it doesn’t update the page’s DOM objects. This means, for example, even though the meta description will be unique to the page in the browser, the meta description stored in the cached DOM is the last one saved by turbolinks on the last full page refresh.

Was this helpful? I get something wrong? Please leave a comment. I asked this question and answered it myself on StackOverflow but I thought I’d post it here as well.