Monthly Archives: July 2015

Schema.org: Product Variants with Different Prices

In my last post, I argued that Google is increasingly able to handle multiple product / offer entities in product pages and still generate Rich Snippets for products. Some people have pointed out that the markup in the live pages I cited was misleading, because it “abused” the http://schema.org/offers property and wrongly puts the multiple offers / products into a http://schema.org/SearchResultsPage entity as a container. While I stick to my original prediction that Google will increasingly select or summarize multiple entities from a page to generate Rich Snippets customized to a single query, I want to provide a clean approach for this frequent scenario.

Below, I will explain how you can properly model a product detail page with multiple product variants that have different prices in a way that almost certainly triggers Google Rich Snippets for products.

The main challenge is to get a price range shown in a Rich Snippet for a page with multiple product variants, like so:

Google Rich Snippet for multiple cars

Before we start, it is important to understand that, to my knowledge, Google has previously shown price ranges in Rich Snippets for Products only in one of the following three cases:

  1. For http://schema.org/AggregateOffer, like so:
    {
      "@context": "http://schema.org",
      "@type": "Product",
      "image": "dell-30in-lcd.jpg",
      "name": "Dell UltraSharp 30\" LCD Monitor",
      "offers": {
        "@type": "AggregateOffer",
        "highPrice": "$1495",
        "lowPrice": "$1250",
        "offerCount": "8",
        "offers": [
          {
            "@type": "Offer",
            "url": "save-a-lot-monitors.com/dell-30.html"
          },
          {
            "@type": "Offer",
            "url": "jondoe-gadgets.com/dell-30.html"
          }
        ]
      }
    }
    
  2. For GoodRelations price specifications in RDFa syntax using gr:hasMinCurrencyValue / gr:hasMaxCurrencyValue, like so:
    <div typeof="gr:Offering" about="#offer">
      <div property="gr:name">GoodRelations T-Shirt - Various Designs</div>
      <div rel="gr:hasBusinessFunction" 
         resource="http://purl.org/goodrelations/v1#Sell"></div>
      <div rel="gr:hasPriceSpecification">
        <div typeof="gr:UnitPriceSpecification">Price: 
        <div property="gr:hasCurrency" content="USD">$</div>
        <span property="gr:hasMinCurrencyValue">10.00</span> to $
        <span property="gr:hasMaxCurrencyValue">99.99</span>
        <div property="gr:validThrough" datatype="xsd:dateTime" content="2012-11-30T23:59:59Z"></div> 
      </div>
    </div>
    
  3. For multiple http://schema.org/Offer entities linked to the same product via http://schema.org/offers, like so:
    {
      "@context": "http://schema.org",
      "@type": "Product",
      "image": "dell-30in-lcd.jpg",
      "name": "Dell UltraSharp 30\" LCD Monitor",
      "offers": [
    	{
    		"@type" : "Offer",
    		"price" : "35",
    		"priceCurrency" : "EUR"
    	},
    	{
    		"@type" : "Offer",
    		"price" : "55",
    		"priceCurrency" : "EUR"
    	}
    	]
    }
    

So far, there was no documented markup pattern for Web pages with multiple product variants that have differing prices. Still, there is a straightforward way to achieve this by combining

Before we start, remember that there are two alternative approaches for modeling product and offer information in schema.org:

  1. You can start with the http://schema.org/Product entity and link it to one or more http://schema.org/Offer entities via http://schema.org/offers.
  2. Or you can start with a http://schema.org/Offer entity and link to the http://schema.org/Product included via http://schema.org/itemOffered.

The essential trick is to use both in combination, which is perfectly valid from the underlying GoodRelations model in schema.org:

  1. First, model an abstract version of the product, e.g. omitting size, color, or configuration information, as a http://schema.org/Product.
  2. Then, link this to two or more http://schema.org/Offer entities via http://schema.org/offers.
  3. Finally, link each of these offers to a more detailed product entity via http://schema.org/itemOffered.
    1. Here is a complete example:

      {
      	"@context" : "http://schema.org",
      	"@type" : "Product",
          "description" : "The Hepp Smart Watch is a unique wristwatch.",
          "name" : "Hepp Smart Watch",
      	"offers" : [
      		{
      			"@type" : "Offer",
      			"availability" : "http://schema.org/InStock",
      			"price" : "50",
      			"priceCurrency" : "EUR",
      			"itemCondition": "http://schema.org/NewCondition",
      			"itemOffered" : 
      			{
      				"@type" : "Product",
      		        "description" : "The Hepp Smart Watch in Silver is robust and has enough memory for most tasks.",
      		        "name" : "Hepp Smart Watch in Silver with 16 GB RAM"
      			}
      		},
      		{
      			"@type" : "Offer",
      			"availability" : "http://schema.org/InStock",
      			"price" : "400",
      			"priceCurrency" : "EUR",
      			"itemCondition": "http://schema.org/NewCondition",
      			"itemOffered" : 
      			{
      				"@type" : "Product",
      		        "description" : "The best Hepp Smart Watch ever: Gold-plated and with 64 GB.",
      		        "name" : "Hepp Smart Watch in Gold with 64 GB RAM"
      			}
      		}
      	]
      }
      

      I have not seen this in the wild yet, but I am very confident that it is the best approach for pages with multiple product variants.

Google Product Rich Snippets for Multiple Products on a Page

It has been a strong principle of Google to show Rich Snippets for Products only if there is exactly one single product on the page. For quite a while, we have predicted that Rich Snippets will become a much more dynamic feature in Google, e.g. that it will be turned on an off depending on a particular query and depending on how it helps highlight important information in the SERPs. Now, for a few weeks, there has been a conflicting requirement for developers in the Google Developer documentation: At https://developers.google.com/structured-data/rich-snippets/products, Google says

Product markup should be used for a specific product, not a category of products or a list of products.

while at https://developers.google.com/structured-data/policies, they state that all products in a multi-product page are to be marked up (or none):

Each entity should be marked up using the relevant schema.org type, such as schema.org/Product for product category pages. Marking up just one category entity from all listed on the page is against our guidelines.

It essentially meant that you could mark-up only deep detail pages that describe exactly one single product. Today, we found first evidence that Google is now properly summarizing multiple product descriptions to generate a summary. If you search for “New Volkswagen Golf Yorkville New York”, you might get the following search result:

Google Rich Snippet for multiple cars

If you look at the first result, you see a price range ($21,515.00 to $30,830.00):

Google Rich Snippet for multiple cars

Now, contrary to what one would expect, there is no http://schema.org/AggregateOffer in the markup, but simply seven http://schema.org/Offer entities. $21,515 is the lowest value of all price properties, and $30,830 the highest one.

While we have not yet seen it in the wild, we expect that Google will also try to create Rich Snippets for single products from multi-item pages depending on the user query. So instead of summarizing a multi-product page into one aggregate Rich Snippet, they might chose a single entity that they think fits your information needs best.

In short: We see that we can now safely mark-up multiple products in a page and expect Rich Snippets for price information. Google is able to summarize them. That is good news, in particular for automotive Web sites.

PS: If you are the person responsible for adding the schema.org markup to http://www.steetpontevolkswagen.net/, I would first like to congratulate to the pretty advanced and effective use of schema.org. Second, I would recommend that you add the new features for http://schema.org/Car for standardized car features and to use http://schema.org/additionalProperty for the other car features.. Need help? Contact us!

PPS: If you look deeper into the markup, you will see that the actual data structure is even a bit weird, because the main entity is a http://schema.org/SearchResultsPage type, linked to the seven offers via http://schema.org/offers. This is wrong, because the offers property for a http://schema.org/SearchResultsPage type is inherited from http://schema.org/CreativeWork and links to offers of the creative work. But the site owner is likely not offering the search results page for $ 20,000 ;-).