Creating schema markup for a single product is straightforward and well documented. But things get more complicated when you’re creating markup for many variations of a product. There are several ways to create schema markup for complex products. This article will describe three common strategies for modeling product variations so you can optimize your markup for search engines.
These strategies are: 1. Simplified and Aggregate Product Offers 2. Each Variant as an Individual Offer and 3. Each Variant as a Product Model.
What is a Product Variant?
Generally, variants are identified as having their own Store Keeping Units (SKUs) which are unique to the Product group and used for eCommerce and Supply Chain information systems. Below is what WooCommerce and Shopify, two popular eCommerce platforms, say about Product Variants.
WooCommerce Variable Products are a product type that lets you offer a set of variations on a particular product such as price, stock, size and more. For example, they may be used on a shirt that’s offered in large, medium and small sizes and in different colours.
Shopify Product Variants are used on products that come with more than one option, such as color or size. Each combination of options is a variant of that product. For example, you might sell a t-shirt with two options, such as size and color. The size option might have three option values: small, medium, or large. The color option might have two option values: blue or green. A variant of these options could be a small, blue t-shirt.
1. Simplified and Aggregate Product Offers
For situations where you don’t have all the data readily available, or want to start off with something basic, you can simplify the product models. With this approach, your Product markup would only use the properties that are shared across all variants such as, name, image, and description. The Product type would then use the offers property to connect to either an Offer, if no variation in pricing was present, or an AggregateOffer if pricing changed among the product variants.
For example, if you’re selling shoes, there may be variations in sizing and colour, but all of them are the same price. You could create markup for a single Product, excluding all sizing and colour information, and connect it to an Offer data item with the price shared across all product models. This is what the markup would look like:
{ "@context": "http://schema.org/", "@type": "Product", "name": "Clarks Falalala Shoes for Men", "image": "https://example.net/shoes/clarks-falalala.jpeg", "description": "A great comfortable walking shoe, carried in sizes 9-11, but you wouldn’t really know that unless you applied fancy NLP to this string", "offers": { "@type": "Offer", "price": 45.99, "priceCurrency": "EUR", "availability": "InStock" } }
If you were selling something that varied in price—for instance, Soap that comes in 250ml, 500ml and 1000ml bottles—then you could call out the lowest price and highest price using AggregateOffer:
{ "@context": "http://schema.org/", "@type": "Product", "name": "Super Suds", "image": "https://example.net/soap/super-suds.jpeg", "offers": { "@type": "AggregateOffer", "lowPrice": 5.99, "highPrice": 17.99, "priceCurrency": "EUR", "availability": "InStock" } }
2. Each Variant as an Individual Offer
This first option doesn’t tell the machine-channel anything about the variation of products you carry, nor does it provide the granularity of stock information by individual SKU. The next level of detail would be to include each variant’s price and availability as a separate Offer. Each Offer should have (as recommended by Google) a sku to differentiate it from other variants, along with its price and availability. Using the same example as before, we might generate:
{ "@context": "http://schema.org/", "@type": "Product", "name": "Clarks Falalala Shoes for Men", "image": "https://example.net/shoes/clarks-falalala.jpeg", "description": "A great comfortable walking shoe, carried in sizes 9-11, but now size 11 isn’t in stock", "offers": [ { "@type": "Offer", "sku": "QWERTYSHOE-9", "price": 45.99, "priceCurrency": "EUR", "availability": "InStock" },{ "@type": "Offer", "sku": "QWERTYSHOE-10", "price": 45.99, "priceCurrency": "EUR", "availability": "InStock" },{ "@type": "Offer", "sku": "QWERTYSHOE-11", "price": 45.99, "priceCurrency": "EUR", "availability": "OutOfStock" } ] }
The Soap Suds example shows varying Offer properties sku, name, price, priceCurrency (in ISO 4217 currency format) and availability;
{ "@context": "http://schema.org/", "@type": "Product", "name": "Super Suds", "image": "https://example.net/soap/super-suds.jpeg", "offers": [{ "@type": "Offer", "sku": "egsoapsuds-250", "name": "Soap Suds 250 ml", "price": 5.99, "priceCurrency": "EUR", "availability": "InStock" },{ "@type": "Offer", "sku": "egsoapsuds-500", "name": "Soap Suds 500 ml", "price": 10.99, "priceCurrency": "EUR", "availability": "OutOfStock" },{ "@type": "Offer", "sku": "egsoapsuds-1000", "name": "Soap Suds 1000 ml", "price": 17.99, "priceCurrency": "EUR", "availability": "InStock" }] }
3. Each Variant as a Product Model
If your products have significant variations among their critical properties, you may want to use the Product Model approach. Essentially, you define a schema.org/Product as the base product, adding properties that are common across all variations. Then, to express properties that are variable, use the ProductModel type. For example, the iPhone 11 is a Product with certain consistent characteristics, but there are different options for GB of memory, colour, and pricing. Each combination of these properties would be a different instance of ProductModel:
{ "@context": "http://schema.org/", "@type": "Product", "name": "iPhone 11", "description": "A great device, loads of memory, 1 million different apps preloaded, outstanding camera, and even makes phone calls!", "image": "https://example.net/phones/apple-iphone11-jpeg", "offers": { "@type": "AggregateOffer", "lowPrice": 599.00, "highPrice": 899.00, "priceCurrency": "USD", "availability": "InStock" }, "additionalProperty": { "@type": "PropertyValue", "name": "Memory", "unitCode": "E34", "unitText": "GB", "value": "64" }, "model": [ { "@type": "ProductModel", "name": "iPhone 11 with 64GB", "color": "White", "offers": { "@type": "Offer", "price": 599.00, "name": "White iPhone 11", "availability": "InStock" } },{ "@type": "ProductModel", "name": "iPhone 11 with 64GB", "color": "Red", "offers": { "@type": "Offer", "price": 649.00, "name": "red usually costs slightly more because it's faster", "availability": "InStock" } },{ "@type": "ProductModel", "name": "iPhone 11 with 128GB", "color": "White", "offers": { "@type": "Offer", "price": 899.00, "name": "White iPhone 11", "availability": "InStock" }, "additionalProperty": { "@type": "PropertyValue", "name": "Memory", "unitCode": "E34", "unitText": "GB", "value": "128" } }] }
Note that ProductModels themselves may contain other ProductModels. This relationship can be defined using the isVariantOf property.
ProductModel Examples in the Wild
If you’d like to see more ProductModel examples in the wild, you can use PublicWWW to search for any schema class: see example.
unitCode Lookup Values
If you’re wondering where the unitCode “E34” comes from, then you’ll want to look up UN/CEFACT Common Codes for specifying the unit of measurement. Here are some common codes for various units of measurement. A spreadsheet is available to download here.
UN/CEFACT Common Code | Unit of Measurement |
28 | kg/m² |
2N | dB |
4H | µm |
4K | mA |
4P | N/m |
A24 | cd/m² |
A86 | GHz |
A94 | g/mol |
B22 | kA |
B32 | kg • m2 |
B43 | kJ/(kg.K) |
B49 | kΩ |
B61 | lm/W |
BAR | bar |
C16 | mm/s |
C24 | mPa.s |
C26 | ms |
C45 | nm |
C62 | 1 |
C65 | Pa.s |
C91 | 1/K |
C94 | min-1 |
CDL | cd |
CEL | °C |
CMQ | cm³ |
CMT | cm |
D33 | T |
D52 | W/K |
D74 | kg/mol |
DAY | d |
DD | ° |
E01 | N/cm² |
E32 | l/h |
FAR | F |
GM | g/m² |
GRM | g |
HTZ | Hz |
HUR | h |
KEL | K |
KGM | kg |
KGS | kg/s |
KHZ | kHz |
KL | kg/m |
KMQ | kg/m³ |
KVT | kV |
KWT | kW |
L2 | l/min |
LTR | l |
LUM | lm |
LUX | lx |
MBR | mbar |
MHZ | MHz |
MIN | min |
MMK | mm² |
MMQ | mm³ |
MMT | mm |
MPA | MPa |
MQH | m3/h |
MQS | m³/s |
MTK | m² |
MTQ | m³ |
MTR | m |
MTS | m/s |
NEW | N |
NU | N • m |
NU | N.m |
OHM | Ω |
P1 | % |
PAL | Pa |
SEC | s |
VLT | V |
WTT | W |
We want your schema markup to be successful! Schema markup can be time-consuming and complicated. That’s why we’re always looking for ways to make things easier for customers through our comprehensive solutions. Book a strategy call with our technical experts today!
Start reaching your online business goals with structured data.
Mark van Berkel is the Chief Technology Officer and Co-founder of Schema App. A veteran in semantic technologies, Mark has a Master of Engineering – Industrial Information Engineering from the University of Toronto, where he helped build a semantic technology application for SAP Research Labs. Today, he dedicates his time to developing products and solutions that allow enterprise teams to leverage Schema Markup to boost their SEO strategy and drive results.