Semantic markup and structured data, tools that were once a secret weapon of cutting edge marketers, are fast becoming requirements for modern SEO. Algorithm updates like Hummingbird and ever-evolving features like the Knowledge Graph have made this stuff mission critical for many of SwellPath’s clients.

Yet, if that’s the case, why do so few of my clients actually have functional structured data on their sites? One simple reason: implementing inline microdata is hard!

The few who have been able to execute have had plenty of guidance and multiple rounds of QA to get things in ship shape. Unfortunately, most marketers don’t have the time for that!

Thank goodness that’s all changed.

Earlier this year, Google announced that it was going to start to support JSON-LD as an alternative to traditional microdata markup. Aaron Bradley over at SEO Skeptic has a great and thorough post on the announcement. If JSON-LD is Latin to you, that’s okay. It simply stands for JavaScript Object Notation for Linked Data and pretty much just means this…


This. Is. Huge!!!

The big deal is that Google is now crawling JavaScript in order to get at structured data; this was never an option before. This means that we can now do away with hardcoding microdata inline (a significant hurdle for many) and inject a JSON-LD script using a tag management platform (for an overview on what tag management is, check out Mike Pantoliano’s post on Moz).

To make things even better, we can build out dynamic and scalable JSON-LD script tags that are powered by a dataLayer for a truly elegant structured data and semantic markup solution.*


* Hat tip to Simo Ahava (the guy who’s done more for Google Tag Manager than Google) for putting up the first post I know of that discusses this concept.

The Results

Yep, the results are in: this actually works! Within a few days of implementing this on the SEMpdx website, a rich snippet started displaying in the SERPs. Note that no other event markup is present on the page; this is all data that’s being delivered via Google Tag Manager.


Have I got your attention now? Read on!

How To Deliver JSON Structured Data with GTM

What follows is a step-by-step tutorial that will show you how to use Google Tag Manager to roll out JSON-LD Structured Data throughout your site in an extremely efficient manner.

Note 1: At the time of writing, Google is only using JSON-LD structured data to create Event-based rich snippets in SERPs and Knowledge Graph features; products, people, recipes, breadcrumbs, etc. all validate with Google, but aren’t used at this point.

This post will also show you how to repurpose some of that work so that you can enable “semantic analytics” (more on that in step 6).

Note 2: This tutorial is focused on an implementation using Google Tag Manager, butthese principles are applicable with any tag management platform. Tealium, Ensighten, Adobe Marketing Cloud’s dynamic tag management, or anything else you may be using; you can easily apply these ideas to your tag manager of choice.

1. Install Google Tag Manager

If you aren’t already running Google Tag Manager on your website, head over to and create a new account and a tag container. Following that, go to Admin > Install GTM and grab the container code. This code needs to be placed on every page throughout your site and should be placed immediately after the opening <body> tag.


Note that there are two versions of Google Tag Manager, V1 and V2. For the purposes of this tutorial, we’re using V1; V2 is still a bit “beta” and, in my opinion, V1 is easier to wrap your head around.

Another thing to note is that if you want to install Google Tag Manager just to manage your JSON-LD structured data, that’s fine. You can leave your legacy tracking on the site, you just won’t be able to complete step 7 (this requires that you use GTM to manage your main page view tracking tag, AKA, a pure GTM analytics implementation).

2. Implement a dataLayer

For those unfamiliar, the dataLayer can be conceptualized as a lyaer of data that sits between your database/server-side code (the application layer) and your front-end user experience (the experience layer). Among other uses, the dataLayer allows Google Tag Manager to easily access information about pages, users, and site interactions on the fly. If you’re doing any kind of advanced analytics using Google Tag Manager already (like Enhanced Ecommerce), you already have a dataLayer running on your site; this allows Google Tag Manager to pass product and transaction information into Google Analytics.

In order for our JSON-LD Structured Data implementation to be truly scalable and dynamic, we need to utilize a dataLayer so that the properties of the entities on each page can be accessed and formatted in JSON-LD (more on that later).

Depending on what type of structured data you’re looking to push out, your dataLayer will look a little different. Below is an example for a product page on an eCommerce website.


No matter what your use case is, you’ll want to create a dataLayer object that surfaces any of the semantic properties that will change on a page-by-page basis. Any semantic properties (AKA itemprops) that will be consistent across a certain type of markup do not need to be surfaced in the dataLayer (e.g. price currency will always be USD for your product structured data, availability will always (hopefully) be “InStock”, etc.).

Some specifics: the dataLayer script needs to be placed above your Google Tag Manager container code (stick the dataLayer in the <head>). Otherwise, the GTM won’t be able to access and use the values in your dataLayer. For more thorough documentation on implementing a dataLayer on your site, check out Google’s documentation here.

3. Configure dataLayer Macros

Once you have Google Tag Manager running on your website, you’ll want to create a dataLayer Variable macro for each property you’re going to need to access. Lucky for us, all we have to do in GTM is create a new macro and choose the out-of-the-box “Data Layer Variable” macro type.

To have some standardization, let’s start all our macro names with “dl – ” followed by the property we’re accessing. Then, simply enter the name of your dataLayer variable in the “Data Layer Variable Name” field and GTM will do the rest. Note that dataLayer version 2 allows you access nested variables, if you need to.


Let’s take the product above as an example. To provide Google with all of the semantic information that we want to, we’ll need to grab the product name, the description, the price, the average rating, and total ratings/votes. That means we need to create five dataLayer Variable macros in total.

  • dl – productName
  • dl – productDescription
  • dl – productPrice
  • dl – productRating
  • dl – productReviewCount

4. Build a Tag to Construct JSON-LD Structured Data

Once we have all those dataLayer macros created, we can use them as variables in a template. We’ll want to create one template for each type of structured data that we want to push out using JSON-LD. To create your own template for pretty much any type of semantic entity, hop on over to, find your desired schema, grab the JSON-LD example, and convert it into a template.

Let’s continue with our product structured data example. The script below is your run-of-the-mill JSON-LD script for a product. All I’ve done is replaced the actual values with the names of the macros we just created in GTM (step 3). Note that you can use macros in ANY custom HTML or JavaScript tag in Google Tag Manager by just typing a macro name within two curly braces, {{like this}}.


For standardization, let’s name our JSON-LD Structured Data macros something like, “Semantic – Product JSON-LD”.

5. Create Rules to Fire the Tag(s)

Now this is where the rubber meets the road, so to speak. We want to create a rule in Google Tag Manager that will trigger our custom JSON-LD tag to fire on all relevant pages. Assuming your site has a clear URL directory structure, you can simply create a rule that is satisfied when the page’s URL contains /products/.


The end result is that for every product page on your website, the rule will trigger your JSON-LD tag. The tag will then dynamically be filled out with the dataLayer variables (based on the dataLayer that is embedded in your source code, and that finished JSON-LD structured data tag will be accessible and indexable to Google!

Once you make sure everything is configured the way you want, push your container live and make sure to validate your JSON-LD using Google’s new and improved structured data testing tool.

6. Build a JavaScript Macro to Enable Semantic Analytics

As it turns out, this method of pushing out JSON Structured Data via Google Tag Manager is also a much more elegant way of enabling semantic analytics. In my Moz post from last year, I made a case for going beyond simply implementing semantic markup and structured data to actually tracking the performance of semantically marked up content. We already have this incredibly rich data for our content, why not actually track that and, even better, use it to enhance our data collection and analytics capabilities?

On top of having awesome rich snippets for your content in the SERPs, imagine being able to access the semantic properties for your site’s content in Google Analytics. It would not only allow you to see how pages with semantic markup perform relative to their non-marked up counterparts, but it would allow you to dig into what semantic types and what properties perform well.

  • Do products with a price under $50 have the best conversion rate?

  • Are continuing education events hosted on a specific day of the week outperforming your other events in terms of registrations?

  • Are blog posts and articles written by specific authors seeing exceptional engagement metrics?

The possibilities are nearly endless!

In my previous post on semantic analytics, I used a set of custom JavaScript macros to grab inline microdata and send that to Google Analytics. It worked well enough, but it was a little clunky and could easily be broken if the site’s content changed (not to mention WYSIWYG nightmares). However, we can leverage what we did in the first part of this tutorial to greatly simplify and streamline the process of enabling semantic analytics.

So let’s create one more Macro in Google Tag Manager called “Semantic Values”. The type will be Custom JavaScript. This will allow us to use a JavaScript function and ultimately return a value that GTM can use to feed our semantic analytics.

The function below is a simple one that you’re free to expand upon. After declaring a “label” variable, we create a “productName” variable and fill it with the value of one of the dataLayer Variables that we created in step 3 (the name of the product). We then check if that variable contains something and if the length is anything greater than 0 (0 would mean the variable was empty), we fill in the “label” variable: the “productName” plus the classification “(Product)”. If the “productName” isn’t set, we set “label” equal to “no semantic markup”.

This macro will always have a value: either a meaningful description of what semantic markup is on the page or a declaration of “no semantic markup”.


As with the other steps, you can modify and/or expand this based upon the needs of your site. By adding additional IF statements (for example), you could check for other semantic properties (like “eventName”, “recipeName”, “personName”, etc.) and then combine all of those and output a rich summary as your “label”.

7. Set Up a Custom Dimension for Semantic Analytics

Now that we have all the labeling set up, we want to feed that into Google Analytics. In step 1, I mentioned that you’d need to be tracking page views via Google Tag Manager for this step to work. That’s because you’ll need to attach a custom dimension to your page view tracking tag.

Before we do that though, you’ll want to login to your Google Analytics account and go to the “Admin” section. Head to Property > Custom Definitions > Custom Dimensions. Create a new custom dimension called “Semantic Analytics” and set the Scope to “Hit”.


Once you confirm and click “Done”, you’ll see a list of all your custom dimensions. Remember what the “Index” number is for “Semantic Analytics” and hop back over to Google Tag Manager. Navigate to your page view tag and scroll down and click into More Settings > Custom Dimensions and then add your index number under Index and then reference your “Semantic Values” macro from step 6.


Now each page view will have either a semantic label or “no semantic markup”. When viewing reports in Google Analytics, simply add “Semantic Analytics” as a secondary dimension and analyze to your heart’s content!

A Little Head Start

I love helping people figure out how to do cool stuff, so if you have any questions about how to get this up and running for your site, just let me know if the comments. However, I thought I could do a little up front work to get you pointed in the right direction.

A great feature of Google Tag Manager is that you can export and import whole containers (all the tags, rules, and macros), so I’ve created an importable GTM container that you can add to your existing container.


A few notes:

  • This will get you set up with product, event, and person JSON structured data tags. You can implement all three or just one. All the tags and macros you need are in there already.

  • This container is for Google Tag Manager V1. It won’t work with V2, but if there’s significant interest I can build one out for V2.

  • Once you download the container JSON file, you’ll want to log into your GTM account and select the Import/Export option. Import with the “Merge” option; this will ensure that you don’t overwrite your existing tags.

  • There’s a pseudo Read Me file that’s stored as a tag in the container. It has instructions for implementing the specific dataLayer that you’ll need.

  • Fair warning – I only pretend to know JavaScript.   There may be bugs in my “Semantic – Custom Dimension Values” macro, but I’ve tested and everything functions well in my tests.

Thanks for reading and I hope to see more structured data out there on the web. Happy optimizing!