Track Page Translations with Google Tag Manager and Google Analytics

Very recently I spotted a conversation somewhere online asking about page translations (unfortunately, I don’t even remember on which platform/community did this happen. Anyway, if I recall correctly, the request was to track the original title of the page in GA (rather than the translated one) and that way keep the data purity at a higher level. In opposite, others were defending that this is very valuable information that can signal the need for a localized website’s version (read: no need for purification).

And this conversation planted a seed in my head. Wouldn’t it be cool to track page translations with Google Tag Manager? Every time someone translates a page, we could track it as an event and later check the aggregated information. One thing led to another and here I am writing my take on this topic.

The context

When it comes to translating a page, there are two mainstream ways of doing that (as far as I know):

By using the Translate to… feature in Google Chrome (or by having a language dropdown menu implemented on a page that is using the Google Translate)

There are probably more solutions but I found these two the most often used (sorry, no particular data, just a gut feeling). If you notice that something big is missing here, post a comment! I’ll be more than happy to update the solution.

When a visitor uses one of the aforementioned translation solutions, the language of the entire content of the website (text) is automatically changed to another language.

In this blog post, we’ll track exact moments when the translation has been activated and will send such data as events to Google Analytics (via GTM). Additionally, we’ll track the translation language and what kind of translation solution was used (Chrome’s built-in translation feature, Google Translate website or Bing Translator website).

I also tried to translate a website with Firefox and it looks like the Google Translate plugin just redirects a visitor to the Google Translate Website.

But before we dive into the actual solution on how to track page translations with Google Tag Manager, first let’s take a look at how the actual translations are working.

If you’re on Chrome, do the right-click anywhere on a page and choose Translate to [some language].

Boom, the entire page’s text content is now translated to your chosen language.

If you want to change the translation options, click the Google Translate icon in the website’s address bar (right corner).

This translation is possible because the browser manipulated the website’s Document Object Model (DOM) (a quick introduction to the DOM is available here). Several modifications include:

translated-rtl or translated-ltr class is added to the <html> node of the website

lang attribute’s value in that very same <html> node is changed to the translation language of visitor’s choice

Luckily with JavaScript, this DOM manipulation can be tracked. Therefore, we can use it as a triggering condition to capture the exact moment when a visitor translates the page. More on that – a bit later.

Once you reload the page, the translation will be gone (unless, maybe, there are some settings that always for the translation. Not sure about that).

An alternative solution to how the page can be translated is by implementing the Google Translate language dropdown. You can learn more about it here. This dropdown is also supported by the solution (explained in this blog post). Such translations will be displayed as “on-page google translate” in your Data Layer and GA reports.

Translation Method #2: Google Translate or Bing Translator websites

The second translation method that I stumbled upon is by simply using the web interface of the popular translation services. You just have to visit their websites, paste the URL you wish to translate and then the translator will generate a link to the translated page.

Once you click the URL, the translated page will be opened in the iFrame. If (at the same time) you open the GA Real-time reports, you’ll notice that the hostname of the page contains a totally different hostname (if you have implemented the Show Full URL filter):

Also, the URLs of the translated page contain various query parameters. One of them indicates the translation language. We’ll use that in our tracking too.

To sum up, every time a page is loaded and the hostname belongs to Bing’s or Google’s translation services, we’ll track that as a page translation (+ read the value of the query parameter that contains the translation language).

Solution: Track Page Translations with Google Tag Manager

GTM Recipe

Curious how this Page Translations tracking with Google Tag Manager is working in detail? Continue reading.

Page Translation Listener

And here is the listener written by yours truly. Compatibility: works on all modern browsers (IE10 and lower won’t be able to track the first translation method). But I think that if visitors are using IE 10 and lower, they deserve to suffer a bit.

// Check if the page is being translated directly from bing.com/translator (viewed within the iframe)

if(window.location.href.indexOf('translatoruser-int.com')>-1){

window.dataLayer.push({

'event':'pageTranslated',

'translationLanguage':getUrlParameter('to'),

'translationService':'bing translator website'

});

}

})();

</script>

If you don’t trust my JS code’s quality, you’re not alone. I don’t trust my coding skills either. One of my goals in 2019 is to learn at least solid essentials of JavaScript, therefore, hopefully, that will improve. Luckily, tasks/problems (like the one explained in this blog post) are a great way of learning anything and feeling the joy of discovery.

Back to the quality of the listener. Since I also do not trust myself with JS (at least for now), I reached out to his excellence Simo Ahava to do a quick code review. Simo was kind to suggest some improvements and give some tips.

So don’t be afraid and feel free to use the code above for your GTM tracking needs. If you’re still not convinced, here is Simo’s Seal of Approval (I just totally made that up).

P.S. I think I need to seriously rethink my personal/work priorities because the design of this seal required way too much time (“thanks” to my limited photoshopping skills).

I’m slightly proud of myself that I was able to pull this seal off but at the same time, I’m horrified of how many other useful things I could have done instead.

Anyway, enough of self-loathing for this time. Let’s get back to business. First, we can take a quick look at the listener’s code and I’ll explain what each part does.

This part of the code is checking the DOM manipulations that are happening to the very top <html> node in the Document Object Model. If the change actually occurs and that change involves adding a class that contains “translated-” string, then an event pageTranslated is pushed to the Data Layer (together with the new value of lang attribute (which basically returns the translation language)).

The 2nd part of the listener (starting from the line 30) is responsible for tracking translations that are happening within the iframe (remember the Translation Method #2 mention in this blog post).

This part is optional and you could actually achieve the same result by using built-in GTM functionality (Pageview trigger and URL variable that reads a query parameter).

But I decided to include URL parsing in the listener in order to keep the number of variables and triggers at a minimum.

First I borrowed a function from David Walsh’s blog post that allows returning a value of a particular query parameter that is currently in the URL.

JavaScript

1

2

3

4

5

6

7

8

9

<script>

// Let's also track pageviews when the page is translated directly from translate.google.com or bing.com/translator

// A function that can return individual query parameter (borrowed from https://davidwalsh.name/query-string-javascript)

Then I created two IF statements that are checking the Page URL. If it contains translate.googleusercontent.com or translatoruser-int.com, it will fire an event pageTranslated to the Data Layer. Thanks to the function mentioned above, it’s easy to return the actual translation language that a visitor/user has chosen (because it is stored in “to” or “tl” query parameters).

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<script>

// Check if the page is being translated directly from translate.google.com (viewed within the iframe)

Data Layer Variables

With every dataLayer.push, there will be two additional keys passed to the Data Layer, translationLanguage and translationService. Currently, the translationService will return one of the 3 possible options:

on-page google translate (this means Translate to… feature after doing a right-click OR if a website has an embedded language dropdown that is using Google Translate)

google translate website (when a visitor lands on a translate.google.com and pastes the URL of the page that he/she wants to translate)

bing translator website (when a visitor lands on a bing.com/translate and pastes the URL of the page that he/she wants to translate)

In order to create those variables in GTM interface, go to Variables > New > Data Layer Variable and and enter the following information (case-sensitive!).

Now repeat the same actions and enter the information of the translationService variable).

Universal Analytics Event Tag

Now, let’s send the translation information as an event to Google Analytics. In GTM interface, go to Tags > New > Universal Analytics and enter the following settings:

Choose the trigger – Custom – pageTranslated (this is the trigger you have created in one of the previous chapters of this blog post)

Preview and Debug

Now the time has come to test. Save all the changes, refresh/enable Preview and Debug mode and see whether everything works. Possible testing scenarios:

Open your website in Chrome. Do the right-click (anywhere on the content), choose Translate to [some language]
and see if your GA Event is visible in the GA Real-time report. Important: GTM preview and debug mode does some crazy stuff when the page is translated, therefore, you should be checking events directly your GA Real-time reports.

google_tag_manager[“YOUR_CONTAINER_ID”].dataLayer.get(‘translationService’)If they return something similar to the screenshot below (of course, the values might be different) and not undefined, the listener did its job properly.
With these commands you are checking what values do those two keys store in the internal Google Tag Manager Data Model.

Go to Google Translate, paste the URL of your page and then click the generated URL of a translated page. It will open an iFrame with the translated page. With the help of Preview and Debug mode, check whether the translation events were sent to Google Analytics.

Repeat the same thing with Bing Translator. Enter the URL, click the generated URL and then in the Preview and Debug mode, check whether the GA Event tag has fired. And, of course, check the Real-time reports in GTM.

IMPORTANT: Since the GA event is set to be as non-interaction hit: true, you won’t be able to see them in the Active Users tab of your GA Real-time event reports. Switch to Events (last 30 minutes), instead.

OK, now what? Sit back and be patient. The translation data will start coming into your Google Analytics reports. Thanks to it, you will be able to measure the need for a localized version of your website. If many people are coming to your pages and are translating them, maybe that’s a good sign to invest and make the website more accessible to residents of that particular country.

Also, it would be interesting to compare the conversion rate of those sessions/visitors when page translation is used vs is not used. It might have a huge impact (or it might not at all). So what are you waiting for? Be curious, try this solution and let’s see what comes out of it.

If you know more ways how a visitor/user can translate a page, feel free to contact me. I’m more than open to update the listener (if, of course, that translation method is actually popular).

Did I miss something related to page translations and Google Tag Manager? Let me know in the comments below!

Julius Fedorovicius

In Google Tag Manager Tips

13 COMMENTS

Hi Julius, this is fantastic.
More or less on the same subject, is there any easy way to avoid data in Events of being translated? I mean, image that you have an event that pull the following data from the DOM: "Brochure Download".
If the user translated the website to Portuguese, for example, it shows: "Brochura baixada". We understand what it means but, we can get lot of Events because if each user changes the language to their own language we can end up with 163 different languages, or more.
This doesn't happens always. So, we can always filter and only show the ones in English - for example; or, create a RegEx Table/Lookup Table and change the,m as they appear. Or event, Replace them on GA. But, this reveals a huge workload for the benefits.
Is there any way we can automate this from happening?
Just picking your brains!! ;-)

Hey, Ricardo, good question. Two ideas come to mind:
- Option A: You forbid translations on a page (applies at least to Google Translate). I haven't tried this but here's a conversation about it https://stackoverflow.com/questions/12238396/how-to-disable-google-translate-from-html-in-chrome. However, this does not sound like a good option.
- Option B: data-* attributes. Ask a developer to add a certain data-* attribute to important website elements and use their values in your events (rather than element text).

oldElementClass.indexOf('translated-') === -1
Seems to be causing an issue for me. Upon further investigation it seems as if the old DOM data is not returned in Chrome unless the MutationObserver is initialized to do so. This is just a guess but removing this from the 'if' statement fixed the issue.

1. Place code on the page using GTM
2. Go to any page on the website using Chrome (on Windows)
3. Right click on the page and choose "Translate to"... (I selected English; the page was already in English, in case this is the corner case causing this)
4. Check Console and see error:
VM440:1 Uncaught TypeError: Cannot read property 'indexOf' of null