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 Dynamic Product Ads: Build your own Retargeting feed

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

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

  • UPDATE September 14, 2017: Removed redundant top level products that would cause duplicate products in cases where only a single variant was present.
  • UPDATE September 13, 2017: Fixed issue where some variant images were showing up blank.

Step 1
Install Shopify’s Google Shopping App

Install Shopify’s free Google Shopping app to configure various properties on your products such as Age Group, Gender, and Product Category.

Step 2
Create a Collection Template for your Feed

Create a new custom collection template that will output your collection as XML instead of HTML.

In your Shopify admin, go to:

  • Online Store > Themes > Action > Edit Code
  • 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. (The most recent version of the code is always 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 %}

  {% if product.variants.size > 0 %}
  {% 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;' }}  {{ Color | 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>{{ 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:{% if variant.image.src %}{{ variant.image.src | product_img_url: 'grande' }}{% else %}{{ product.featured_image.src | product_img_url: 'grande' }}{% endif %}</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 | strip_html | strip_newlines | replace: '&', '&amp;' }}</g:color>{% endunless %}
{% unless Size == "" %}<g:size>{{ Size | strip_html | strip_newlines | replace: '&', '&amp;' }}</g:size><g:size_system>US</g:size_system>{% endunless %}
<g:gender>{{ Gender }}</g:gender>
</item>

  {% endfor %}
  {% else %}
<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>{{ 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>
  {% endif %}
{% endfor %}
</channel>
</rss>
{% endpaginate %}

or Download from Github:  Shopify Facebook Product Feed Template

Step 3
Assign products to your Feed Collection.

You now need to assign products to your new facebook feed template:

  • Go to Products > Collections
  • Click Create Collection
  • Enter a Title for your feed collection. I recommend Facebook Product Feed.
  • Add the products you want to be included in your Facebook feed, either manually or using conditions.
  • IMPORTANT! Assign your feed TEMPLATE to this collection. In the right column, at the bottom, under Theme Templates, choose : collection.fb-product-feed (the name may change depending on what you actually called your template file).
  • Click Save Colleciton.
  • Preview the collection to make sure it works. You should see unformatted text on the screen. Do a “view source” in your browser to see the formatted XML.
  • Copy the url of this collection as you need it in the next step.

Step 4
Upload your Product Feed to Facebook

  • Log into Facebook Business Manager
  • Go to Assets > Product Catalogs > Product Feeds and click +Add Product Feed to create a new feed.
  • Enter a descriptive name for your feed. (eg: Shopify Facebook Feed); your store’s currency; select recurring or single upload; and click next.
  • Enter your feed collection url you copied in step 3 above. Leave the username & password 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, fix them, re-fetch, and keep doing so until the feed 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 on your Public Store Pages

Depending on how your store is setup, you may need to add some code to prevent your Facebook feed collection from showing up on your store. The exact way to do this may depend 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 your Dynamic Product Remarketing campaigns!

Related Posts