All posts

Tutorial

How to show review stars on Shopify collection product cards

Add star ratings to the product cards in a Shopify collection grid by reading the reviews.rating metafield your review app maintains. Here's the Liquid for the stars, the review count, accessibility, and hiding the block for products with no reviews.

Bas Lefeber

Founder, learnshopify.dev · June 5, 2026 · 3 min read

Star ratings on the product cards in a collection grid are one of the highest-impact things you can add to a Shopify storefront: shoppers scan the grid and click the social proof. The feature looks like UI, but the important decision is about data: where do the stars come from?

Don't build a review system

Reviews are owned by an app (Judge.me, Loox, Yotpo, Shopify Product Reviews). The app collects, moderates, and stores them, and writes the aggregate to a rating metafield on each product. Your theme's only job is to read that metafield and draw the stars. Building your own review storage in the theme is the classic AI-suggested wrong turn.

Where the rating lives

The de-facto standard (and what Shopify's own Dawn theme reads) is the reviews namespace with two metafields: reviews.rating and reviews.rating_count. The first is a rating type, which is an object, so you read its .value:

liquid
{{ product.metafields.reviews.rating.value }}   {% comment %} e.g. 4.8 {% endcomment %}{{ product.metafields.reviews.rating_count }}    {% comment %} e.g. 124 {% endcomment %}

Note

Some apps use a different namespace (e.g. spr.reviews for the legacy Shopify Product Reviews app). Check Settings → Custom data → Products in your admin to see the exact namespace and key your app writes, then swap it into the snippets below.

Drawing the stars (no JavaScript)

Round the value, then loop one to five and print a filled star when the index is within the rating, an empty one otherwise. Pure Liquid, no script needed:

snippets/card-product.liquid
<span class="rating-stars" role="img" aria-label="Rated {{ product.metafields.reviews.rating.value }} out of 5">  {% assign rounded = product.metafields.reviews.rating.value | round %}  {% for i in (1..5) %}    {% if i <= rounded %}{% else %}<span class="star--empty"></span>{% endif %}  {% endfor %}</span><span class="rating-count">({{ product.metafields.reviews.rating_count }})</span>

The role="img" plus aria-label matter: without them a screen reader announces a meaningless run of star characters. With them it reads "Rated 4.8 out of 5." That's the production-grade version, and the part AI-generated snippets almost always skip.

Half stars

Rounding to whole stars is fine for a card. If you want half stars, render five star outlines and overlay a filled copy clipped to rating.value / 5 * 100% width with CSS — still no JavaScript, and it reads the same metafield.

Hide it for products with no reviews

A brand-new product has no reviews yet. Showing an empty five-star row (or worse, zero stars) looks broken and can hurt conversion. Guard the whole block on the count:

liquid
{% if product.metafields.reviews.rating_count > 0 %}  <span class="rating-stars" role="img" aria-label="Rated {{ product.metafields.reviews.rating.value }} out of 5">    {% assign rounded = product.metafields.reviews.rating.value | round %}    {% for i in (1..5) %}{% if i <= rounded %}{% else %}<span class="star--empty"></span>{% endif %}{% endfor %}  </span>  <span class="rating-count">({{ product.metafields.reviews.rating_count }})</span>{% endif %}

Now products with reviews show their stars and unreviewed products show nothing, exactly the behavior a merchant expects.

What AI tools get wrong here

  • Inventing a homemade review form and storage in the theme instead of reading the app's metafield.
  • Hardcoding five filled stars, so every product looks 5-star regardless of its real rating.
  • Reaching for a JavaScript widget when a Liquid loop renders server-side and faster.
  • Skipping the aria-label, leaving the rating inaccessible.
  • Forgetting the rating_count > 0 guard, so new products show an empty row.

Learn this properly · free lesson

Review stars on the product card

Build the star rating step by step in the interactive editor against a real collection: draw the stars, add the count and accessible label, then guard the unreviewed product.

Try this lesson — free

Frequently asked questions

Where does Shopify store a product's star rating?

Not in the product itself. A review app (Judge.me, Loox, Yotpo, Shopify Product Reviews) writes an aggregate to a metafield, conventionally reviews.rating (a rating type) and reviews.rating_count. Your theme reads product.metafields.reviews.rating.value and reviews.rating_count.

How do I show stars on the collection page product cards?

In your card snippet, round product.metafields.reviews.rating.value, loop {% for i in (1..5) %}, and print a filled star when i <= rounded and an empty one otherwise. Add the count from reviews.rating_count next to it.

How do I hide the stars for products with no reviews?

Wrap the whole rating block in {% if product.metafields.reviews.rating_count > 0 %} ... {% endif %} so a product with zero reviews renders nothing instead of an empty star row.

Which metafield namespace does my review app use?

Most use the reviews namespace (reviews.rating, reviews.rating_count). The legacy Shopify Product Reviews app used spr.reviews. Check Settings → Custom data → Products in your admin to confirm the exact namespace and key, then read that path in Liquid.

LiquidMetafieldsProduct cardsReviews

Keep going in the curriculum