Richie JS version 1.1.4 🚀
Product & Varients

Product & Variants (Product, ProductGroup, Review, Offer)

What is product rich result?

Adding Product markup to your webpage makes it eligible for a product snippet display. Product snippets are enhanced text results that showcase additional product details like ratings, reviews, price, and availability.

ProductGroup

Products like apparel, shoes, furniture, electronics, and luggage often come in various sizes, colors, materials, or patterns. To help Google recognize these variants as part of the same parent product, use the ProductGroup class with properties like variesBy, hasVariant, and productGroupID alongside Product structured data.

ProductGroup also allows you to specify common properties for all variants, such as brand and reviews, reducing duplicated information.

Kindly Refer Google Doc (opens in a new tab) to know more about product rich result.

What are necessary data for product rich result?

1. Product name

product.html
<div class="product">
 
  <h1 class="rjs-prod-1-name"> Denim Jacket </h1>
 
<div>

2. Images

product.html
<div class="product">
 
  <img class="rjs-prod-1-img" src="https://example.com/image1.jpg" alt="Product Image 1">
  <img class="rjs-prod-1-img" src="https://example.com/image2.jpg" alt="Product Image 2">
 
<div>

3. Description

product.html
<div class="product">
 
  <p class="rjs-prod-1-desc">
    Product Description Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  </p>
 
<div>

4. SKU ID / MPN Code

product.html
<div class="product">
 
  <p>
    SKU ID:
    <span class="rjs-prod-1-sku">123456789</span>
  </p>
 
  <p>
    MPN Code:
    <span class="rjs-prod-1-mpn">ABC123</span>
  </p>
 
<div>

5. Brand name

product.html
<div class="product">
  
  <p>
    Brand:
    <span class="rjs-prod-1-brand">XYZ Brand</span>
  </p>
 
<div>

6. Reviews

product.html
<div class="product">
 
  <section class="rjs-prod-1-reviews">
    
    <div class="urate">
      <!-- rating value -->
      <p class="rv">4.5</p>
      <!-- max rate -->
      <p class="mr">5</p>
      <p class="raterP">John</p>
    </div>
 
    <div class="urate">
      <!-- rating value -->
      <p class="rv">4.5</p>
      <!-- max rate -->
      <p class="mr">5</p>
      <p class="raterO">Foogle</p>
    </div>
 
  </section>
 
<div>

7. Aggregated rating

product.html
<div class="product">
  
  <div class="rjs-prod-1-aggrate">
    <!-- aggregated rate-->
    <p class="arv">100</p>
    <!-- max possibly rate -->
    <p class="mr">100</p>
    <!-- total user rate count -->
    <p class="rc">1000</p>
  </div>
 
<div>

8. Offer

Offer is a object that consists of shipping details, return policy, price, purchase link, availability and condition.

Shipping details

  • Shipping cost - rjs-prod-*(uid)-delcost
  • Shipping destination - data-delover (data attribute)
  • Processing time - rjs-prod-*(uid)-ptime
  • Delivery time - rjs-prod-*(uid)-ttime
đź’ˇ
data-range is mandatory for processing & delivery time (see line no 8 & 12)
product.html
<div class="product">
 
  <p>
    Shipping Cost:
    <span class="rjs-prod-1-delcost" data-delover="india">80</span>
  </p>
 
  <p class="rjs-prod-1-ptime" data-range="1-3">
    Processing Time: 1-3 business days
  </p>
 
  <p class="rjs-prod-1-ttime" data-range="3-5">
    Estimated Delivery Time: 3-5 business days
  </p>
 
<div>

Merchant return details

  • Return within
  • Return fee
product.html
<div class="product">
 
  <p>
    Return Policy:
    <span class="rjs-prod-1-returnin">30 days</span>
  </p>
 
  <p>
    Return Fees:
    <span class="rjs-prod-1-returnfee">Free</span>
  </p>
 
<div>

Validity

This is defined as reservedNames.product.productPriceValidUntilNext in rjs.config.json

rjs.config.json
  {
    "reservedNames": {
      "product": {
      "productPriceValidUntilNext": 30 //30days from generation date.
      }
    }
  }

Purchase link

The purchase link is automatically generated based on the hierarchical structure of the input file. For files containing multiple variants on a single page, the link includes specific variant parameters in the URL, such as https://www.ashop.com/productPage?var=black_20_male.

Parameter name is defined as reservedNames.product.varientParameterName in rjs.config.json. Configure this according to your web server's logic of parameters handling.

rjs.config.json
  {
    "reservedNames": {
      "product": {
      "varientParameterName": "var"
      }
    }
  }

Price & Currency

đź’ˇ
Alpha-3 code is for currency
product.html
<div class="product">
  
  <p>
    Price:
    <span class="rjs-prod-1-cost" data-currency="inr">990</span>
  </p>
 
<div>

Availability

Availability is boolean (true or false)

product.html
<div class="product">
  
  <p>
    Availability:
    <span class="rjs-prod-1-avail" data-avail="true">In Stock</span>
  </p>
 
<div>

Condition

Two possible values are,

  • new
  • used
product.html
<div class="product">
  
  <p>
    Item Condition:
    <span class="rjs-prod-1-cond" data-cond="new">New</span>
  </p>
 
<div>

9. Varies By classes

There are six type of variant class,

  • Color - color
  • Gender - audage
  • Age - audage
  • Material - material
  • Pattern - pattern
  • Size - size
Two or more classes can be added by using separator between them.
Example: color-audage-gender- Element's innerText value order should match them and follow after name of the product. (see line number 4)
đź’ˇ
data-var should be added in product name element (rjs-prod-*-name) element.
product.html
<div class="product">
 
  <h1 class="rjs-prod-1-name" data-var="color-audage-gender">
    Denim Jacket(Product Name) | Black | Age 20 | Male
  </h1>
  
<div>

Function and parameters

đź’ˇ
By default input file is overwriiten with result so destination is optional
This is only for API method. We prefer CLI method for keeping it simpler (refer - Working with API & CLI).
func_params.js
const richResultType = 'product';
const filePath = 'product.html';
const destination = 'dist/product.html'; /* optional */
 
richie(richResultType, filePath, destination);

Example of a Instance

article.html
<body>
 
	<div class="product">
 
		<!-- name -->
		<h1 class="rjs-prod-1-name" data-var="color-audage-gender">Denim Jacket | Black | Age 20 | Male</h1>
 
		<!-- images -->
		<img class="rjs-prod-1-img" src="https://example.com/image1.jpg" alt="Product Image 1">
		<img class="rjs-prod-1-img" src="https://example.com/image2.jpg" alt="Product Image 2">
 
		<!-- description -->
		<p class="rjs-prod-1-desc">Product Description Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
 
		<!-- skuid -->
		<p>
			SKU ID:
			<span class="rjs-prod-1-sku">123456789</span>
		</p>
 
		<!--mpn code  -->
		<p>
			MPN Code:
			<span class="rjs-prod-1-mpn">ABC123</span>
		</p>
 
		<!-- brand name -->
		<p>
			Brand:
			<span class="rjs-prod-1-brand">XYZ Brand</span>
		</p>
 
 
		<p>
			Price:
			<span class="rjs-prod-1-cost" data-currency="inr">990</span>
		</p>
 
		<p>
			Availability:
			<span class="rjs-prod-1-avail" data-avail="true">In Stock</span>
		</p>
 
 
		<p>
			Item Condition:
			<span class="rjs-prod-1-cond" data-cond="new">New</span>
		</p>
 
 
		<p>
			Return Policy:
			<span class="rjs-prod-1-returnin">30 days</span>
		</p>
 
		<p>
			Return Fees:
			<span class="rjs-prod-1-returnfee">Free</span>
		</p>
 
		<!-- delivery across and return policy applicable country -->
		<p>
			Shipping Cost:
			<span class="rjs-prod-1-delcost" data-delover="india">80</span>
		</p>
 
		<p class="rjs-prod-1-ptime" data-range=" 1-3">Processing Time: 1-3 business days</p>
 
		<p class="rjs-prod-1-ttime" data-range="3-5">Estimated Delivery Time: 3-5 business days</p>
 
		<!-- review -->
		<section class="rjs-prod-1-reviews">
			
			<div class="urate">
				<!-- rating value -->
				<p class="rv">4.5</p>
				<!-- max rate -->
				<p class="mr">5</p>
				<p class="raterP">John</p>
			</div>
 
			<div class="urate">
				<!-- rating value -->
				<p class="rv">4.5</p>
 
				<!-- max rate -->
				<p class="mr">5</p>
 
				<p class="raterO">Foogle</p>
			</div>
 
		</section>
 
		<!-- aggregate review -->
		<div class="rjs-prod-1-aggrate">
			<!-- aggregate rate that got -->
			<p class="arv">100</p>
 
			<!-- max possibly rate -->
			<p class="mr">100</p>
 
			<!-- total user rate count -->
			<p class="rc">1000</p>
		</div>
 
	</div>
 
</body>

Output of a Instance

article.html
<script type="application/ld+json">
  [
    {
      "@context": "https://schema.org/",
      "@type": "ProductGroup",
      "name": "Denim Jacket",
      "description": "Product Description Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
      "url": "https://www.cresteem.com/pages/productVarient/productCombined",
      "brand": { "@type": "Brand", "name": "XYZ Brand" },
      "productGroupID": "e965dfe6ea09a9fa90f45a5bad9c2730",
      "variesBy": ["color", "suggestedAge", "suggestedGender"],
      "hasVariant": [
        {
        "@context": "https://schema.org/",
        "@type": "Product",
        "name": "Denim Jacket",
        "image": [
        "https://example.com/image1.jpg",
        "https://example.com/image2.jpg"
        ],
        "description": "Product Description Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "sku": "123456789",
        "mpn": "ABC123",
        "offers": {
        "@type": "Offer",
        "category": "Fees",
        "price": 990,
        "priceCurrency": "INR",
        "url": "https://www.cresteem.com/pages/productVarient/productCombined?var=black_20_male",
        "priceValidUntil": "2024-05-05T18:13:20.000Z",
        "availability": "InStock",
        "itemCondition": "NewCondition",
        "hasMerchantReturnPolicy": { "@id": "#return_policy" },
        "shippingDetails": { "@id": "#shipping_policy" }
        },
        "audience": {
        "@type": "PeopleAudience",
        "suggestedGender": "MALE",
        "suggestedAge": { "@type": "QuantitativeValue", "minValue": 20 }
        },
        "color": "Black"
        },
        {
        "@context": "https://schema.org/",
        "@type": "Product",
        "name": "Denim Jacket",
        "image": [
        "https://example.com/image1.jpg",
        "https://example.com/image2.jpg"
        ],
        "description": "Product Description Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "sku": "123456789",
        "mpn": "ABC123",
        "offers": {
        "@type": "Offer",
        "category": "Fees",
        "price": 990,
        "priceCurrency": "INR",
        "url": "https://www.cresteem.com/pages/productVarient/productCombined?var=brown_10_female",
        "priceValidUntil": "2024-05-05T18:13:20.000Z",
        "availability": "InStock",
        "itemCondition": "NewCondition",
        "hasMerchantReturnPolicy": { "@id": "#return_policy" },
        "shippingDetails": { "@id": "#shipping_policy" }
        },
        "audience": {
        "@type": "PeopleAudience",
        "suggestedGender": "FEMALE",
        "suggestedAge": { "@type": "QuantitativeValue", "minValue": 10 }
        },
        "color": "Brown"
        }
      ],
      "aggregateRating": {
      "@type": "AggregateRating",
      "ratingValue": 100,
      "bestRating": 100,
      "ratingCount": 2000
      },
      "review": [
        {
        "@type": "Review",
        "reviewRating": {
        "@type": "Rating",
        "ratingValue": 4.5,
        "bestRating": 5
        },
        "author": { "@type": "Person", "name": "John" }
        },
        {
        "@type": "Review",
        "reviewRating": {
        "@type": "Rating",
        "ratingValue": 4.5,
        "bestRating": 5
        },
        "author": { "@type": "Organization", "name": "Foogle" }
        },
        {
        "@type": "Review",
        "reviewRating": {
        "@type": "Rating",
        "ratingValue": 4.5,
        "bestRating": 5
        },
        "author": { "@type": "Person", "name": "John" }
        },
        {
        "@type": "Review",
        "reviewRating": {
        "@type": "Rating",
        "ratingValue": 4.5,
        "bestRating": 5
        },
        "author": { "@type": "Organization", "name": "Foogle" }
        }
      ]
      },
      {
        "@context": "https://schema.org/",
        "@id": "#shipping_policy",
        "@type": "OfferShippingDetails",
        "shippingRate": {
        "@type": "MonetaryAmount",
        "value": 80,
        "currency": "INR"
        },
        "shippingDestination": {
        "@type": "DefinedRegion",
        "addressCountry": "IN"
        },
        "deliveryTime": {
        "@type": "ShippingDeliveryTime",
        "handlingTime": {
        "@type": "QuantitativeValue",
        "minValue": 1,
        "maxValue": 3,
        "unitCode": "DAY"
        },
        "transitTime": {
        "@type": "QuantitativeValue",
        "minValue": 3,
        "maxValue": 5,
        "unitCode": "DAY"
        }
      }
    },
    {
      "@context": "https://schema.org/",
      "@id": "#return_policy",
      "@type": "MerchantReturnPolicy",
      "applicableCountry": "IN",
      "returnPolicyCategory": "MerchantReturnFiniteReturnWindow",
      "merchantReturnDays": 30,
      "returnMethod": "ReturnByMail",
      "returnFees": "FreeReturn"
    }
  ]
</script>


Let's see what's next!