Adding Schema.org Microdata to your Shopify Product Pages to enable Google Merchant Center automatic updates (with product variant support)

If you are using Google Merchant Center to drive either your Google Product Listing Ads (PLAs) or for your Dynamic Remarketing Ads, you have likely ran into an issue where Merchant Center will sometimes give you a warning that there is insufficient match of micro-data information and that it is no longer performing automatic item updates.

merchant-center-warning

This is generally due to incorrect or incomplete micro-data on your product page, in particular if you have submitted deep-linking product variant data to your merchant center.

The Fix: Add Variant Level Micro-data

To fix this issue, you need to know some basic HTML and be able to navigate your product.liquid file.

Firstly, I recommend you read this great write-up by Gavin Ballard on adding micro-data to your Shopify store: http://gavinballard.com/microdata-on-shopify-and-other-ecommerce-platforms/

There is overlap with what is discussed below, but the article provides some good background and other benefits of using micro-data.

Product.liquid

All the required edits should be limited to your Product.liquid file. In a nutshell: You need to define a Product itemscope which will have properties such as Product Url, Product Image, Product Title, and Product Description.

Nested within the Product will be an Offer itemscope that will contain the product variant’s price, currency, condition, and availability.

Schema.org Product ItemScope

Open your product.liquid file and add the Product itemscope property to the outer most div. The first line of your product.liquid should look something like this:

<div itemscope itemtype="http://schema.org/Product">

 

Directly below this line, you should add the product variant’s url and image markup as so:

<meta itemprop="url" content="{{ shop.url }}{{ product.selected_or_first_available_variant.url }}" />
<meta itemprop="image" content="https:{{ product.selected_or_first_available_variant.image.src | product_img_url: 'grande' }}" />

 

Find where your product’s title and description are displayed, and add itemprop=name and itemprop=description attributes as shown below:

<!-- Product Title -->
<h1 itemprop="name">{{ product.title }}</h1>
<!-- Product description -->
<div class="product-description" itemprop="description">
{{ product.description }}</div>

 

Schema.org Offer ItemScope

Now you need to find the place in your product.liquid file where you display your price, find a wrapping div tag and add the Offers itemscope attributes to the tag. The Offers itemscope MUST nested within the Product itemscope div tag.

<div itemprop="offers" itemscope itemtype="http://schema.org/Offer">

 

Immediately after this line you can add the product variant’s price, currency, condition, and availability microdata as so:

<meta itemprop="priceCurrency" content="{{ shop.currency }}" />
<meta itemprop="price" content="{{ product.selected_or_first_available_variant.price | money_without_currency | remove: ',' }}" />
<meta itemprop="itemCondition" itemtype="http://schema.org/OfferItemCondition" content="http://schema.org/NewCondition"/>
{% if product.selected_or_first_available_variant.available %}
	<link itemprop="availability" href="http://schema.org/InStock" />
{% else %}
	<link itemprop="availability" href="http://schema.org/OutOfStock" />
{% endif %}

 

Putting it all together

Once done, your product.liquid should have roughly the following structure.

<!-- BEGIN Product itemscope -->
<div itemscope itemtype="http://schema.org/Product">
  <meta itemprop="url" content="{{ shop.url }}{{ product.selected_or_first_available_variant.url }}" />
  <meta itemprop="image" content="https:{{ product.selected_or_first_available_variant.image.src | product_img_url: 'grande' }}" />

  <!-- Product Title & Description -->
<h1 itemprop="name">{{ product.title }}</h1>
<div class="product-description" itemprop="description">
  {{ product.description }}</div>
<!-- BEGIN Offer itemscope -->
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
    <meta itemprop="priceCurrency" content="{{ shop.currency }}" />
    <meta itemprop="price" content="{{ product.selected_or_first_available_variant.price | money_without_currency | remove: ',' }}" />
    <meta itemprop="itemCondition" itemtype="http://schema.org/OfferItemCondition" content="http://schema.org/NewCondition"/>
    {% if product.selected_or_first_available_variant.available %}
    			<link itemprop="availability" href="http://schema.org/InStock" />
    {% else %}
    			<link itemprop="availability" href="http://schema.org/OutOfStock" />
    {% endif %}</div>
</div>

 

Final Steps

  1. Save and test your new product page in Google’s Structured Data Testing Tool, and fix all errors if any.
  2. Wait and check back periodically in Google Merchant center to ensure no new errors were introduced. It will take a few weeks before the “unable to update” warning disappears.

Related Reading

Shopify + Facebook Product Feed: How to build your own Product Catalog

If you want to setup Facebook Dynamic Product Remarketing ads for your Shopify store, you will need to upload your store’s product catalog to Facebook. Below is a walk through of how to generate your Facebook product feed.

This is an advanced topic and so I will assume you have a basic understanding of HTML/Liquid, the Shopify Store Admin and Facebook Business Manager.

Step 1: Install the Shopify Google Shopping App

Installing this free app will allow you to configure various properties on your products such as Age Group, Gender, and Product Category.

Step 2: Create a Custom Collection Template for your Feed

This step involves getting your hands dirty with code. If you are not a developer and have a low appetite for risk, consider asking a coder to do this step for you.

What we are doing here is creating a template, that when assigned to a collection, will cause that collection to be displayed as XML instead of HTML.

In your Shopify admin, go to:

  • Online Store > Themes
  • In the dotdotdotmenu and choose Edit HTML / CSS
  • Under Templates, choose Add a new Template
  • Choose collection from the drop down and name your template fb-product-feed

Paste the following code into your new template and click Save. (This code is also available on Github here: Shopify Facebook Product Feed Template)

{% layout none %}<?xml version="1.0"?>
<rss xmlns:g="http://base.google.com/ns/1.0" version="2.0">
{% paginate collection.products by 1000 %}
{% assign CountryCode = 'US' %}
{% if shop.currency == 'CAD' %}{% assign CountryCode = 'CA' %}{% endif %}
{% assign Color = "" %}
{% assign Size = "" %}
<channel>
<title>{{ shop.name }} {{ collection.title | replace: '&', '&amp;' }}</title>
	<link>{{ shop.url }}</link>
<description>{{ collection.description | strip_html }}</description>
{% for product in collection.products %}
{% assign GoogleProductCategory = product.metafields.google.google_product_type %}
{% assign Gender = product.metafields.google.gender %}
{% assign AgeGroup = product.metafields.google.age_group %}

{% comment %}Output the top level product and then all variants{% endcomment%}
<item>
<title>{{ product.title | strip_html | strip_newlines | replace: '&', '&amp;' }}</title>
	<link>{{ shop.url }}{{ product.url }}</link>
<description>{{ product.title | strip_html | strip_newlines | replace: '&', '&amp;' }} {{ product.description | replace: '</', ' </' | strip_html | strip_newlines | replace: '&', '&amp;' }}</description>
<g:google_product_category>{{ GoogleProductCategory | replace: '&', '&amp;' }}</g:google_product_category>
<g:item_group_id>shopify_{{ CountryCode }}_{{ product.id }}</g:item_group_id>
<g:id>{{ product.id }}</g:id>
<g:condition>new</g:condition>
<g:price>{{ product.price | money_without_currency }} {{ shop.currency }}</g:price>
<g:availability>{% if product.available %}in stock{% else %}out of stock{% endif %}</g:availability>
<g:image_link>http:{{ product.featured_image.src | product_img_url: 'grande' }}</g:image_link>
<g:gtin>{{ product.barcode }}</g:gtin>
<g:brand>{{ product.vendor }}</g:brand>
<g:mpn>{{ product.sku }}</g:mpn>
<g:product_type>{{ product.type }}</g:product_type>
<g:age_group>{{ AgeGroup }}</g:age_group>
<g:gender>{{ Gender }}</g:gender>
</item>

{% for variant in product.variants %}
{% for option in product.options %}
{% if option == 'Color' %}{% capture Color %}{{ variant.options[forloop.index0] }}{% endcapture %}
{% elsif option == 'Size' %}{% capture Size %}{{ variant.options[forloop.index0] }}{% endcapture %}
{% endif %}
{% endfor %}
<item>
<title>{{ product.title | strip_html | strip_newlines | replace: '&', '&amp;' }}</title>
	<link>{{ shop.url }}{{ variant.url }}</link>
<description>{{ product.title | strip_html | strip_newlines | replace: '&', '&amp;' }} {{ variant.title | strip_html | strip_newlines | replace: '&', '&amp;' }} {{ product.description | replace: '</', ' </' | strip_html | strip_newlines | replace: '&', '&amp;' }}</description>
<g:google_product_category>{{ GoogleProductCategory | replace: '&', '&amp;' }}</g:google_product_category>
<g:item_group_id>shopify_{{ CountryCode }}_{{ product.id }}</g:item_group_id>
<g:id>{{ variant.id }}</g:id>
<g:condition>new</g:condition>
<g:price>{{ variant.price | money_without_currency }} {{ shop.currency }}</g:price>
<g:availability>{% if variant.available %}in stock{% else %}out of stock{% endif %}</g:availability>
<g:image_link>http:{{ variant.image.src | product_img_url: 'grande' }}</g:image_link>
<g:gtin>{{ variant.barcode }}</g:gtin>
<g:brand>{{ product.vendor }}</g:brand>
<g:mpn>{{ variant.sku }}</g:mpn>
<g:product_type>{{ product.type }}</g:product_type>
<g:age_group>{{ AgeGroup }}</g:age_group>
{% unless Color == "" %}<g:color>{{ Color }}</g:color>{% endunless %}
{% unless Size == "" %}<g:size>{{ Size | remove: 'Mens ' | remove: 'Ladies ' | remove: 'Child ' | remove: 'Infant ' | replace: '&', '&amp;' }}</g:size><g:size_system>US</g:size_system>{% endunless %}
<g:gender>{{ Gender }}</g:gender>
</item>

{% endfor %}
{% endfor %}
</channel>
</rss>
{% endpaginate %}

or Download from Github:  Shopify Facebook Product Feed Template

Step 3: Assign products to your Facebook Feed Collection.

You should now have a your Facebook Feed Template created. This is just the template that defines how your collection will be displayed on your site. You still need to assign products to this template so we can submit the feed to Facebook.

This involves creating a new product collection, and choosing the fb-product-feed as the template to use:

  • Go to Products > Collections
  • Click the Add Collection button
  • Enter a name for your new collection. I recommend Facebook Product Feed.
  • Add products you want published as part of this collection feed. (either manually or via dynamic rules)
  • IMPORTANT: Select your custom collection template: collection.fb-product-feed.liquid at the bottom of the right hand column.
  • Click Save.

Preview the collection to make sure it works. You should just see a bunch of unformatted text on the screen. If you do a “view source” in your browser, you should now see the formatted XML.

Make sure you copy the url of this collection, as you will need to submit this url to Facebook Business Manager.

Step 4: Add your Product Feed to Facebook Business Manager

Make sure you have your Facebook Collection url open from step 3 above.

  • Log into Facebook Business Manager
  • Go to Assets > Product Catalogs > Product Feeds and click the +Add Product Feed button to create a new feed.
  • Enter a descriptive name for your feed. eg: Shopify Facebook Feed and your store’s currency.
  • Choose Schedule Recurring Uploads
  • Enter your feed collection url in the Feed URL field, and leave the username & password fields blank. Choose a time for your daily upload to occur (early morning is usually a good time)
  • Click Create Feed and wait for the feed to be fetched and processed.
  • Fix errors: If there are errors, go back and fix any errors (either in your product data because of missing meta fields, or you may need to edit the template for custom functionality), re-fetch, and keep doing so until the file is error free.

NOTE: If you have more than 1000 variants, you will need to submit multiple feeds with a ?page=x querystring appended like so:

Step 5: Exclude your Facebook Feed Collection from Showing up on your Store Pages

If your store is setup to programatically display all your collections, then you will want to make sure your Facebook feed doesn’t show up. The exact way to do this will change depending on your theme, but generally you will want to have an “unless” statement within the loop that displays your collections:


{% unless collection.title contains "facebook" %}

... your collection code ...

{% endunless %}

Done!

You are now ready to setup Dynamic Product Remarketing on Facebook. (But that will be for another post)

Related Posts