Adding Automatic Shopify Structured Data for Products

shopify-structured-data-JSON

Adding structured data in the schema.org format for products is a best practice for search engine optimization in your Shopify store.  And JSON-LD is now considered the recommended and preferred method for adding the structured data.

Google provides a handy Structured Data Testing Tool to see how your microdata looks.

And more good news is that many Shopify themes already have the automatic structured data built in. But some notable examples do not. Look at what happens when you test the Tesla Gear Store.

no shopify structured data example

Pixel Union makes some beautiful Shopify themes and maybe @elonmusk’s gear store could have structured data if they updated their theme with the code from this post. Maybe the latest version of @pixelunion’s Jitensha theme includes microdata. Editor’s note: see Pixel Union’s response at end of article. But every Shopify owner who cares about search engine rankings should check their pages for structured data.

The Schema.org page for a single, identifiable product instance shows you the code examples:

Without Markup:
<div>ACME Racing Bike in black (2008). ACME Racing Bike, bought 8/2008, almost new, with a signature of Eddy Merckx on the frame.</div>



Micodata Example:
We use the IndividualProduct type when we are concerned with the specific item, rather than a set of indistinguishably similar items.
<div itemscope itemtype="https://schema.org/IndividualProduct" itemid="#product">
 <link itemprop="additionalType" href="https://www.productontology.org/id/Racing_bicycle" />
 <span itemprop="name">ACME Racing Bike in black (2008)</span>
 <span itemprop="description">ACME Racing Bike, bought 8/2008, almost new, with a signature of Eddy Merckx on the frame</span>
</div>

RDFa Example:
We use the IndividualProduct type when we are concerned with the specific item, rather than a set of indistinguishably similar items.<div  typeof="IndividualProduct" resource="#product">
 <link property="additionalType" href="https://www.productontology.org/id/Racing_bicycle" />
 <span property="name">ACME Racing Bike in black (2008)</span>
 <span property="description">ACME Racing Bike, bought 8/2008, almost new, with a signature of Eddy Merckx on the frame.</span>
</div>

And finally…
The JSON-LD Example

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@id": "#product",
  "@type": "IndividualProduct",
  "additionalType": "https://www.productontology.org/id/Racing_bicycle",
  "description": "ACME Racing Bike, bought 8/2008, almost new, with a signature of Eddy Merckx on the frame.",
  "name": "ACME Racing Bike in black (2008)"
}
</script>

Thank you Schema.org for the perfect example of structured product microdata but adding this to our product.liquid file in Shopify isn’t what we need. We want the microdata automatically relevant for each product.

Getting the Shopify Structured Data into Your Product Pages Automatically

One method is well documented for adding rich snippets in a Quora Post on How do I implement schema.org in shopify? The post will tell you how to get the microdata onto your Shopify products with the data pulling automatically from Shopify variables. This is great but it’s not the method that Google recommended.

JSON-LD preferred metho

So we’re part of the way there but Google’s recommendations have to be taken seriously. A scouring of the Shopify forums turned up this code from Mircea Piturca:

{% assign collection_urls = '' %}
  {% for collection in product.collections %}
  	 {% assign collection_urls = collection_urls | append: '"' | append: shop.url | append: '/collections/' | append: collection.handle | append: '"' %}
  	 {% if forloop.last != true %}
       {% assign collection_urls = collection_urls | append:',' %}
  	 {% endif %}
  {% endfor %}

  {% assign current_variant = product.selected_or_first_available_variant %}


<script type="application/ld+json"
{
  "@context": "https://schema.org/",
  "@type": "Product",
  "url": "{{ shop.url | append: '/products/' | append: product.handle }}",
  "name": "{{ product.title }}",
  "image": "{{ product.featured_image.src | img_url: 'master' }}",
  "description": "{{ product.description | strip_html | escape }}",
  {% if collection_urls != blank %}
  "category": [
    {{ collection_urls }}
  ],
  {% endif %}
  "brand": {
    "name": "{{ product.vendor }}"
  },
  "offers": {
    "@type": "Offer",
    "priceCurrency": "{{ shop.currency }}",
    "price": "{{ current_variant.price | money }}",
    "availability": "https://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}",
    "seller": {
      "@type": "Organization",
      "name": "{{ shop.name }}"
    }
  }
}
>  </script>

However, adding this code to the theme gives an error in the Structured Testing tool.

 "priceCurrency": "{{ shop.currency }}"

returns something like $100.00 or $1,000.00 if the price is over $999. The testing tool wants to see the data as a straight numeral with no dollar sign or comma for larger figures.

Also the

 "description": "{{ product.description | strip_html | escape }}",

is giving the full product description. You’re already including well crafted SEO description text on all your products so why not show that in the structured microdata?

The tweak for the price is use

"price": "{{ current_variant.price | money_without_currency | remove: ',' }}",

No comma and no dollar sign returned.

To pull back the search engine optimized description from the Shopify product we use

"description": "{{ page_description }}",

So the full liquid code looks like this:

{% assign collection_urls = '' %}
  {% for collection in product.collections %}
  	 {% assign collection_urls = collection_urls | append: '"' | append: shop.url | append: '/collections/' | append: collection.handle | append: '"' %}
  	 {% if forloop.last != true %}
       {% assign collection_urls = collection_urls | append:',' %}
  	 {% endif %}
  {% endfor %}

  {% assign current_variant = product.selected_or_first_available_variant %}


<script type="application/ld+json">
{
  "@context": "https://schema.org/",
  "@type": "Product",
  "url": "{{ shop.url | append: '/products/' | append: product.handle }}",
  "name": "{{ product.title }}",
  "image": "{{ product.featured_image.src | img_url: 'master' }}",
  "description": "{{ page_description }}", 
  {% if collection_urls != blank %}
  "category": [
    {{ collection_urls }}
  ],
  {% endif %}
  "brand": {
    "name": "{{ product.vendor }}"
  },
  "offers": {
    "@type": "Offer",
    "priceCurrency": "{{ shop.currency }}",
    "price": "{{ current_variant.price | money_without_currency | remove: ',' }}",
    "availability": "https://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}",
    "seller": {
      "@type": "Organization",
      "name": "{{ shop.name }}"
    }
  }
}
>  </script>

Remember to test your product page data using the Structured Data Testing Tool. And why not have a look at the data your top ranked competitors are using as well.

Editor’s note: This was Pixel Union’s response on the structured data for their Jitensha theme

The full conversation is available on Twitter.

3 Comments

  1. Eduardo Priuli on May 27, 2017 at 1:02 am

    Hey Misterdif_

    So great your post, sometimes we need an external help to set up our Shopify store with the current SEO tendency, the shopify updates and support seems to stuck in the past sometimes.
    I was checking the coding on the GSDTT, and it returns and error:

    In the first line, following the arrows, and same error in the line “collections_urls” as follow:

    {% assign collection_urls = ” %} >>>>> JSON-LD Missing ‘}’ or object member name.
    {% for collection in product.collections %}
    {% assign collection_urls = collection_urls | append: ‘”‘ | append: shop.url | append: ‘/collections/’ | append: collection.handle | append: ‘”‘ %}
    {% if forloop.last != true %}
    {% assign collection_urls = collection_urls | append:’,’ %}
    {% endif %}
    {% endfor %}
    {% assign current_variant = product.selected_or_first_available_variant %}

    {
    “@context”: “https://schema.org/”,
    “@type”: “Product”,
    “url”: “{{ shop.url | append: ‘/products/’ | append: product.handle }}”,
    “name”: “{{ product.title }}”,
    “image”: “{{ product.featured_image.src | img_url: ‘master’ }}”,
    “description”: “{{ page_description }}”,
    {% if collection_urls != blank %} >>>>>>> JSON-LD Missing ‘}’ or object member name.
    “category”: [
    {{ collection_urls }}
    ],
    {% endif %}
    “brand”: {
    “name”: “{{ product.vendor }}”
    },
    “offers”: {
    “@type”: “Offer”,
    “priceCurrency”: “{{ shop.currency }}”,
    “price”: “{{ current_variant.price | money_without_currency | remove: ‘,’ }}”,
    “availability”: “https://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}”,
    “seller”: {
    “@type”: “Organization”,
    “name”: “{{ shop.name }}”
    }
    }
    }
    >

    Do you have any clue, how to fix it?
    Thanks once again for the post and the help!

    Cheers,

    Eduardo
    smookio.it

  2. Mr. Dif on June 9, 2017 at 8:43 am

    Hi Eduardo – in your code above I don’t see the “script” tags so that would make a difference. I think it’s also important to note that some of the new Shopify free themes actually already have structured data built in. The Venture theme is one example of this.

  3. Mr. Dif on February 6, 2019 at 1:55 pm

    Note that you need add https before {{ product.featured_image.src | img_url: ‘master’ }} to make the images from the Shopify cdn valid. The structured data testing tool proves this out. Also it’s asking for more information. I’ll need to revisit this.

Leave a Comment