
Product Reviews Ratings
- 71 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Collect, moderate, and display customer reviews with star ratings and schema.org markup so products earn Google rich-result stars.
About
Sets up review collection, moderation, aggregate scoring, and AggregateRating structured data across major commerce platforms. A developer uses it when adding social-proof reviews or enabling star ratings in Google Search results.
- schema.org AggregateRating markup for Google star rich results
- Verified-purchase badging and moderation via platform review apps
Product Reviews Ratings by the numbers
- 71 all-time installs (skills.sh)
- Ranked #512 of 853 Sales & Marketing skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill product-reviews-ratingsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 71 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Collect, moderate, and display customer reviews with star ratings and schema.org markup so products earn Google rich-result stars.
Files
Product Reviews & Ratings
Overview
Product reviews are the strongest social proof signal in e-commerce — products with 5+ reviews convert at 270% higher rates than products with none. Every major platform has review apps that handle collection, moderation, schema.org markup for Google star ratings, and verified purchase badging without custom code. Only build a custom review system if you need proprietary moderation logic, deep API integration, or review data in your own database.
When to Use This Skill
- When launching a new store and needing a review collection and display system
- When implementing schema.org
AggregateRatingmarkup to enable star ratings in Google Search results - When building a moderation workflow to prevent fake or spam reviews
- When displaying verified purchase badges to increase review credibility
- When triggering post-purchase review request emails automatically after delivery
- When importing reviews from one platform or app to another
Core Instructions
Step 1: Determine platform and choose the right review tool
| Platform | Recommended Tool | Why |
|---|---|---|
| Shopify | Judge.me | Free plan includes unlimited reviews, photo reviews, verified purchase badges, schema.org markup, and post-purchase email requests |
| Shopify | Yotpo | More advanced features: Q&A, loyalty integration, Google Shopping reviews syndication — best for mid-market+ stores |
| WooCommerce | WooCommerce built-in reviews + WP Product Review plugin | WooCommerce has built-in star ratings; add WP Product Review for schema.org markup and verified purchase gating |
| WooCommerce | Judge.me for WooCommerce | Same feature set as the Shopify version; available as a WooCommerce integration |
| BigCommerce | Judge.me or Yotpo | Both available on the BigCommerce App Marketplace with full feature parity |
| Custom / Headless | Build review API | Required when reviews need to live in your own database with custom moderation logic |
---
Step 2: Platform-specific setup
---
Shopify
Option A: Judge.me (recommended — free, full-featured)
1. Install Judge.me Product Reviews from the Shopify App Store 2. Judge.me automatically sends a post-purchase review request email after a configurable delay:
- Go to Judge.me → Settings → Review Request Emails
- Set delay to 5–7 days after fulfillment (gives customers time to receive and use the product)
- Customize the email template with your brand colors and product images
3. Configure review display:
- Go to Judge.me → Widgets → Install Widgets
- Enable the review widget on your product template (Judge.me provides a one-click install)
- Enable the star rating snippet in product listings
4. Enable schema.org markup:
- Go to Judge.me → Settings → SEO
- Ensure "Add aggregate rating schema" is enabled — this is what enables star ratings in Google search results
5. Configure verification and moderation:
- Go to Settings → Review Settings
- Enable Verified Purchase Only: only customers who bought the product can leave a review
- Enable Auto-publish verified reviews, manual moderation for unverified reviews
- Set profanity filter to "Medium" or higher
Option B: Yotpo (mid-market and enterprise)
1. Install Yotpo Reviews from the App Store 2. Configure review request timing in Yotpo → Settings → Review Request 3. Enable Google Shopping Reviews syndication if you run Google Shopping campaigns — Yotpo sends review data directly to Google 4. Use Yotpo Q&A to add a question-and-answer section below reviews on the PDP
Testing schema.org markup: After enabling Judge.me or Yotpo schema output, validate with Google's Rich Results Test using your product page URL. Star ratings appear in Google Search within 1–2 weeks of indexing.
---
WooCommerce
WooCommerce built-in reviews (free, basic):
1. Go to WooCommerce → Settings → Products → Reviews 2. Enable Enable product reviews 3. Enable Show "verified owner" label on customer reviews — this restricts reviews to customers who purchased the product 4. Enable Reviews can only be left by "verified owners" to gate unverified submissions
Adding schema.org markup and enhanced display:
1. Install WP Product Review from the WordPress plugin directory 2. WP Product Review adds:
- Aggregate star rating schema.org markup (required for Google rich results)
- Star rating display in product listings
- Review pros/cons fields
3. Configure in WP Product Review → Settings
Automating review request emails:
1. Install Klaviyo or AutomateWoo for post-purchase email automation 2. In Klaviyo: create a Flow triggered by the "Placed Order" event with a 7-day delay, containing a review request link 3. In AutomateWoo: go to AutomateWoo → Workflows → Add → trigger: "Order Status Changed to Completed" with a 7-day delay
Judge.me for WooCommerce:
- Install Judge.me for WooCommerce (available at judge.me)
- Provides the same review request emails, verified purchase gating, and schema markup as the Shopify version
---
BigCommerce
Judge.me for BigCommerce:
1. Go to Apps → Search "Judge.me" and install 2. Same configuration as the Shopify version — review request emails, schema markup, and verified purchase gating work identically
BigCommerce built-in product reviews: 1. Go to Products → [Product] → Reviews tab to manually moderate reviews 2. Go to Settings → Store Settings → Miscellaneous → enable Product Reviews 3. Built-in reviews do not include schema.org markup — install Judge.me or Yotpo to get Google star ratings in search results
Yotpo for BigCommerce: 1. Install from the BigCommerce App Marketplace 2. Includes Google Shopping Reviews syndication and SMS review requests alongside email
---
Custom / Headless
For headless storefronts, build a review pipeline with post-purchase trigger, moderation, Bayesian aggregate scoring, and schema.org output:
// lib/reviews.ts
// POST /api/reviews — accept review submission with signed token verification
export async function submitReview(req: Request, res: Response) {
const { token, productId, rating, title, body, authorName } = req.body;
// Validate signed token (generated in post-purchase email, prevents spam)
const tokenData = await verifyReviewToken(token);
if (!tokenData) return res.status(401).json({ error: 'Invalid or expired review token' });
const verifiedPurchase = await db.orderItems.exists({ orderId: tokenData.orderId, productId });
// Auto-moderation: spam score + profanity check
const spamScore = await checkSpam({ body, authorName, ip: req.ip });
const hasProfanity = await checkProfanity(body + ' ' + title);
const status =
spamScore > 0.8 ? 'spam' :
hasProfanity ? 'pending' :
verifiedPurchase ? 'approved' : 'pending';
const review = await db.reviews.create({
productId, orderId: tokenData.orderId, customerId: tokenData.customerId,
authorName, authorEmail: tokenData.email, rating, title, body,
verifiedPurchase, status, approvedAt: status === 'approved' ? new Date() : null,
});
if (status === 'approved') await updateProductRatingSummary(productId);
res.json({ reviewId: review.id, status });
}
// Bayesian aggregate: prevents a 2-review product with 5.0 outranking a 200-review product with 4.7
export async function updateProductRatingSummary(productId: string) {
const reviews = await db.reviews.findMany({ where: { productId, status: 'approved' } });
const rawAverage = reviews.length > 0
? reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length : 0;
const globalMean = await db.reviews.globalAverageRating();
const C = 5; // confidence weight — trust product's own average after 5+ reviews
const bayesianAverage = (C * globalMean + reviews.reduce((s, r) => s + r.rating, 0)) / (C + reviews.length);
await db.productRatingSummaries.upsert({ productId }, {
productId, reviewCount: reviews.length,
averageRating: Math.round(bayesianAverage * 10) / 10,
rawAverageRating: Math.round(rawAverage * 10) / 10,
});
}
// Emit schema.org AggregateRating JSON-LD — required for Google star ratings in search
export function buildProductSchema(product: Product, ratingSummary: { reviewCount: number; averageRating: number }) {
return {
'@context': 'https://schema.org',
'@type': 'Product',
name: product.name,
image: product.images.map(i => i.url),
description: product.description,
sku: product.sku,
offers: {
'@type': 'Offer',
price: (product.priceInCents / 100).toFixed(2),
priceCurrency: 'USD',
availability: product.inventoryQuantity > 0 ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock',
},
...(ratingSummary.reviewCount > 0 && {
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: ratingSummary.averageRating.toFixed(1),
reviewCount: ratingSummary.reviewCount,
bestRating: '5',
worstRating: '1',
},
}),
};
}
// Trigger review request email 5 days after delivery
export async function triggerReviewRequest(orderId: string) {
const order = await db.orders.findById(orderId, { include: ['lineItems.product', 'customer'] });
const token = await createSignedReviewToken(orderId, order.customerEmail);
await reviewQueue.add(
'send-review-request',
{ orderId, email: order.customerEmail, token, products: order.lineItems.map(i => ({ productId: i.productId, name: i.product.name })) },
{ delay: 5 * 86400000, jobId: `review-request-${orderId}` }
);
}---
Step 3: Configure moderation workflow
All review apps need a moderation strategy before go-live:
In Judge.me:
- Go to Settings → Review Settings → Moderation
- Set verified reviews to auto-publish; unverified reviews to manual review queue
- Enable the profanity filter
- Check the moderation queue weekly at Judge.me → Reviews → Pending
In Yotpo:
- Go to Yotpo → Moderation → Settings
- Configure auto-approve rules (e.g., star rating ≥ 3 and verified purchase → auto-approve)
- Yotpo sends a daily moderation digest email to your configured team email
For custom builds: auto-approve verified purchase reviews that pass spam and profanity checks; queue all others. Never skip moderation entirely — process the pending queue daily.
---
Step 4: Measure review impact
| Metric | Benchmark | Where to Find |
|---|---|---|
| Review collection rate | 3–8% of delivered orders | Judge.me Analytics → Email Performance |
| Products with 5+ reviews | Track % of active products | Judge.me → Insights |
| Average rating | 4.2–4.7 is healthy | Platform product listing page |
| Click-through rate from Google star ratings | Monitor in Google Search Console after schema is live | Search Console → Search Appearance → Rich Results |
Best Practices
- Use Judge.me or Yotpo before building from scratch — they handle schema markup, email timing, verified purchase logic, and moderation queues out of the box
- Send review requests 5–7 days after delivery, not after shipment — the customer needs time to receive and use the product
- Never delete negative reviews — suppressing them erodes trust and may violate FTC guidelines; respond to them publicly instead
- Show verified purchase badges — they increase review trust and help customers distinguish genuine reviews
- Cap carousels at 5–10 reviews on initial load — lazy load additional reviews to avoid blocking page LCP
- Validate schema.org markup with Google's Rich Results Test before launching — star ratings appear in search only when the JSON-LD is correct
Common Pitfalls
| Problem | Solution |
|---|---|
| Star ratings not showing in Google Search | Ensure AggregateRating.reviewCount is ≥ 1 and schema is in the <head> as JSON-LD; test with Google's Rich Results Test |
| Review request sent before product delivered | Trigger the review email from the delivery webhook, not the ship event; add 5-day buffer after delivery |
| Spam reviews flood the moderation queue | Enable Akismet integration in WooCommerce or use Judge.me's built-in spam filter; auto-reject submissions with high spam scores |
| Duplicate reviews from the same customer | Judge.me and Yotpo enforce one review per verified purchase; for custom builds add a unique constraint on (customerId, productId) |
| Review photos slow the page | Judge.me and Yotpo automatically resize and serve photos via CDN; for custom builds resize to 200px thumbnails at upload time |
Related Skills
- @user-generated-content
- @customer-segmentation
- @personalization-engine
- @conversion-rate-optimization
{
"context": "Tests whether the agent correctly implements Bayesian-smoothed aggregate rating calculation and generates valid schema.org Product/AggregateRating JSON-LD markup for Google Search star ratings. Covers the ProductRatingSummary model, Bayesian formula specifics, and structured data output.",
"type": "weighted_checklist",
"checklist": [
{
"name": "ProductRatingSummary model",
"max_score": 8,
"description": "Defines a data structure (type/interface/class) with both averageRating (Bayesian-smoothed) and rawAverageRating (simple mean) as separate fields"
},
{
"name": "Distribution field",
"max_score": 7,
"description": "ProductRatingSummary includes a distribution field tracking count per star level (1 through 5)"
},
{
"name": "Bayesian formula used",
"max_score": 12,
"description": "The rating calculation uses the formula (C * globalMean + sum_of_ratings) / (C + n), not a simple arithmetic mean"
},
{
"name": "Confidence weight C=5",
"max_score": 10,
"description": "The Bayesian confidence weight C is set to 5 (not 1, 10, or another value)"
},
{
"name": "Global mean used",
"max_score": 8,
"description": "The Bayesian formula incorporates a global average rating across all products, not a hardcoded fallback value"
},
{
"name": "Rounding to 1 decimal",
"max_score": 7,
"description": "Both averageRating and rawAverageRating are rounded to 1 decimal place (e.g., Math.round(x * 10) / 10 or equivalent)"
},
{
"name": "Schema.org context",
"max_score": 8,
"description": "JSON-LD output includes '@context': 'https://schema.org' and '@type': 'Product'"
},
{
"name": "AggregateRating type",
"max_score": 8,
"description": "JSON-LD includes aggregateRating with '@type': 'AggregateRating'"
},
{
"name": "ratingValue format",
"max_score": 7,
"description": "aggregateRating.ratingValue is formatted to 1 decimal place (e.g., '4.3' not '4.333...' or 4)"
},
{
"name": "bestRating and worstRating",
"max_score": 8,
"description": "aggregateRating includes bestRating set to '5' and worstRating set to '1'"
},
{
"name": "Conditional AggregateRating",
"max_score": 9,
"description": "The aggregateRating block is omitted (not included) when reviewCount is 0"
},
{
"name": "reviewCount in schema",
"max_score": 8,
"description": "aggregateRating.reviewCount reflects the actual number of approved reviews"
}
]
}
Product Rating Engine for E-Commerce Platform
Problem/Feature Description
A mid-sized online retailer is launching a first-party review system. The engineering team has collected product reviews in their database but now needs to build the calculation and display layer. The product manager has flagged a specific problem: several new products with just 1–2 glowing reviews are appearing at the top of category pages, outranking established products with hundreds of balanced reviews. The team wants a fair scoring system that doesn't reward products with very few reviews.
Additionally, the SEO team has noticed competitors showing star ratings in Google Search results (the yellow stars in the snippet), and wants the same for this store. They need structured data markup on every product page that passes Google's Rich Results Test.
Output Specification
Implement the solution as TypeScript (.ts) files. Produce:
1. `rating-calculator.ts` — A module that calculates aggregate product ratings. It should export a function that takes a list of review ratings (numbers) and a global mean rating, and returns a summary object. Demonstrate the calculation with a sample dataset of at least 3 products with different review counts (include a product with 0 reviews).
2. `schema-builder.ts` — A module that generates JSON-LD structured data for a product page. It should export a function that accepts a product object and a rating summary, and returns the JSON-LD object. Include a demonstration showing output for a product with reviews and a product without reviews.
3. `demo.ts` — A runnable script that imports and exercises both modules, printing the results to stdout. It should be executable with npx ts-node demo.ts (or compiled and run with tsc && node dist/demo.js).
Write package.json with any required dependencies. Do NOT include large binary assets or model files.
{
"context": "Tests whether the agent implements the review display widget with correct default sort order, pagination behavior, verified-purchase badge display, and a helpful votes endpoint that prevents duplicate voting.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Default sort: most helpful",
"max_score": 10,
"description": "The review listing query or API orders by helpfulVotes descending (most helpful first) as the default sort, not by createdAt or rating"
},
{
"name": "Initial page size 5-10",
"max_score": 9,
"description": "The initial/default page size for review display is between 5 and 10 reviews (inclusive), not 20, 50, or 'all'"
},
{
"name": "Pagination implemented",
"max_score": 8,
"description": "The review listing supports pagination (page/offset parameter or cursor), enabling subsequent pages to be loaded beyond the initial set"
},
{
"name": "verifiedPurchase badge",
"max_score": 9,
"description": "The review display output or component includes a visual indicator (badge, label, or flag) for reviews where verifiedPurchase is true"
},
{
"name": "Duplicate vote prevention",
"max_score": 10,
"description": "The helpful vote endpoint checks whether (reviewId, voterId) already exists before creating a vote"
},
{
"name": "409 on duplicate vote",
"max_score": 9,
"description": "The helpful vote endpoint returns HTTP 409 (or an equivalent conflict error) when the same voter attempts to vote again on the same review"
},
{
"name": "voterId uses session or IP",
"max_score": 8,
"description": "The voterId is derived from the customer's session ID when available, falling back to the request IP address (not just IP, not just session)"
},
{
"name": "helpfulVotes counter incremented",
"max_score": 8,
"description": "After a successful vote, the review's helpfulVotes counter is incremented (not replaced or recalculated from a join)"
},
{
"name": "Review request email timing",
"max_score": 9,
"description": "The post-purchase review request is scheduled with a 5-day delay after delivery (not immediately, not 1 day, not at ship time)"
},
{
"name": "Signed token in review link",
"max_score": 10,
"description": "The review request email link includes a signed token (not a plain customerId or orderId), so customers can submit reviews without logging in"
},
{
"name": "Only approved reviews shown",
"max_score": 10,
"description": "The public review listing filters to only show reviews with status 'approved'; pending/spam/rejected reviews are excluded"
}
]
}
Review Display and Helpfulness Voting for a Product Page
Problem/Feature Description
A fashion retailer's product pages currently show no customer reviews, and the conversion rate is significantly lower than industry benchmarks. The product team has asked the engineering team to surface customer reviews directly on product pages. The UX designer wants to show the most trustworthy and useful reviews first, with a way for shoppers to signal which reviews they found helpful. The ops team has also flagged that they need a post-purchase flow that asks customers for reviews at the right moment — early enough to be relevant, but late enough that customers have actually received and used the product.
The engineer needs to build: (1) an API endpoint and data layer for fetching reviews for a product page with sensible defaults, (2) a front-end component (or server-rendered HTML template) that displays reviews with appropriate trust indicators, and (3) the "helpful" voting mechanism so shoppers can upvote useful reviews, plus the job that schedules review request emails.
Output Specification
Produce the following TypeScript files:
1. `review-api.ts` — API handlers for:
GET /api/products/:productId/reviews— returns paginated approved reviews for a product pagePOST /api/reviews/:reviewId/helpful— records that a visitor found a review helpful
2. `review-widget.ts` (or .tsx if using React/JSX) — A component or template function that renders the review list. It should accept an array of review objects and render them, including any trust-related display elements.
3. `review-email-trigger.ts` — The function that schedules a post-purchase review request email job when an order is delivered. Include stub implementations for the queue and email sender.
4. `demo-output.json` — A static JSON file showing example API output from GET /api/products/:productId/reviews with at least 3 sample reviews (mix of verified and unverified).
Write package.json with any required dependencies.
{
"context": "Tests whether the agent implements the review submission endpoint correctly: signed token validation, verified-purchase detection, the three-way auto-moderation logic (spam/profanity/verified), and the correct data model fields including status transitions and approvedAt timestamp.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Review data model fields",
"max_score": 8,
"description": "The Review type/interface/schema includes: id, productId, orderId (nullable), customerId (nullable), authorName, authorEmail, rating typed as 1|2|3|4|5, title, body, verifiedPurchase boolean, status, helpfulVotes, createdAt, approvedAt (nullable)"
},
{
"name": "Token validation 401",
"max_score": 9,
"description": "The submission endpoint verifies the review token before processing; returns 401 (or equivalent error) when the token is invalid or missing"
},
{
"name": "verifiedPurchase from order",
"max_score": 8,
"description": "verifiedPurchase is determined by checking whether an order item exists matching both the token's orderId and the submitted productId (not just checking if a token exists)"
},
{
"name": "Spam threshold 0.8",
"max_score": 10,
"description": "Reviews with a spam score above 0.8 are assigned status 'spam' (the threshold is 0.8, not 0.5 or 0.9)"
},
{
"name": "Profanity triggers pending",
"max_score": 9,
"description": "Reviews that contain profanity (but are not spam) are assigned status 'pending', not auto-rejected or auto-approved"
},
{
"name": "Verified auto-approve",
"max_score": 9,
"description": "Verified purchase reviews with no profanity and spam score ≤ 0.8 are auto-approved (status 'approved'), not left as 'pending'"
},
{
"name": "approvedAt set on approval",
"max_score": 8,
"description": "approvedAt is set to the current timestamp when a review is auto-approved; it is null when status is 'pending' or 'spam'"
},
{
"name": "Summary update after approval",
"max_score": 9,
"description": "updateProductRatingSummary (or equivalent) is called only when a review is approved, not for pending or spam reviews"
},
{
"name": "Unique constraint on reviews",
"max_score": 8,
"description": "The schema or migration includes a unique constraint on the combination of customerId and productId (prevents duplicate reviews from same customer)"
},
{
"name": "No delete in moderation",
"max_score": 8,
"description": "The moderation actions support only 'approve' and 'reject' (status change); there is NO delete/destroy endpoint or action for reviews"
},
{
"name": "moderatedBy recorded",
"max_score": 7,
"description": "When a moderator approves or rejects a review, the moderatedBy field is set to the admin user's id"
},
{
"name": "moderationReason recorded",
"max_score": 7,
"description": "The moderation endpoint accepts and stores a reason field alongside the approve/reject action"
}
]
}
Customer Review Submission and Moderation System
Problem/Feature Description
An e-commerce startup is building a review system from scratch after migrating away from a third-party review platform. They need an API backend that handles review submissions from customers and gives the operations team the tools to moderate content before it goes live. The team has been burned before by fake reviews flooding their old system, so spam prevention and verified-purchase authenticity are top priorities.
The backend engineer has been asked to design and implement two parts: first, a customer-facing endpoint that accepts review submissions (triggered from post-purchase emails) and applies automatic content moderation, and second, an admin-facing API for the operations team to manually review flagged content. The solution should be written as TypeScript code that documents the intended behavior clearly enough that the rest of the team can implement the database layer.
Output Specification
Write the solution as TypeScript (.ts) files:
1. `types.ts` — TypeScript interfaces/types for the review data model and rating summary model.
2. `review-submission.ts` — The review submission handler. Include stub implementations for external dependencies (token verification, spam checking, profanity checking, database operations) as comments or simple mocks so the logic flow is clear.
3. `moderation.ts` — The admin moderation handlers: listing pending reviews (with pagination) and performing a moderation action on a single review.
4. `README.md` — A short explanation (1–2 paragraphs) of the moderation status flow: when reviews get auto-approved vs. sent to the queue vs. marked as spam, and what happens to the rating summary when a review is moderated.
The README should be written as real technical documentation (not a test description).
{
"name": "finsi/product-reviews-ratings",
"version": "0.1.0",
"summary": "Review collection, moderation, aggregate scoring, and display widgets",
"skills": {
"product-reviews-ratings": {
"path": "SKILL.md"
}
}
}