Either "offers", "review", or "aggregateRating" should be specified - Google Error

Damian_Rushwort
New Member
16 0 0

Hi

 

I'm getting the following error showing against all my products in the Google search console.

 

Either "offers", "review", or "aggregateRating" should be specified.

 

Anyone seen this before / know how to resolve? 

 

Damian 

Replies 268 (268)
tim
Shopify Expert
3258 232 1178

If shopping bot does not run javascript (though I can't test right now) , then just omitting metafield content as I've said would solve the problem. 

As reviews app keeps an instance of json in metafield. 

When it runs its javascript code, it rewrites contents of this div with different html, which includes json again,  plus review form and actual reviews. 

That's where it's possible to intercept it, pull the reviews out and add them to our structured data. 

This way I was able to produce product structured data without warnings. 

EmmanuelFlossie
Shopify Partner
2953 221 710

Hello Tim, ah yes very good point. I overlooked that fact. Thanks for sharing your experience! Much appreciated.

 

Just want to highlight a spelling error in the closing div

Instead of

<div id="shopify-product-reviews" data-id="{{product.id}}">/div>

it should be

<div id="shopify-product-reviews" data-id="{{product.id}}"></div>

 

Get in touch with Emmanuel: a Google Shopping Specialist, Google Ads Diamond Product Expert, and also a a Google Product Expert Education 2021 & Tailwind 2023 Award winner.
Need Google Merchant Center or Google Shopping support?.
Hobby-shop
Tourist
8 0 0

not easy question because the review data are not stored in metafields of product but in spr directly. This is the reason why this DON'T WORK

 

<script>
function getData() {
$.ajax({
url : '\/\/productreviews.shopifycdn.com\/assets\/v4\/spr.js?shop=[SHOPNAME].myshopify.com',
type: 'GET',
success : handleData
})
}
loadReviewsScript() {
const baseUrl = this.data.get('url');
const shop = this.data.get('shop');
const productId = this.data.get('productId');
const tag = document.createElement('script');
window.callback = this.handleReviewData.bind(this);

tag.src=`${baseUrl}?callback=callback&shop=${shop}&product_id=${productId}`;
tag.async = true;

document.body.appendChild(tag);
}
handleReviewData(data) {
const reviewData = this.parseReviewData(data);
}
parseReviewData(data) {
return $(data.reviews).map((i, el) => {
const $el = $(el);

return {
'author': $el.find('.spr-review-header-byline').text(),
'body': $el.find('.spr-review-content-body').text(),
'title': $el.find('.spr-review-header-title').text()
};
});
}
review:
{
"@type": "Review",
"author": "{{ review.id }}",
"datePublished": "{{ product.metafields.spr.reviews | split: 'review.date" content="' | last }}",
"description": "{{ product.metafields.spr.reviews | split: 'review.content" content="' | last }}",
"name": "{{ product.metafields.spr.reviews | split: 'review.id" content="' | last }}",
"itemReviewed": "{{ product.metafields.spr.reviews | split: 'review.product.name" content="' | last }}",
"reviewRating": {
"@type": "Rating",
"bestRating": "5",
"ratingValue": "{{ product.metafields.spr.reviews | split: 'reviewCount" content="' | last }}",
"worstRating": "1"
}
}

</script>

 

Note the difference, the only array arrived is reviewCount because this is the only date stored in metafields


@tim wrote:

If shopping bot does not run javascript (though I can't test right now) , then just omitting metafield content as I've said would solve the problem. 

As reviews app keeps an instance of json in metafield. 

When it runs its javascript code, it rewrites contents of this div with different html, which includes json again,  plus review form and actual reviews. 

That's where it's possible to intercept it, pull the reviews out and add them to our structured data. 

This way I was able to produce product structured data without warnings. 


 

tim
Shopify Expert
3258 232 1178

@EmmanuelFlossie, thanks for noticing this -- phone is not the best device for posting.

@Hobby-shop  I'd recommend using  the 'code' button to post you code -- it difficult to read otherwise. 

 

I do not quite get it why do you want to do Ajax'ing yourself -- it's still javascript.  I'd rather wait for Shopify  app to do it's job and call your code via SPRCallbacks, where you can parse DOM and collect review data. 

Now,  you can read the structured data json (prepared in liquid)   JSON.parse it to a javascript variable, add the data on actual reviews and then overwrite that structured data json with updated information.

 

Sorry,  can't share my code ATM as I have no access from my phone. 

 

Hobby-shop
Tourist
8 0 0

@timsomething like this?

<script>
  var SPRCallbacks = {
    onProductLoad: function( e ) {
      $('[itemprop="itemreviewed"]').remove();
      $('[itemprop="itemReviewed"]').remove(); 
      $('[type="application/ld+json"]').filter(':contains("itemReviewed")').remove();
     return {
'author': $el.find('.spr-review-header-byline').text(),
'body': $el.find('.spr-review-content-body').text(),
'title': $el.find('.spr-review-header-title').text()
};
    },
    onReviewsLoad: function( e ) {
      $('[itemprop="itemreviewed"]').remove();
      $('[itemprop="itemReviewed"]').remove(); 
      $('[type="application/ld+json"]').filter(':contains("itemReviewed")').remove();
     return {
'author': $el.find('.spr-review-header-byline').text(),
'body': $el.find('.spr-review-content-body').text(),
'title': $el.find('.spr-review-header-title').text()
};
    }
  }                
</script>
Mujex
Tourist
3 0 0

Hi, Tim can you help me with issue on my shop?  

 

Email me at hello@ecoroots.us 

 

Thanks a lot, 

 

Alin

 

 

ToplineEyewear
Visitor
2 0 0

@tim ,

Looking through the forum trying to find solutions to multiple issues I am looking to address I was wondering if you hire out custom work.  I can do basic HTML but not in depth for what I'm looking for for the site I'm building for myself: 

https://glassesinthemail.com/

Would you please contact me if interested at vbsunglassshack@gmail.com.  I'm new to the forum and Private Messaging privileges have yet to be unlocked

 

  • I'm looking to hide unavailable product variants instead of simply graying them out.
  • I'm wanting to show multiple images per each variant within a product (I know there's apps for this however I would rather have it permanently coded if possible than use an outside app).
Sunglass retailer since 2001.
Akshay_V
Shopify Partner
438 16 58

@ToplineEyewear 

Akshay is here as a Shopify Partner. 

Please let me know how can I help you? Also please check your email I have sent you an email for this.

Akshay Vaghasiya | Email: hello@lavitastic.com | Skype: akshayvaghasiya84
Want to modify theme or custom changes on store hire me.
If helpful then please Like and Accept Solution.
Buy me a coffee PayPal
everythingblack
Visitor
2 0 0

Hi @Akshay_V 

 

Encountering the same problem here since I started syncronising with Google:

I've been through this topic and it's not very clear what I should do to get resolve this...

I know all is in dutch, but I think you can tell by the looks of it what it is?

If not let me know...

Schermafbeelding 2021-01-13 om 22.24.20.pngSchermafbeelding 2021-01-13 om 22.24.33.png

 

Schermafbeelding 2021-01-13 om 22.25.57.png

shamsul96
Tourist
7 0 0

Hello, How can I solve the issues?

shamsul96_0-1613214463554.png

 

EmmanuelFlossie
Shopify Partner
2953 221 710

By installing structured data. You can use my free tutorial here: https://feedarmy.com/kb/shopify-microdata-for-google-shopping/

Get in touch with Emmanuel: a Google Shopping Specialist, Google Ads Diamond Product Expert, and also a a Google Product Expert Education 2021 & Tailwind 2023 Award winner.
Need Google Merchant Center or Google Shopping support?.
shamsul96
Tourist
7 0 0

I saw your code. your schema code for Shopify product review app. but I use Judge.me.

EmmanuelFlossie
Shopify Partner
2953 221 710

For custom coding ie, other review apps, you can contact me on my website, and I am happy to help you.

Get in touch with Emmanuel: a Google Shopping Specialist, Google Ads Diamond Product Expert, and also a a Google Product Expert Education 2021 & Tailwind 2023 Award winner.
Need Google Merchant Center or Google Shopping support?.
Silvary
Tourist
5 0 5

Hi 🙋🏽‍♀️ 

im a new Shopify user only went live last week I have the judge.me app & have 2 errors & 7 warnings on my google console regarding the above error topics.

im not technically minded but can follow instructions I think! 
can I ask why Shopify support these apps if they are not supported automatically!

Can you advise me how I can please resolve this issue, I would be very grateful 

EmmanuelFlossie
Shopify Partner
2953 221 710

If Shopify would be able to resolve everything, then there would be no need for apps. Shopify simply can't do everything themselves, how basic you may thing it is.

Everyone has different needs, if all possibilities would exist, you Shopify account would have 10000's of apps prebuild, and you would see thousands of menus, and would not be able to navigate or use your store.

 

Here is a guide: https://feedarmy.com/kb/shopify-microdata-for-google-shopping/

Get in touch with Emmanuel: a Google Shopping Specialist, Google Ads Diamond Product Expert, and also a a Google Product Expert Education 2021 & Tailwind 2023 Award winner.
Need Google Merchant Center or Google Shopping support?.
Silvary
Tourist
5 0 5

Thank you for your prompt reply & the time you take to help it’s much appreciated, I noticed it says to contact you if on Judge.me which I am. Can you also confirm if I need to remove any existing code? 
kind regards 

EmmanuelFlossie
Shopify Partner
2953 221 710

It's possible, I would not know. As each merchant is different. If you contact me on my website, I am happy to help.

Get in touch with Emmanuel: a Google Shopping Specialist, Google Ads Diamond Product Expert, and also a a Google Product Expert Education 2021 & Tailwind 2023 Award winner.
Need Google Merchant Center or Google Shopping support?.
luxuriaistanbul
Excursionist
33 0 4

Hello,

hope this message finds you safe. We have currently approximately 400 reviews for 20% of the products on the web site www.luxuria.com.tr.

I am using debut theme and using the standard shopify review app. 

Currently I have for 1082 products missing "ratingCount" "reviewCount" and "ratingValue" problem in Google Search Console.

Can anyone please help me with this problem?

Best

Aydin

product-template looks like:

 

<div class="product-template__container page-width"
  id="ProductSection-{{ section.id }}"
  data-section-id="{{ section.id }}"
  data-section-type="product"
  data-enable-history-state="true"
  data-ajax-enabled="{{ settings.enable_ajax }}"
>
  {% comment %}
    Get first variant, or deep linked one
  {% endcomment %}
  {%- assign current_variant = product.selected_or_first_available_variant -%}
  {%- assign product_image_zoom_size = '1024x1024' -%}
  {%- assign product_image_scale = '2' -%}
  {%- assign enable_image_zoom = section.settings.enable_image_zoom -%}
  {%- assign compare_at_price = current_variant.compare_at_price -%}
  {%- assign price = current_variant.price -%}
 
  {% case section.settings.media_size %}
    {% when 'small' %}
      {%- assign product_media_width = 'medium-up--one-third' -%}
      {%- assign product_description_width = 'medium-up--two-thirds' -%}
      {%- assign height = 345 -%}
    {% when 'medium' %}
      {%- assign product_media_width = 'medium-up--one-half' -%}
      {%- assign product_description_width = 'medium-up--one-half' -%}
      {%- assign height = 530 -%}
    {% when 'large' %}
      {%- assign product_media_width = 'medium-up--two-thirds' -%}
      {%- assign product_description_width = 'medium-up--one-third' -%}
      {%- assign height = 720 -%}
    {% when 'full' %}
      {%- assign product_media_width = '' -%}
      {%- assign product_description_width = '' -%}
      {%- assign height = 1090 -%}
      {%- assign enable_image_zoom = false -%}
  {% endcase %}
 
  <div class="grid product-single{% if section.settings.enable_payment_button %} product-single--{{ section.settings.media_size }}-media{% endif %}">
    <div class="grid__item product-single__media-group {{ product_media_width }}{% if section.settings.media_size == 'full' %} product-single__media-group--full{% endif %}" data-product-single-media-group>
      {%- assign featured_media = product.selected_or_first_available_variant.featured_media | default: product.featured_media -%}
 
      {%- for media in product.media -%}
        {% include 'media', media: media, featured_media: featured_media, height: height, enable_image_zoom: enable_image_zoom, image_zoom_size: product_image_zoom_size, image_scale: product_image_scale %}
      {%- endfor -%}
 
      <noscript>
        {% capture product_image_size %}{{ height }}x{% endcapture %}
        <img src="{{ featured_media | img_url: product_image_size, scale: product_image_scale }}" alt="{{ featured_media.alt }}" id="FeaturedMedia-{{ section.id }}" class="product-featured-media" style="max-width: {{ height }}px;">
      </noscript>
 
      {% assign first_3d_model = product.media | where: "media_type", "model" | first %}
 
      {%- if first_3d_model -%}
        <button
          aria-label="{{ 'products.product.view_in_space_label' | t }}"
          class="product-single__view-in-space"
          data-shopify-xr
          data-shopify-model3d-id="{{ first_3d_model.id }}"
          data-shopify-title="{{ product.title | escape }}"
          data-shopify-xr-hidden
        >
          {% include 'icon-3d-badge-full-color' %}<span class='product-single__view-in-space-text'>{{ 'products.product.view_in_space' | t }}</span>
        </button>
      {%- endif -%}
 
 
      {% if product.media.size > 1 %}
        {% if product.media.size > 4 %}
          {%- assign enable_thumbnail_slides = true -%}
        {% endif %}
 
        <div class="thumbnails-wrapper{% if enable_thumbnail_slides == true %} thumbnails-slider--active{% endif %}">
          {% if enable_thumbnail_slides == true %}
            <button type="button" class="btn btn--link medium-up--hide thumbnails-slider__btn thumbnails-slider__prev thumbnails-slider__prev--{{ section.id }}">
              {% include 'icon-chevron-left' %}
              <span class="icon__fallback-text">{{ 'sections.slideshow.previous_slide' | t }}</span>
            </button>
          {% endif %}
          <ul class="product-single__thumbnails product-single__thumbnails-{{ section.id }}">
            {% for media in product.media %}
              <li class="product-single__thumbnails-item product-single__thumbnails-item--{{ section.settings.media_size }} js">
                <a href="{{ media.preview_image | img_url: product_image_zoom_size, scale: product_image_scale }}"
                   class="text-link product-single__thumbnail product-single__thumbnail--{{ section.id }}"
                   data-thumbnail-id="{{ section.id }}-{{ media.id }}"
                   {% if enable_image_zoom %}data-zoom="{{ media.preview_image | img_url: product_image_zoom_size, scale: product_image_scale }}"{% endif %}>
 
                    {%- capture thumbnailAlt -%}
                      {%- if media.media_type == 'video' or media.media_type == 'external_video' -%}
                        {{ 'sections.featured_product.video_thumbnail_alt' | t: imageAlt: media.alt | escape }}
                      {%- elsif media.media_type == 'model' -%}
                        {{ 'sections.featured_product.model_thumbnail_alt' | t: imageAlt: media.alt | escape }}
                      {%- else -%}
                        {{ 'sections.featured_product.gallery_thumbnail_alt' | t: imageAlt: media.alt | escape }}
                      {%- endif -%}
                    {%- endcapture -%}
 
                    <img class="product-single__thumbnail-image" src="{{ media.preview_image | img_url: '110x110', scale: 2 }}" alt="{{ thumbnailAlt }}">
                    {%- if media.media_type == 'video' or media.media_type =='external_video' -%}
                      <div class="product-single__thumbnail-badge">
                        {% include 'icon-video-badge-full-color' %}
                      </div>
                    {%- endif -%}
                    {%- if media.media_type == 'model' -%}
                      <div class="product-single__thumbnail-badge">
                        {% include 'icon-3d-badge-full-color' %}
                      </div>
                    {%- endif -%}
                </a>
              </li>
            {% endfor %}
          </ul>
          {% if enable_thumbnail_slides == true %}
            <button type="button" class="btn btn--link medium-up--hide thumbnails-slider__btn thumbnails-slider__next thumbnails-slider__next--{{ section.id }}">
              {% include 'icon-chevron-right' %}
              <span class="icon__fallback-text">{{ 'sections.slideshow.next_slide' | t }}</span>
            </button>
          {% endif %}
        </div>
      {% endif %}
    </div>
 
    <div class="grid__item {{ product_description_width }}">
      <div class="product-single__meta">
 
        <h1 class="product-single__title">{{ product.title }}</h1>
<span class="stamped-product-reviews-badge stamped-main-badge" data-id="{{product.id}}" data-product-title="{{product.title}}" data-product-type="{{product.type}}" style="display: block;"></span>
 
          <div class="product__price">
            {% include 'product-price', variant: current_variant, show_vendor: section.settings.show_vendor %}
          </div>
                
         {% include 'ZooomyListWishlistProduct' %}
          {%- if shop.taxes_included or shop.shipping_policy.body != blank -%}
            <div class="product__policies rte" data-product-policies>
              {%- if shop.taxes_included -%}
                {{ 'products.product.include_taxes' | t }}
              {%- endif -%}
              {%- if shop.shipping_policy.body != blank -%}
                {{ 'products.product.shipping_policy_html' | t: link: shop.shipping_policy.url }}
              {%- endif -%}
            </div>
          {%- endif -%}
 
          {% capture "form_classes" -%}
            product-form product-form-{{ section.id }}
            {%- unless section.settings.show_variant_labels %} product-form--hide-variant-labels {% endunless %}
            {%- if section.settings.enable_payment_button and product.has_only_default_variant %} product-form--payment-button-no-variants {%- endif -%}
            {%- if current_variant.available == false %} product-form--variant-sold-out {%- endif -%}
          {%- endcapture %}
 
          {% form 'product', product, class:form_classes, novalidate: 'novalidate', data-product-form: '' %}
            {% unless product.has_only_default_variant %}
              <div class="product-form__controls-group">
                {% for option in product.options_with_values %}
                  <div class="selector-wrapper js product-form__item">
                    <label {% if option.name == 'default' %}class="label--hidden" {% endif %}for="SingleOptionSelector-{{ forloop.index0 }}">
                      {{ option.name }}
                    </label>
                    <select class="single-option-selector single-option-selector-{{ section.id }} product-form__input"
                      id="SingleOptionSelector-{{ forloop.index0 }}"
                      data-index="option{{ forloop.index }}"
                    >
                      {% for value in option.values %}
                        <option value="{{ value | escape }}"{% if option.selected_value == value %} selected="selected"{% endif %}>{{ value }}</option>
                      {% endfor %}
                    </select>
                  </div>
                {% endfor %}
              </div>
            {% endunless %}
 
            <select name="id" id="ProductSelect-{{ section.id }}" class="product-form__variants no-js">
              {% for variant in product.variants %}
                <option value="{{ variant.id }}"
                  {%- if variant == current_variant %} selected="selected" {%- endif -%}
                >
                  {{ variant.title }}  {%- if variant.available == false %} - {{ 'products.product.sold_out' | t }}{% endif %}
                </option>
              {% endfor %}
            </select>
 
            {% if section.settings.show_quantity_selector %}
              <div class="product-form__controls-group">
                <div class="product-form__item">
                  <label for="Quantity-{{ section.id }}">{{ 'products.product.quantity' | t }}</label>
                  <input type="number" id="Quantity-{{ section.id }}"
                    name="quantity" value="1" min="1" pattern="[0-9]*"
                    class="product-form__input product-form__input--quantity" data-quantity-input
                  >
                </div>
              </div>
            {% endif %}
 
            <div class="product-form__error-message-wrapper product-form__error-message-wrapper--hidden{% if section.settings.enable_payment_button %} product-form__error-message-wrapper--has-payment-button{% endif %}"
              data-error-message-wrapper
              role="alert"
            >
              <span class="visually-hidden">{{ 'general.accessibility.error' | t }} </span>
              {% include 'icon-error' %}
              <span class="product-form__error-message" data-error-message>{{ 'products.product.quantity_minimum_message' | t }}</span>
            </div>
 
            <div class="product-form__controls-group product-form__controls-group--submit">
              <div class="product-form__item product-form__item--submit
                {%- if section.settings.enable_payment_button %} product-form__item--payment-button {%- endif -%}
                {%- if product.has_only_default_variant %} product-form__item--no-variants {%- endif -%}"
              >
                <button type="submit" name="add"
                  {% unless current_variant.available %} aria-disabled="true"{% endunless %}
                  aria-label="{% unless current_variant.available %}{{ 'products.product.sold_out' | t }}{% else %}{{ 'products.product.add_to_cart' | t }}{% endunless %}"
                  class="btn product-form__cart-submit{% if section.settings.enable_payment_button %} btn--secondary-accent{% endif %}"
                  data-add-to-cart>
                  <span data-add-to-cart-text>
                    {% unless current_variant.available %}
                      {{ 'products.product.sold_out' | t }}
                    {% else %}
                      {{ 'products.product.add_to_cart' | t }}
                    {% endunless %}
                  </span>
                  <span class="hide" data-loader>
                    {% include 'icon-spinner' %}
                  </span>
                </button>
                {% if section.settings.enable_payment_button %}
                  {{ form | payment_button }}
                {% endif %}
              </div>
            </div>
          {% endform %}
        </div>
 
        {%- comment -%}
          Live region for announcing updated price and availability to screen readers
        {%- endcomment -%}
        <p class="visually-hidden" data-product-status
          aria-live="polite"
          role="status"
        ></p>
 
      
        {%- comment -%}
          Live region for announcing that the product form has been submitted and the
          product is in the process being added to the cart
        {%- endcomment -%}
        <p class="visually-hidden" data-loader-status
          aria-live="assertive"
          role="alert"
          aria-hidden="true"
        >{{ 'products.product.loader_label' | t }}</p>
 
      <!-- orkun -->
          <div class="product-single__description rte" itemprop="description">
          {{ product.description }}
      </div>
      
      <div id="shopify-product-reviews" data-id="{{product.id}}">{{ product.metafields.spr.reviews }}</div> 
      
       {% if section.settings.show_share_buttons %}
         {% include 'social-sharing', share_title: product.title, share_permalink: product.url, share_image: product.featured_media %}
       {% endif %}
      
      <div itemprop="aggregateRating" itemscope itemtype="https://schema.org/AggregateRating">
<span itemprop="ratingValue">{{ product.metafields.spr.reviews | split: '"ratingValue": "' | last | split: '"' | first | plus: 0 }}</span>
yıldız – <span itemprop="reviewCount"> {{ product.metafields.spr.reviews | split: '"reviewCount": "' | last | split: '"' | first | plus: 0 }}</span> yorum
</div>
      
          
      {% comment %} Added on December 8 2020 by Jonathan L at Shopify  {% endcomment %}
    {%- if review_count > 0 -%}
      "aggregateRating": {
        "@type": "AggregateRating",
        "itemReviewed": {{ product.title | json }},
        "bestRating": "5",
        "worstRating": "1",
        "ratingValue": "{{ review_rating }}",
        "reviewCount": "{{ review_count }}"
      },
 {%- endif %}
 
 
    </div>
  </div>
</div>
{% unless product == empty %}
  <script type="application/json" id="ProductJson-{{ section.id }}">
    {{ product | json }}
  </script>
  <script type="application/json" id="ModelJson-{{ section.id }}">
    {{ product.media | where: 'media_type', 'model' | json }}
  </script>
{% endunless %}
 
{%- for field in product.metafields.instructions -%}
      <li>{{ field | first }}: {{ field | last }}</li>
    {%- endfor -%}
 
{% schema %}
 
 
luxuriaistanbul
Excursionist
33 0 4

and here how the product.liquid looks like:

 

{% comment %}
The contents of the product.liquid template can be found in /sections/product-template.liquid
{% endcomment %}

{% section 'product-template' %}
{% section 'product-recommendations' %}

{% if collection %}
<div class="text-center return-link-wrapper page-width">
<a href="{{ collection.url }}" class="btn btn--secondary btn--has-icon-before return-link">
{% include 'icon-arrow-left' %}
{{ 'products.product.back_to_collection' | t: title: collection.title }}
</a>
</div>
{% endif %}

<script>
// Override default values of shop.strings for each template.
// Alternate product templates can change values of
// add to cart button, sold out, and unavailable states here.
theme.productStrings = {
addToCart: {{ 'products.product.add_to_cart' | t | json }},
soldOut: {{ 'products.product.sold_out' | t | json }},
unavailable: {{ 'products.product.unavailable' | t | json }}
}
</script>

{% assign current_variant = product.selected_or_first_available_variant %}

<script type="application/ld+json">
{
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "{{ product.metafields.manysales.review_avg_rating }}",
"reviewCount": "{{ product.metafields.manysales.review_count }}"
},
"@context": "http://schema.org/",
"@type": "Product",
"name": {{ product.title | json }},
"url": {{ shop.url | append: product.url | json }},
{%- if product.featured_media -%}
{%- assign media_size = product.featured_media.preview_image.width | append: 'x' -%}
"image": [
{{ product.featured_media | img_url: media_size | prepend: "https:" | json }}
],
{%- endif -%}
"description": {{ product.description | strip_html | json }},
{%- if current_variant.sku != blank -%}
"sku": {{ current_variant.sku | json }},
{%- endif -%}
"brand": {
"@type": "Thing",
"name": {{ product.vendor | json }}
},
"offers": [
{%- for variant in product.variants -%}
{
"@type" : "Offer",
{%- if variant.sku != blank -%}
"sku": {{ variant.sku | json }},
{%- endif -%}
"availability" : "http://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}",
"price" : {{ variant.price | divided_by: 100.00 | json }},
"priceCurrency" : {{ cart.currency.iso_code | json }},
"url" : {{ shop.url | append: variant.url | json }}
}{% unless forloop.last %},{% endunless %}
{%- endfor -%}
]
}
</script>

EmmanuelFlossie
Shopify Partner
2953 221 710

You seem to have multiple codes, make sure to combine and only show one code. It looks like you use someone to do this for you.

I recommend getting back in touch with Added on December 8 2020 by Jonathan L at Shopify

To help you resolve this issue.

SImply copy pasting a few pages, does not work. Structured data can be installed from many different areas.

Get in touch with Emmanuel: a Google Shopping Specialist, Google Ads Diamond Product Expert, and also a a Google Product Expert Education 2021 & Tailwind 2023 Award winner.
Need Google Merchant Center or Google Shopping support?.
luxuriaistanbul
Excursionist
33 0 4

Thank you very much for your response. 

We had problem with shopify review app, that snippet was not working, even if we had the code for snippet. 

I will contact shopify support. Lets see if they recommend something.

simone83
Tourist
11 1 4

Is there any news about this case? Our structured data is set up correctly in our theme. And Google's rich snippet test says everything is perfect.

Until someone creates a product review using Shopify's product review app. Then it gets ugly because of the extra ld+json code added by the product review app. I tried to remove the ld+json code from the product review app via JS, but the JS code doesn't work (and I'm not a JS developer, so I'm lost). That's the only problem I have with structured data. I don't want a product review app to interfere with me and embed structured data into our HTML code itself.

So, how can I remove this extra structured data from the Shopify Product Review app? Does anyone have any ideas? Thank you.

EmmanuelFlossie
Shopify Partner
2953 221 710

You can simply ignore how ugly it looks. As long as there are no errors.

Warnings are ok as these are optional.

Google Merchant Center will read only the first product container.

Google Search Console will merge all containers together.

Get in touch with Emmanuel: a Google Shopping Specialist, Google Ads Diamond Product Expert, and also a a Google Product Expert Education 2021 & Tailwind 2023 Award winner.
Need Google Merchant Center or Google Shopping support?.
simone83
Tourist
11 1 4

Thank you for your reply @EmmanuelFlossie !

Our structured data code in theme is at the top of the page and includes all necessary (and unnecessary) data, including review and breadcrumb data. And in the middle of the HTML code there is the inserted code from the review app which only includes a simple product object (with a lot of missing information) and the review data.

When I look at the rich result testing tool from Google then the order is wrong and the information are double. But at least everything is green. 😄

item-with-review.png

 

 

 

 

 

 

 

 

 

 

 

However, if I go to snippet preview then the search result doesn't contain any rich result information.

If a product doesn't have any reviews then everything works and also the rich result is shown with all information in the preview:
item-without-reviews.png

 

 

 

 

 

 

 

 

What do you think? 

EmmanuelFlossie
Shopify Partner
2953 221 710

I recommend looking through your code to ensure the complete data is first, ie at the top.

You will need to sift through the theme and see how everything is built.

Every theme is different, and even with the same theme, the coding will be different depending on custom edits.

Get in touch with Emmanuel: a Google Shopping Specialist, Google Ads Diamond Product Expert, and also a a Google Product Expert Education 2021 & Tailwind 2023 Award winner.
Need Google Merchant Center or Google Shopping support?.
simone83
Tourist
11 1 4

Hi Emmanuel.

Yeah. I know and we know our theme as well. 😄

Our structured data starts at line 630 in source code and the structured data from the review app starts at line 1811. That's why I'm wondering about the wrong order in the rich result testing tool from Google.

Structured data created and handled by us:

our-structured-data.png

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Structured data from review app:

review-app.png

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Seems correct (imho). And I don't know why Google is showing it wrong in the rich result testing tool.

 

SefSima
Visitor
3 0 0

I have added code fromhttps://feedarmy.com/kb/shopify-microdata-for-google-shopping/ , which is working good except that is doesn't have review snippets, so google search console is reporting a warning and as result, it's showing products = 0.

I understand that code should be something like bellow, but I am not sure which code to place instead of ???. I spent days to find/figure out this, without progress, so would appreciate any help. 

 

,"review":
[{"@context":"https://schema.org/",
"@type":"Review",
"description":"Shopify Product Reviews",
"reviewRating":[{"@type":"Rating","ratingValue":"???"}],
"reviewBody":"???",
"name":"???",
"author":[{"@type":"Person","name":"K???"}],
"datePublished":"???"
}]

 

EmmanuelFlossie
Shopify Partner
2953 221 710

In my code only aggregateRating is included. For reviews themselves they should be included by the review app you are using.

The codes do not need to be all in 1 code.

Get in touch with Emmanuel: a Google Shopping Specialist, Google Ads Diamond Product Expert, and also a a Google Product Expert Education 2021 & Tailwind 2023 Award winner.
Need Google Merchant Center or Google Shopping support?.
SefSima
Visitor
3 0 0

Hi Emmanuel, Thank your for your reply. I am using Shopify Product Review app, and no, review snippets do not exist (checked on https://search.google.com/test/rich-results), or I did something wrong on the way. I am quite sure that I did it as per your explanation. Thank you for that code and instruction. 

So it would be great if someone can point me out to what is the exact structure of product.metafields.spr.reviews, then I can probably use text parser to take it out.

Or if there is even easier way to extract review snippets - that would be amazing. 

EmmanuelFlossie
Shopify Partner
2953 221 710

If you are using Shopify review app, then I don't think they generate what you want. I recommend you contact Shopify directly for support.

My code, does not include reviews, only aggregateRating.

Get in touch with Emmanuel: a Google Shopping Specialist, Google Ads Diamond Product Expert, and also a a Google Product Expert Education 2021 & Tailwind 2023 Award winner.
Need Google Merchant Center or Google Shopping support?.
SefSima
Visitor
3 0 0

Dear Emmanuel, thanks for your reply. Yes, both Shopify Product Review app and your code do not provide review snippets - otherwise, you code would be perfect. I know it's possible to extract review snippets from SPR, because I saw it. But I cannot find how to do it. I read everything I could find as Shopify help and a everything else I could find online. 

So it would be great if someone can point me out to what is the exact structure of product.metafields.spr.reviews, then I can probably use text parser to take it out.

Or if there is even easier way to extract review snippets - that would be amazing. 

Leysam
Shopify Partner
112 14 44

Anybody who needs help with this, you can check my solution here or you can contact me directly. I've already helped 5 people with this issue.

 

 

Leysam | The Shopify Guy  

 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - Email me at leysam@grindot.studio

 - Check our work and services offer: https://www.grindot.studio/
Hobby-shop
Tourist
8 0 0

Hi Tim and all! This last code patch works, no more warning both in GST classic and in beta version (also inside GSC). Have you idea how to capture each single review in json-ld? We would like not to make API callback, perhaps would it possible trying via css the capture?
Something like this ..
{% if breadcrumb_entity_microdata != blank %}
<script type="application/ld+json">
{
"@context": "http://schema.org",
{{ reviews_entity_microdata }}
}
</script>
{% endif %}

Tks everyone, this community post is very useful with each contribution.

Hotcakes
Tourist
3 0 1

Just want to make sure nobody misses Emmanuels post at https://community.shopify.com/c/Technical-Q-A/Either-quot-offers-quot-quot-review-quot-or-quot-aggre... which has a solution that worked for me.


@EmmanuelFlossie wrote:

Hello all, I have updated the aggregatedRatings issue for Shopify reviews. You can copy the latest code here: Easy To Follow Structured Data Tutorial With Updated AggregatedRatings resolved


 

Akshay_V
Shopify Partner
438 16 58

@seegang-berlin 

I have checked the link and I found there are few errors and one more thing is review app repeating schema code the second time and it needs to be fixed.
Reference Screenshots: 
https://prnt.sc/qllt1a

Reference Link: 
https://search.google.com/structured-data/testing-tool/u/0/#url=https%3A%2F%2Fseegang.berlin%2Fprodu...

 

For this I need your store admin collaborator access and this issue is chargeable because it is time consuming task. Moreover, Once I submit update you can check solution on above reference link because Google search console take time for update its data around 15 to 20 days.

So please let me know.

Akshay Vaghasiya | Email: hello@lavitastic.com | Skype: akshayvaghasiya84
Want to modify theme or custom changes on store hire me.
If helpful then please Like and Accept Solution.
Buy me a coffee PayPal
seegang-berlin
Tourist
9 0 11

Hi Akshay,

 

I'm new to Shopify - just switching from Etsy and don't fully understand the Shopify "ways of doing things" yet.

Let me describe my perspective:

- I'm paying for a shop system that allows me to create a shop without advanced coding skills.

- after some days I discover that fundamental functions like customer communication, translations, review are not part of the deal

- I am forced to pay more for third party plugins which I all have to evaluate individually for their quality and performance - overall I'm now paying something like 50$/month for this.

- some missing features (i.e. reviews) are kindly provided by Shopify 

- I am very careful in not messing up my theme and not installing too many plugins

- after I made my selection, I actually restarted the entire shop from scratch to make sure I have no code garbage in my theme

- then I run into a *confirmed* bug caused by a policy change of Google not supported by Shopify's free review plugin.

 

And now I'm asked to pay again to have this bug fixed!?

I assume you can do nothing about this, because you are a freelancer paid by Shopify to manage the bushfires, but is this perception of mine correct?

 

Two constructive questions to move forward:

 

1. Could I solve the problem myself by simply deleting the affected products and recreating them from scratch?

2. Why are not all my products affected by this bug? Even more weird: one of the products in my list above (the number 9...) is showing up on Google totally fine:

Screen Shot 2020-01-10 at 09.39.26.png

So Google *IS* finding all information it needs and has even indexed it.

 

Cheers,

Jenny

 

 

seegang-berlin
Tourist
9 0 11

Re: Question 2

DAMMED - I did a few more tests with Google Structured Data Testing Tool on other of my products not mentioned by the Google Search Console and it looks like ALL of my 244 products have the same issue.

 

Not good! 

tim
Shopify Expert
3258 232 1178

@seegang-berlin 

I feel your pain.

You may read through my posts in this thread, where I tried to explain why the problem exists and why it's not easy to come up with universal fix. 

 

I know that Shopify tried to solve the problem once and recently once more, this time they moved away from microdata formatting to JSON-LD, but this, imho, does not fix it properly (as it creates an unnecessary extra object on the page with its own warnings and sometimes errors). Unfortunately, with this change the fixes I suggested do not work anymore out of the box.

 

The way your structured data is output depends on the theme you're using and there is more than one way to do it, some are incompatible. If your theme does not include the code to pull review data from the App(s), it would be necessary to modify it (DIY or hire a developer) to implement structured data properly.

Re-creating your products would not help.

 

However, I'd like to point out that it's a store-wide fix and not per-product as was suggested several posts earlier.

 

Regarding your question 2: Note that Google is usually very slow to recognise the changes (in most cases) and may still keep old data in its index(es). My impression is that there are several independent processes and one may still serve your products with proper reviews while another complains about wrong structured data in your search console. Synchronisation between them is slow, but will eventually happen, so I'd suggest fixing the problem ASAP.

 

seegang-berlin
Tourist
9 0 11

Hi @tim, Hi @Akshay_V 

 

in the attempt to understand what has happened and what options do I have -  here are few more questions:

 

1. Is the only way do get the "few errors and the code duplication error" out of my code to hire a developer like you?
2. Will this error not occur again, when I create new products or new collections once you have removed it from my code?

3. Will this problem occur again, if I switch to another theme?

4. Do you have a list of Themes/Review App s that do not run into this problem, in case I am willing to switch theme?

5. Can you (privately) send me a cost-estimate for the fix on my current theme?

 

Best,

Jenny

NaturalWraps_RB
Visitor
1 0 0

Hi Everyone,

 

I have been reading through this article. I have looked at the structured data tool which shows an issue but the information is in place so Im not sure what the issue is. Any suggestions?

 

https://search.google.com/structured-data/testing-tool/u/0/#url=https%3A%2F%2Fnaturalwraps.co.uk%2Fp...

 

Akshay_V
Shopify Partner
438 16 58

@NaturalWraps_RB 

I have checked the link which you have attached with your concern. I found there is lots of error https://prnt.sc/qpd941. One more thing you have not used any product review app and as per new google rich snippet aggregate rating or review is required so do you want to add product review app.

For fixing these errors you can hire me I will do it. If you want a faster response you can contact me directly on below contact information.

Akshay Vaghasiya | Email: hello@lavitastic.com | Skype: akshayvaghasiya84
Want to modify theme or custom changes on store hire me.
If helpful then please Like and Accept Solution.
Buy me a coffee PayPal
Jamie_Heartwood
Visitor
2 0 0

Or here is an idea: the Shopify Development team behind the Product Reviews App could just fix their broken code?!

 

For the record, I followed Tim's great advice (further above) and that has worked for me — so thank you, Tim!  🙂  I'm no coder (nor expert by any long stretch of the imagination) but I managed to figure it out from his advice (albeit with many a coffee!) so it definitely does work! 

 

If you can't fix it yourself (and Shopify simply aren't interested in fixing their app for us) then Tim definitely knows his stuff, if you need to hire someone I guess.

Akshay_V
Shopify Partner
438 16 58

@seegang-berlin 

Sorry, there is no way to remove unwanted code or fixing that code. You need to hire an expert like us to fix the theme issue or you can contact theme support to fix this error.

Akshay Vaghasiya | Email: hello@lavitastic.com | Skype: akshayvaghasiya84
Want to modify theme or custom changes on store hire me.
If helpful then please Like and Accept Solution.
Buy me a coffee PayPal
twebb
Tourist
4 0 3

I have read through all of the posts concerning Google Either "offers", "review", or "aggregateRating" should be specified error, but could not find a solution to this issue.

 

I have one error on all of my product pages. According to Google Structured Data Testing Tool this error is the product type.

 

"@type": "ListItem",
"position": 3,
"item": {
"@type": "Product",

 

Any help would be greatly appreciated.

 

https://inspiredbytheoutdoors.com/products/deer-family-42-metal-wall-art

Sabine_Mohr
Excursionist
85 0 6

What exactly would have to be deleted ? Thank you Sabine.

Beemohr
?We love to knit ?
* www.beemohr.com *  www.beemohr.de * 
Wilson-Betances
Visitor
1 0 0

Hello, can you help me please?

I can't find the file to clear the code.

ureb
Visitor
3 0 0

https://am81.net/ 

Same message received

Search Console
Products issues detected on https://am81.net/

To the owner of https://am81.net/:

Search Console has identified that your site is affected by 1 Products issues:

Top Errors

Errors can prevent your page or feature from appearing in Search results. The following errors were found on your site:

Either "offers", "review", or "aggregateRating" should be specified

We recommend that you fix these issues when possible to enable the best experience and coverage in Google Search.

Akshay_V
Shopify Partner
438 16 58

@ureb 

please read above comments.

Akshay Vaghasiya | Email: hello@lavitastic.com | Skype: akshayvaghasiya84
Want to modify theme or custom changes on store hire me.
If helpful then please Like and Accept Solution.
Buy me a coffee PayPal
ureb
Visitor
3 0 0

Either 'offers', 'review' or 'aggregateRating' should be specified 

i have read the comments but still unclear, i have a single page with this problem and i cannot fix it 


https://am81.net/products/2-5d-anti-glare-matte-frosted-tempered-glass-screen-protector-for-iphone-x...
12344.jpg

Akshay_V
Shopify Partner
438 16 58

@ureb 

You can not fix it by own because it is code error and it is not on a single page. It is for all the product pages.

Akshay Vaghasiya | Email: hello@lavitastic.com | Skype: akshayvaghasiya84
Want to modify theme or custom changes on store hire me.
If helpful then please Like and Accept Solution.
Buy me a coffee PayPal