While working at Distilled, I often come across issues with implementing technical SEO changes to websites. This can be for a variety of reasons: some sites have rigid CMSs that don’t allow for customization, while others have development queues of many months (or years, in some cases!).
In these cases, it doesn’t matter how good a job we do identifying the changes that need to be made in order to improve a site’s performance — if nothing can be implemented, our advice is worthless. Something we like to say at Distilled is that “it's not our job to deliver reports, it's our job to effect change.” In order to make this a reality for clients with the types of issues I mention above, it’s necessary to explore alternative ways of getting changes made.
One option for this is to implement some sort of "meta-CMS." This is a system that sits on top of an existing CMS, and allows you to make specific changes to pages on a site, bypassing the technical and/or technical constraints that a CMS may entail. <plug> While also having the ability to split-test SEO changes across groups of pages on a website, our own DistilledODN tool can be (and is being) used for this purpose. </plug>
For sites for which a meta-CMS is not an option, a third solution is to use a tag management system (when one is installed and configured). In this article I’ll be referencing Google Tag Manager (GTM), which is the most widely used tag manager (accounting for 72.6% of the tag management market, according to BuiltWith.com). Tag managers use a single JavaScript container tag to inject various different tags (e.g. tracking, remarketing, and CRO tags) into webpages. The benefit of this is that in order to add or amend tags, it’s not necessary for a developer to make any changes to the page; changes can be made to the tags within a container and these tags will be implemented on the page.
Tag managers are mostly used to implement off-the-shelf tags, like Google Analytics or Facebook tracking. A lesser-known functionality is to implement custom HTML snippets (which can include JavaScript code). This allows you to make any arbitrary changes you like to the HTML of a page (or set of pages) based on rules you define. A benefit of using tag managers is that you can apply changes to pages at scale across a site with a single tag.
This allows us to bypass CMS restrictions and development queues, directly applying changes to things like page titles, canonical tags, and on-page content.
Because tag managers use JavaScript to implement tags, in the past it hasn’t been seen as a reliable way to make SEO changes. The traditional thinking has been that, in terms of making SEO changes, Google (and other search engines) can’t reliably execute JavaScript, so any changes made with JavaScript would likely be ignored. However, recently, we are seeing evidence that changes are being picked up by Google, including implementation through tag managers. This article will show a few examples of this in action, and how to implement these sorts of changes on your site.
How to make any HTML change using GTM
The sorts of changes we’re interested in involve either adding in new elements to a page, amending the content or attributes of elements, or removing elements from a page. For each of these, you’ll potentially need knowledge around:
- CSS selectors and HTML, in order to know which elements on the page to change/pull data from
- JavaScript (especially jQuery*), in order to inject elements into the page
For example, there are simple elements you can add into a page that don’t require anything to be extracted from the page (other than the page URL, which is an inbuilt variable in GTM). On the other hand, there are more complex changes, such as adding in product structured data on e-commerce sites, that require you to extract data from the page (e.g. product names, prices, etc).
If you’re not technical and just want to be able to implement changes in GTM, I’ll include an off-the-shelf GTM container at the end of this post, with instructions on how to use it.
*If your site has jQuery loaded, it will be much easier to extract and write elements to a page. In order to check this, you can open the Console while viewing the page in Chrome or Firefox and type “jQuery” (case-sensitive). If jQuery is not loaded, you will see an error message.
Inserting an element
In order to insert an element into an HTML page, you can use a custom HTML tag in GTM. Below is an example of a custom HTML tag that inserts a meta robots noindex tag to the page. This below example uses jQuery, but you can do the same thing without jQuery if need be.
<script> // Removes any existing meta robots tag jQuery('meta[name="robots"]').remove(); // Create an empty meta element, called 'meta' var meta = document.createElement('meta'); // Add a name attribute to the meta, with the value 'robots' meta.name = 'robots'; // Add a content attribute to the meta element, with the value 'noindex, follow' meta.content = 'noindex, follow'; // Insert this meta element into the head of the page, using jQuery jQuery('head').append(meta); </script>
This snippet will add a meta robots noindex, follow element, after deleting any existing meta robots elements, to every page to which it applies. In GTM, every tag is associated with at least one trigger, which tells the container when the tag should be applied. For any changes we want Google to take note of, we want the tags to trigger as soon as the page loads. We can decide which pages the tag should load on using any variable we like to specify pages.
The above HTML tag can be amended to create other types of elements. These are explored in the example section below.
Extracting data from the page
There are two approaches to extracting data from a page. You can either use GTM’s inbuilt variables, which allow you to extract the text or an attribute of an element based on CSS selectors, or do the same with JavaScript and/or jQuery within the custom HTML tag.
In the context of SEO changes, the most common place where you’ll want to extract data from the page would be to construct structured data markup using JSON-LD. In order to demonstrate the different methods, I’ll show a way of constructing product markup by extracting items both in GTM variables and within a custom HTML tag.
For this example, we can imagine a site with product pages that have data about their products each given unique IDs within the HTML of the page. In reality, you’ll need to find CSS selectors that give you the exact elements you’re looking for. A great tool for this is the Selector Gadget Chrome extension that allows you to find a unique CSS selector for any element on a page.
For our example, let’s imagine the following IDs:
Element ID |
Associated Schema Item |
---|---|
product_name |
name |
product_img |
image |
price_value |
price |
price_currency |
priceCurrency |
ratings_count |
reviewCount |
avg_rating |
ratingValue |
Using GTM variables
If you’re using GTM variables to pull the data out of the page, you’ll need to set up a variable for each of the above elements. You can do this by going to the Variables menu and clicking "NEW" under "User-Defined Variables."
For each of the above elements, define a new "DOM Element"-type variable, using an ID or CSS selector appropriate to each item. For all of the above, you’ll want to leave the "Attribute Name" field blank except for the image, where you’ll want to extract the src attribute.
In order to pull these variables into some JSON-LD markup, we’ll need to set up a custom HTML tag that references them.
Note that, in order to reference a GTM variable, you need to wrap them in double curly brackets. Also note that we’ve referenced “Page URL,” which is a default built-in variable in GTM. The last four lines of this script are turning the jsonData element into part of a script element, with type “application/ld+json,” to be injected into the head of the page.
Using jQuery
We can do the same thing as the above without touching GTM variables, instead using a single HTML tag. In this case, we need to use jQuery to do the same job that the GTM variables are doing.
This HTMl tag is very similar to the one using variables, except in place of each variable, it uses jQuery to extract data from the page. Obviously this is only possible for pages that have jQuery loaded, but equivalent expressions are possible in JS without jQuery.
The advantage of this method is that you don’t need to set up individual variables for each element — all of the information is contained in this one tag. On the other hand, if you have variables being referenced by many different tags and/or triggers, it makes sense to use variables, as if and when you need to change the definition of the variable, it will apply to all tags and triggers without the need to change each individual one.
Does it work?
This is all very well and good, as long as Google actually sees and indexes the changes that are being made via GTM. As mentioned above, there is uncertainty as to whether Google can index (and even then, whether it respects) markup and content implemented through JavaScript. I have three examples from the last couple of months of changes being made through GTM, and immediately respected by Google.
1. JSON-LD structured data markup
With the above example, using both the jQuery and variable methods, we can see rich snippets in search results, where there is no structured data at all on the page before GTM applies it. The below snippet is from a dummy page where a product snippet has been applied.
2. Canonical tags
We have also seen evidence of Google paying attention to canonical tags implemented through GTM. The below chart (taken from STAT) shows the number of keywords for which a page ranked, before and after a canonical tag was implemented using GTM. After the implementation, the page stopped ranking for any keywords, and the destination of the canonical tag started ranking in its place.
3. Mobile switchboard tags
In this example, a site had separate desktop and mobile versions on different subdomains. Mobile switchboard tags were implemented on the desktop site using GTM, and immediately pages on the mobile subdomain began being indexed.
Some examples of tags
All of the below tags can be found in this dummy GTM container. They are applicable only for sites that have jQuery loaded. In order to implement the tags, take the following steps:
- Download the container from Google Drive.
- Within the "Admin" menu of the GTM container you want to import into, select "Import Container":
- Select the container file from its download location, and select "Merge" and "Rename conflicting tags…" in order to not overwrite any tags that are already set up.
- Click "Confirm."
- Once the container is loaded in, make necessary edits to tags so that they are suitable for your site, and assign triggers to apply only to pages that are relevant.
Tag to insert mobile switchboard tags
If you have a separate mobile site with the same page and URL structure, this tag can add in switch tags, replacing "www" with "m" in domain names. It will also add a canonical tag to mobile pages that don’t already have one, pointing to their direct desktop equivalents. You can customize this tag to have whatever subdomain your mobile site is on by changing the domains on lines 3, 8, 12, and 16.
Tag to add noindex tag
This is identical to the tag mentioned above. Take care with the trigger if you use this — you don’t want to accidentally noindex every page on your site! This tag will remove any existing meta robots tag, and write a "noindex follow" meta robots tag.
A potential use case for this would be to noindex any product pages for out-of-stock products. You could use a trigger that detects an "out of stock" in a particular element on the page, and automatically adds in a noindex tag when that is the case.
Tag to add self-referential canonical
This will add a canonical tag to pages, pointing to themselves — or, if the page has URL parameters, pointing to a parameterless version of the page. Take care when implementing this on pages that are intended to canonical to other pages (including on separate mobile sites), as it will overwrite any existing canonical tags. Also make sure that you do not implement it on a page that has parameters, and is not intended to canonicalize to the version of the page without parameters (e.g. paginated versions of pages).
Tag to insert breadcrumb structured data
This tag cycles through any breadcrumb elements that share a CSS selector on a page, and writes them into JSON-LD. It then takes either the canonical URL of the current page, or the current URL if no canonical exists, and writes that as the final breadcrumb element.
This tag is named "Insert Breadcrumb Markup to Any Page." Within the tag, you should rename the "selector_for_breadcrumb_link" on lines 8 and 29 of the tag to be a CSS selector of the breadcrumb links on the page.
Tag to insert product structured data
This is the jQuery example discussed above. Replace the IDs within the selectors of the specific elements you wish to include in the structured data. If there are no aggregate ratings, remove lines 16–21.
Thanks for this post, specially the part titled "Does it work?" ha ha :D. I've loved it!! When I wrote "Here is How to Generate and Insert Rel Canonical with Google Tag Manager", here in Moz too, but some moths ago, lots of people have doubts about functioning. So I am really glad reading your post and your canonical tests results. Of course it works. Sometimes, things only need some more time to work :) Tag Managers have been created to do things like these possible.
Recently I've done one more experiment to test changing canonical dynamically with GTM and JS (although having Yoast SEO predefined with a different canonical value), and it DOES work :))
Thanks again and kind regards.
Lucía Marín
Hi Lucía,
Your post was part of the inspiration for this one, so thanks! I'm glad I could provide some more evidence to go along with what you've seen.
Sam
So stoked to see this idea catching on!
Lucia, I'm so glad that I got to see your post when I did and in time to mention it in my MozCon talk.
Sam, great piece. Thanks for spreading the good word!
Wowwww, thankyou very much to both, Sam and Mike!!
Mike, what a big honour to be mentioned by you in your Mozcon talk. Besides, I saw you have also included the URL Variable creation process at your post 29 Advanced Google Tag Manager Tips Every Marketer Should Know and I really enjoyed it. Nice article and a lot of good ideas to take into account too :D
I really love the almost endless creativity functionality that GTM has. From now on, we shall just imagine and create <3
Thanks so much again to both and kind regards :))
Hey Sam Nemzer!
I have one question that I have been scratching my head over this for far to long. Sincerely hope that you have a better solution.
When you can't use paths as triggers, but have to find something else for the trigger to fire (say a css-selector). How would you set that up? Can tell you how I worked around this (but I don't think my solution is ideal so I will wait for a reply).
Hi Hans,
I would do this by setting up a 'DOM Element' User-Defined Variable that relates to the CSS selector you're interested in. You can then set the trigger to fire only when an attribute of that selection matches whatever value you like (with regex if you want to match a range of values) .
Hey again Sam, and thanks for your answer!
Need an example to wrap my head around this, hoping you can offer just a little more help. :-)
For a customer I found that the CSS-selector for add-to-cart button differed on single-product-sites from everywhere else on the site. The CSS-selector was:
.product-shop .btn-cart
So for your sollution the custom variable I need to set up then would be:
That particular button always says "Buy" (in norwegian tho) in innerHTML. So would I then set my trigger to be the following?
'Custom variable name' matches RegEx 'Buy'
Yes that would work - if no element is found with that selector on the page, or with text other than 'Buy', that trigger won't fire.
Nice job, Sam! Looking forward to testing this. You mention the self-referencing canonical tag shouldn't be used on pages with parameters, such as paginated pages. Any reason this couldn't be extended for that purpose?
No reason at all, in that case you would need to come up with some slightly more complex javaScript (for example this suggestion from Stack Overflow) that would extract parameters from the URL, and then inject the parameters you want to keep (e.g. page number) into the canonical URL. I hope that makes sense!
Amazingly I did this, or at least referenced much of this in a talk yesterday (completely co-incidental although a Distilled employee was there)... Question for you though :-)
Do you have any issues with ampersands, or other charachters the way you have done it ? this is an issue I have been experiencing (and a few others).
Definitely coincidence - I only realised you were talking about this subject after I'd written most of this post (although the ideas may have circuitously come from you originally).
I haven't seen anything weird with ampersands - what exactly was the issue you saw?
if say you have an ampersand in a product name (the site I work on has a shed load of them) the testing tools suggests that its incorrect, I have been replacing them with and but you write your code slightly differently :D.
The site hasn't got jQuery so our containers literally are as below, whereas you build it up as a string, wondering if that encodes things better...
<script type="application/ld+json">
{
"@context": "https://schema.org"
thanks for the great article! Have you tried or do you know if Google robots have the same behaviour if the tags are implemented on DTM?
I'm afraid I haven't had any experience doing this kind of thing with DTM - if anyone else has done so I'd be very interested to hear what results they got
I tried DTM to remove a no-index robots tag to no avail.
(var i = t.querySelectorAll('meta[name="robots"]'), a = 0; a < i.length; a++) i[a].remove()
It works when inspecting the element but not when looking at the fetch and render HTTP response in GSC:
https://cl.ly/0Z1100240P3c
Great article, Sam, this is perfect guide to start with google tag manager. This will help a lot to understand Google Tag manager. I will apply all this on my recent blog. Hope we will get better result.
Brilliant Article Sam! Thank you for this, i have struggled with Schema and stuff like that before but this really puts the nail on the head for me! I shall print this off and show my colleagues!
Thank you again.
Sam, your article is brilliant! Can't wait to try this out. Love structured data.
This is an excellent way to use google tag manager.
Anyone know if there are site speed implications to this type of approach or is it more or less the same?
Really interesting stuff, thanks for posting!
Interesting article. Have you verified that Google respects noindex, nofollow tags added through GTM? I would assume that if it works for Canonical tags it would also work for noindex.
I don't have any examples to share, but noindex tags are another thing Google pays attention through when they're added with GTM.
Using GTM for fixing your pages after they are sent out from the server is a bandaid solution at best. Google’s JavaScript reading is still not perfect and has been noted to lose content that’s not loaded fast enough. If it’s an option, working with your development team and finding solutions that are going to work all the time is better. Take Schema for example. Schema that’s added to the page via GTM isn’t picked up by other search engines such as Bing - which is not surprising. Why does that matter? Apple Siri uses Bing as its voice search, which is highly influenced by Schema.
Don’t rely on JavaScript to produce the results you expect.
Well - having done multiple implementations where we use JSON LD deployed through GTM, it is being picked up fine by Google - this was some custom, Google only code so I am not too worried about Bing. Bing is important but often this is a, lets get stuff done.
Often 10 minutes work in GTM will give you a much better ROI than getting it deployed through your development team...
Why do you think that Bing doesn't crawl JavaScript ?
Bing doesn't validate Schema markups in JSON-LD - it has to be in Microdata or RDFa if you want Bing to read and understand that markup. But JSON-LD is a better format, so hopefully Bing will come around soon.
Also Bing isn't set up so that it properly reads tags inserted by GTM. Try validating a Bing Webmaster Tools account by adding the code through GTM if you don't believe that (shouldn't take you many minutes to test). Haven't tested this with other TMS's than GTM tho, so they might read tags inserted by other TMS's.
A TMS should be used primarily to insert tracking-tags and event-tags that doesn't need to slow down loadingtime of websites. But most SEO's out there work for clients with a limited budget and with little to no access to programmers/developers that can insert and fix stuff the proper way. So knowing how to do this through GTM will help you satisfy at least Googles needs until a time when you can go from this "bandaidsolution" to implement it properly on the site. (The results it gets you from Google usually validates such a request).
And while Google does pick up on ie. Schema markup added through GTM, it is not the best solution according to Juan Felipe Rincon at Google. He advised me to implement it directly in the sourcecode when I asked (met him at SMX London last week). The main reason he gave for this was crawlbudgets. It doesn't take much time for GTM to insert a static script to a given page, but if you try a dynamic script like this article suggests - then you have to realize that GTM takes some time to identify variables and fill the script before inserting it. Being inserted in async-dl-tag means that this will be perhaps the last operation performed before the site is fully loaded. And by that time Googlebot will usually have moved on to crawl the next site since it doesn't really stick around when it's just a GTM tag since that is understood immediately. This won't happen if you ie. opt for a bootstrap solution to fill the JSON-LD script with the same info - since googlebot will wait to see what that script does before moving on.
That being said, if you don't have access to a dev/programmer that can help you with this then GTM is a great solution! And it's one I often go for when it comes to adding proper Schema markups (on top of all trackingcodes and event-tracking) because of clients wanting to keep costs down.
I actually was thinking the exact same thing and took that test one step further.
I took one of our GTM containers and added the robots code above then did "Fetch as Bingbot" for one of the pages. The results didn't contain the robots meta tag but the inspected page does contain it. That could lead to the possibility that Bing won't see this at all and crawl the pages you don't want them to.
Looking for a job, Hans? https://verbinteractive.workable.com/j/781AA8037E
Flattered that you asked, but I am very happy with my current employer (in Norway). :-)
But it is weird that Bing can't fetch inserts from GTM nor understand JSON-LD markups. They really need to catch on at some point or Apple will go back to Google - and then they lose their one really big fighting chance against Google.
Great job on this article, Sam. We primarily use GTM for conversion tracking code implementation. I've never considered using it as an additional system to manage meta data on sites that are a bit more difficult to work with! - will definitely be making use of this now! I'd love to see more articles based on more advanced conversion & value conversation tracking if you've got anything in the pipeline?
Thanks Danny!
I'm not planning anything conversion-related at the moment, but the place I go to if I want to know anything about GTM is Simo Ahava's excellent blog
Ouch, Danny, I have lots of articles about GTM & Conversion, but in Spanish.
In case you want to take a look. E.g.
https://translate.google.com/translate?sl=es&tl=en...
I'll try to write here at Moz again in English :)
I've been doing some work on a website that has a very limited cms so I was trying to find a way to implement schema and custom html for individual pages and I was thinking about gtm as a possible solution so this was a very timely article. Thanks for the insight
Wow, this article is so complete. A year ago, I was talking with my sysadmin about Google Tag Manager, but I did not know anything about the things you cand do with this tool. The problem is it seems you need to know how to program somethings in order to implement functionalities to the website. I am a 0 in coding, so I will talk to my sysadmin again to pray for help haha. Thanks for de info!
Hi Sam, very interesting post. For non technical seos, how can we learn managing google tag manager? Is it woth it?
Such a legit guide on Google Tag Manager, we have very little experience with Google Tag Manager but are excited to start using some of these great examples and tips to get started! Thanks for the awesome insight.
I usually don't read articles about GTM but this post is awesome and was totally worth reading! Thanks for sharing! Cheers, Martin
A really good article on GTM, beautifully written, it would help even the novices to implement GTM without much technical help.
Really enjoyed your article. Can't wait to set up some experiments and test my ability to make it work for clients. Is there really a way out of development queue hell? That possiblily is sooooo exciting.
Thanks
Thank you very much sam To see if I can implant it like this, I have tried and I have not got it. please help!!!!
Thank you for sharing your knowledge !! I've been learning little by little Google tag manager and any SEO web developer we have to use it from now on. So again we have to put the batteries. Does anyone know if there is any course of Google's own gag manager? Just as there is adwords and analytics
Great article. How would i extract the price minus the currency symbol if my page html was something like:
<p id="price">£1.78</p>
Hey Michael,
Easiest is to set up a custom JavaScript variable. For that instance I would do something similar to this (spending the time it takes me to write this here - so you might have to work it just a little).
function() {
var element = document.querySelector('#price');
var price = element.innerHTML.replace('£', '');
return price;
}
Hi Sam! Great tactical article and useful examples. As much as I hate using bandaid solutions, I find it quite handy for large entreprise website with multiple CMS and level of ownership to get things implemented on a decent timeline! Now to get that GTM code implemented first...
Hi Sam, thanks for the comprehensive guideline!
While injecting JSON-LD is pretty clear what about removing elements with GTM? Let's say I need to remove Schema markup generated by CMS (have no CMS access and/or structured data setting in it) and then fire a correct markup using the method above. Does removing elements eligible in GTM?
Great article. I have very little experience with Google Tag Manager. Thank you so much sharing.
Hi Sam!
Amazing post with Google Tag Manager implementation with SEO functions, I testing this with my websites. thanks for sharing! :)
Best regards!
Sam this is great, thank you. Our AdWords & SEO Managers are constantly troubleshooting tag manager so this will be a great resource. Cheers.
I liked the way of presenting the article. Thanks for sharing, it would be useful for the readers who are looking for these type of information.
Thank you for this great article, we hope it will help to increase our statistics of our main source, we would love to read more articles based on more advanced conversion & value conversation tracking.
Superb article! Thanks Sam for sharing.
1 in 3 people check websites on Smartphones. If GTM helps to change into a friendly website then it’s wonderful.
A wonderful article!!
Is perfect to start with google tag manager
Very Interesting article. I have got some advanced seo idea from your article. I will impliment in my blog. Thank you so much sharing.
Hi Sam
Thanks for publishing best information in the shape of this article. I seek knowledge after reading this article. You wrote it well with examples.
Is there any knowledge in particular that you are left wanting, or has Sam's article just inspired you to expand your knowledge in general? In the latter case, I recommend the "random article" function on Wikipedia.
I have some knowledge and getting more from moz. I am getting start soon and inspired from moz content. Also searching how to create great content for a back link. I think moz will be helpful to create content and to get unique back links in near future.