
Review Generation Engine
- 72 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Automatically request and collect product reviews post-purchase with timed email/SMS sequences, photo incentives, and fake-review detection.
About
Runs timed post-purchase email and SMS sequences to solicit reviews, with photo incentives and fraud detection for fake reviews. A developer uses it to systematically grow review volume after orders.
- Timed post-purchase email/SMS review-request sequences
- Photo incentives plus fake-review fraud detection
Review Generation Engine by the numbers
- 72 all-time installs (skills.sh)
- Ranked #510 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 review-generation-engineAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 72 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Automatically request and collect product reviews post-purchase with timed email/SMS sequences, photo incentives, and fake-review detection.
Files
Review Generation Engine
Overview
Product reviews are the most trusted form of social proof — 88% of shoppers consult reviews before purchasing, and products with 50+ reviews convert 4.6% better than those with none. The fastest path to high review volume is a systematic post-purchase request sequence triggered by delivery confirmation, not order placement. Dedicated review apps (Judge.me, Yotpo, Stamped) handle the entire request flow, photo upload UI, and verified buyer badges without custom code.
When to Use This Skill
- When a new product has fewer than 10 reviews and needs social proof to convert
- When overall review volume is low despite healthy order volume
- When wanting to add photo or video review incentives to an existing text-only system
- When migrating to a new review platform and needing to rebuild the request sequence
Core Instructions
Step 1: Choose the right review platform
| Platform | Best For | Shopify | WooCommerce | BigCommerce | Price |
|---|---|---|---|---|---|
| Judge.me | Best value, full features | App Store | Plugin | App Marketplace | Free tier; $15/mo for photos |
| Yotpo | Enterprise, social sharing, UGC | App Store | Plugin | App Marketplace | Free tier; $119+/mo |
| Stamped.io | Loyalty + review combination | App Store | Plugin | App Marketplace | $23+/mo |
| Okendo | DTC brands, media reviews, attributes | App Store | — | — | $19+/mo |
| WooCommerce Reviews | Basic, built-in | — | Built-in | — | Free |
Recommendation: Use Judge.me for most stores — the best feature-to-price ratio, free plan allows unlimited reviews, and $15/month unlocks photo reviews (the single highest-converting feature).
Step 2: Configure your review request sequence
---
Shopify with Judge.me
1. Install Judge.me from the Shopify App Store 2. Go to Judge.me → Settings → Review Requests 3. Configure the request timing:
- First request: 7 days after order fulfillment (not order placement — wait until the product is received and used)
- Second request (if no review): 14 days after first request
4. Go to Judge.me → Settings → Emails and customize:
- Email 1 (day 7): Simple request with star rating widget — clicking a star pre-fills the rating in the form
- Email 2 (day 21): Add a photo review incentive — "Add a photo and get 15% off your next order"
5. Enable Verified Buyer badge — displayed automatically on reviews from confirmed purchasers 6. Go to Judge.me → Settings → Moderation and set auto-publish rules:
- Auto-publish: ratings 3–5 stars
- Hold for manual review: ratings 1–2 stars
---
WooCommerce with Judge.me
1. Install the Judge.me for WooCommerce plugin 2. Configuration mirrors the Shopify setup 3. Alternatively, use Yotpo for WooCommerce if you want UGC and social sharing built in
For WooCommerce's built-in reviews + AutomateWoo: 1. Enable WooCommerce → Settings → Products → Reviews 2. Create an AutomateWoo workflow:
- Trigger: Order Delivered (or Order Status = Completed + 7 day delay)
- Action: Send Email with a link to the product review page
3. This is free but lacks photo review support and star rating widgets — use Judge.me for higher conversion rates
---
BigCommerce with Yotpo
1. Install Yotpo from the BigCommerce App Marketplace 2. Go to Yotpo → Reviews → Mail After Purchase and configure:
- Send timing: 7 days after order fulfilled
- Enable follow-up email: 14 days if no review submitted
3. Configure the smart prompts — Yotpo's review form is embedded in the email itself, allowing customers to submit a rating without leaving the email
---
Step 3: Set up photo review incentives
Photo reviews increase conversion rate 4× more than text reviews. The incentive should reward the photo specifically, not the review itself (incentivizing reviews violates FTC guidelines; incentivizing photo submission is permitted with proper disclosure).
In Judge.me: 1. Go to Judge.me → Settings → Coupons 2. Enable Photo review coupon: "Add a photo to your review and receive 15% off your next order" 3. Judge.me issues the coupon automatically after a photo review is approved
In Yotpo: 1. Go to Yotpo → Reviews → Incentives 2. Enable Media Reviews incentive with a discount code
Step 4: Display reviews on product pages
All review apps provide a widget snippet or theme block. For Shopify:
1. Go to Judge.me → Widgets → Review Widget 2. Install the widget in your theme via Shopify → Online Store → Themes → Customize → Add Section → Judge.me Review Widget 3. Place the review widget below the product description on product pages 4. Enable Review Carousel for the homepage to display your best reviews site-wide
Step 5: Measure review program health
| Metric | Healthy Target | Where to Find |
|---|---|---|
| Review request open rate | > 35% | App analytics |
| Review submission rate | 5–15% of requests | App analytics |
| Photo review rate | > 20% of all reviews | App analytics |
| Average product rating | > 4.2 stars | Product pages / app dashboard |
| Review count per product (top products) | > 50 | App analytics |
If submission rate is below 5%, the request is being sent too early (before delivery) or the form has too many required fields. Set the request to fire 7 days after fulfillment and reduce the form to star rating + 1 text field.
Step 6: Custom / Headless
For headless stores, use a review platform API (Judge.me, Yotpo, or Stamped all have REST APIs) rather than building a custom review system. The review collection, moderation, and display widgets are all available as embeddable components.
If you must collect reviews via a custom form, generate a tokenized review link that pre-identifies the customer and product so they do not need to log in:
// Generate a signed review link — valid for 30 days
function generateReviewToken(orderId: string, productId: string, customerId: string): string {
const payload = { orderId, productId, customerId, exp: Math.floor(Date.now() / 1000) + 30 * 86400 };
return jwt.sign(payload, process.env.REVIEW_JWT_SECRET!);
}
// Include ?rating=4 in the link when the customer clicks a star in the email
// This pre-fills the rating on the form — single most important UX optimization for review volume
// Schedule review requests via your order webhook (Shopify/WooCommerce/BigCommerce)
// Trigger: order status transitions to "delivered" (use carrier tracking webhook)
// Step 1: 7 days after delivery
// Step 2: 14 days after delivery (if no review submitted yet) — add photo incentive
// Cancel remaining steps when a review is submittedBest Practices
- Time the request to after confirmed delivery — asking for a review before the product arrives damages trust; use your platform's order fulfillment status, not order placed
- Make the star rating widget clickable in the email — each star links to the review form with
?rating=Npre-filled; this single feature typically doubles review submission rates - Never pay cash for positive reviews — financial incentives for reviews violate FTC guidelines; only offer incentives for adding media (photos/video) to an existing review
- Verified buyer badge drives conversion — mark reviews from confirmed purchasers and display it prominently; shoppers trust verified reviews significantly more than anonymous ones
- Respond to negative reviews publicly — brands that respond to 1–2 star reviews with empathy and resolution offers build more trust than brands with only 5-star reviews
- Cap at 2 review requests per order — a third request causes unsubscribes; two requests (day 7 + day 21) is the maximum
Common Pitfalls
| Problem | Solution |
|---|---|
| Review requests sent to customers who returned the order | Configure the app to skip review requests when an order has a return or refund; most review apps support this under refund settings |
| Low review rate despite high open rate | The form has too much friction — reduce required fields to star rating + one text field |
| Photo reviews not triggering the coupon | Check the app's approval settings — the coupon fires only after the photo review is approved, not submitted |
| Review volume spikes followed by sudden drops | You may have trained customers to wait for the incentive; make the incentive visible in email 2 only, not email 1 |
| Products with no reviews showing a blank section | Configure a fallback in the review widget — show "Be the first to review this product" with a CTA |
Related Skills
- @social-proof-widgets
- @ugc-campaign-management
- @email-marketing-automation
- @loyalty-program-optimization
- @customer-retention-engine
{
"context": "Tests whether the agent correctly implements a 3-step post-purchase review request sequence with proper timing, channels, delivery-triggered start, job cancellation on review submission, and correct queue configuration options.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Delivery-triggered start",
"max_score": 10,
"description": "The scheduling function is described or documented as being triggered after confirmed delivery (not after order placement or payment), referencing shipment/delivery events or webhooks"
},
{
"name": "Three steps defined",
"max_score": 8,
"description": "Exactly 3 steps are defined in the schedule (no more, no fewer)"
},
{
"name": "Step 0: email at 7 days",
"max_score": 8,
"description": "Step 0 uses the 'email' channel and a delay of 7 days (604800000 ms or equivalent)"
},
{
"name": "Step 1: SMS at 14 days",
"max_score": 8,
"description": "Step 1 uses the 'sms' channel and a delay of 14 days (1209600000 ms or equivalent)"
},
{
"name": "Step 2: email at 21 days",
"max_score": 8,
"description": "Step 2 uses the 'email' channel and a delay of 21 days (1814400000 ms or equivalent)"
},
{
"name": "SMS conditional on no email open",
"max_score": 8,
"description": "DESIGN.md or code comments indicate step 1 SMS is only sent if the step 0 email was not opened"
},
{
"name": "jobId format",
"max_score": 8,
"description": "Queue jobs are given a jobId matching the pattern `review-request-{orderId}-step{i}` (or equivalent template using orderId and step index)"
},
{
"name": "removeOnComplete",
"max_score": 8,
"description": "Jobs are added with `removeOnComplete: true` (or equivalent setting to clean up completed jobs automatically)"
},
{
"name": "Cancel on review submitted",
"max_score": 10,
"description": "The `onReviewSubmitted` (or equivalent) function iterates all 3 step indices and removes/cancels the corresponding job from the queue"
},
{
"name": "Return check skips skips",
"max_score": 8,
"description": "Code or DESIGN.md mentions skipping review requests for orders with active return requests (does NOT send to returned orders)"
},
{
"name": "Step 2 photo incentive noted",
"max_score": 8,
"description": "DESIGN.md or code comments note that step 2 is the photo incentive ask (15% off or photo review framing)"
},
{
"name": "Step indices in job data",
"max_score": 8,
"description": "Job payload includes the step index (0, 1, or 2) so the consumer knows which message to send"
}
]
}
Post-Purchase Review Collection Automation
Problem/Feature Description
A mid-sized e-commerce brand sells physical goods directly to consumers and wants to grow its product review volume without hiring a dedicated customer success team. They currently have zero automated outreach — reviews only come from customers who proactively seek out the form. The engineering team has a background job queue already running (BullMQ) and a basic order management system with delivery webhook support. They want to add systematic, multi-touch review request outreach that starts after each order is confirmed delivered and stops automatically as soon as a customer submits a review.
The head of growth has specifically asked that the solution not feel spammy — customers should get a first gentle nudge shortly after delivery, a light follow-up only if they haven't engaged, and one final ask with a meaningful incentive to capture photo reviews. The business also ships several hundred orders per week, so the team needs the approach to be queue-based, idempotent, and clean.
Output Specification
Implement a TypeScript module called review-scheduler.ts that exports:
- A
scheduleReviewRequests(order: Order)function that enqueues all outreach steps for a delivered order - A
onReviewSubmitted(orderId: string)function that cancels any remaining scheduled outreach for that order
Also write a short DESIGN.md documenting the timing of each step, the channel used for each step, and the rationale for when each step fires.
Use the following type definitions as a starting point (add whatever additional types you need):
interface Order {
id: string;
customerId: string;
lineItems: Array<{ productId: string }>;
}You may assume a reviewRequestQueue BullMQ queue is available as an import. Do not implement the actual email/SMS sending logic — just the scheduling.
{
"context": "Tests whether the agent implements the correct fraud/spam flag conditions, the specific decision rules mapping flags to moderation outcomes, the automated 15-minute moderation queue, correct aggregate rating calculation, and CDN cache invalidation.",
"type": "weighted_checklist",
"checklist": [
{
"name": "High-frequency flag",
"max_score": 8,
"description": "Raises 'high-frequency' flag when a customer has submitted more than 3 reviews within the past 1 hour"
},
{
"name": "Suspicious IP flag",
"max_score": 7,
"description": "Raises 'suspicious-ip' flag when more than 5 reviews have come from the same IP address within the past 7 days"
},
{
"name": "Too-short body flag",
"max_score": 7,
"description": "Raises 'too-short' flag when review body is fewer than 20 characters (NOT the same as the submission validation minimum of 10)"
},
{
"name": "Repetitive characters flag",
"max_score": 8,
"description": "Raises a repetitive-characters (or equivalent) flag using a regex that detects 4 or more consecutive identical characters (e.g., /(.){4,}/ or /(.\\1{3,})/)"
},
{
"name": "Incentive-disclosure-risk flag",
"max_score": 8,
"description": "Raises 'incentive-disclosure-risk' flag ONLY when rating is 5 AND the body contains the word 'discount' (case-insensitive)"
},
{
"name": "Profanity check",
"max_score": 7,
"description": "Calls checkProfanity (or equivalent profanity API/word-list) on the review body and adds a 'profanity' flag if found"
},
{
"name": "Rejected decision rule",
"max_score": 10,
"description": "Returns 'rejected' (only) when flags include 'profanity' OR 'high-frequency' — not for other flags alone"
},
{
"name": "Needs-human-review rule",
"max_score": 7,
"description": "Returns 'needs-human-review' when flags are present but neither 'profanity' nor 'high-frequency' is among them"
},
{
"name": "avgRating precision",
"max_score": 7,
"description": "avgRating is rounded/formatted to exactly 1 decimal place (toFixed(1) or Math.round to 1 decimal) before saving"
},
{
"name": "Published reviews only",
"max_score": 8,
"description": "Aggregate rating calculation filters to only reviews with status 'published' (excludes pending, needs-human-review, rejected)"
},
{
"name": "CDN cache invalidation",
"max_score": 8,
"description": "refreshProductRatingAggregate calls invalidateProductCache (or equivalent) after updating the product rating"
},
{
"name": "15-minute moderation schedule",
"max_score": 7,
"description": "MODERATION_RULES.md or code sets up the moderation queue to run automatically every 15 minutes (via cron, setInterval, or queue scheduler with 15-minute interval)"
},
{
"name": "Photo incentive on approval",
"max_score": 8,
"description": "When a review is approved and has a pending incentive, a unique discount code is created and a thank-you email is sent to the reviewer"
}
]
}
Review Moderation and Rating Aggregation System
Problem/Feature Description
An e-commerce platform has been accumulating reviews in a pending queue and needs a backend pipeline to automatically moderate them and update product ratings. The site has been targeted by waves of fake positive reviews — several products have been flooded with suspicious 5-star entries from a small set of IP addresses, and others show unusual bursts of activity from single accounts. The team has also noticed some reviews that are too short to be useful, contain nonsense characters, or awkwardly disclose that the reviewer received a benefit. They want a defensible, auditable moderation layer rather than relying entirely on manual review.
After moderation, approved reviews should be reflected in the product's star rating immediately, and the product page served from the CDN should be refreshed to show the latest rating. For reviews that include photos, an incentive (discount code) should be sent to the reviewer after approval.
Output Specification
Implement the following in a file named moderation.ts (TypeScript):
- A
moderateReview(reviewId: string)function that inspects a single review and returns a moderation decision - A
processReviewModeration()function that processes all pending reviews - A
refreshProductRatingAggregate(productId: string)function that updates the product's aggregate rating
Also write a MODERATION_RULES.md file documenting each flag your system can raise, the condition that triggers it, and the decision logic that maps flags to outcomes.
You may assume these imports are available: db (ORM), subHours, subDays (date-fns), checkProfanity, createUniqueDiscount, sendReviewThankYouEmail, refreshProductRatingAggregate, and invalidateProductCache. Do not implement those imported functions.
{
"context": "Tests whether the agent implements a tokenized, login-free review submission system with correct JWT expiry, pre-filled star rating, verified buyer marking, pending status, proper validation limits, and the photo incentive creation flow.",
"type": "weighted_checklist",
"checklist": [
{
"name": "JWT-based token",
"max_score": 8,
"description": "generateReviewToken uses jwt.sign() (or equivalent JWT library) to create a signed token — NOT a plain string or UUID"
},
{
"name": "Token 30-day expiry",
"max_score": 8,
"description": "The JWT payload sets an expiry of 30 days from creation (exp = now + 30 * 86400 or equivalent in seconds)"
},
{
"name": "No login required",
"max_score": 8,
"description": "GET /review/:token handler does NOT check session, cookies, or Authorization headers for authentication — token alone is sufficient"
},
{
"name": "Pre-filled rating",
"max_score": 8,
"description": "The form renderer reads a `rating` query parameter and passes it to the template as a pre-filled value (e.g., prefilledRating or equivalent)"
},
{
"name": "Token verify on POST",
"max_score": 8,
"description": "POST /review/:token verifies the JWT token before processing submission, returning 400/401 on invalid/expired tokens"
},
{
"name": "isVerifiedBuyer true",
"max_score": 8,
"description": "The created review record explicitly sets isVerifiedBuyer (or equivalent field) to true"
},
{
"name": "Status pending",
"max_score": 8,
"description": "The created review record is saved with status 'pending' (not 'published' or 'approved' directly)"
},
{
"name": "Rating validation 1–5",
"max_score": 8,
"description": "Submission rejects ratings outside the range 1–5 with a 400 error"
},
{
"name": "Body min length validation",
"max_score": 8,
"description": "Submission rejects a body shorter than 10 characters with a 400 error"
},
{
"name": "Title/body truncation",
"max_score": 8,
"description": "Title is truncated/limited to 100 characters AND body is truncated/limited to 2000 characters before saving"
},
{
"name": "Photo incentive created",
"max_score": 8,
"description": "When photos are present, a pending incentive record is created with type 'percent_off' and value 15 (NOT immediately issued as a discount code)"
},
{
"name": "Queue cancellation on submit",
"max_score": 8,
"description": "submitReview calls onReviewSubmitted (or equivalent) after saving, to cancel remaining review request queue jobs"
},
{
"name": "Token expiry/invalid handled",
"max_score": 4,
"description": "GET /review/:token renders an error page (not a 500) when the token is invalid or expired"
}
]
}
Customer Review Submission Endpoint
Problem/Feature Description
A growing direct-to-consumer brand has recently switched from a third-party review app to a custom-built solution. Their backend is a Node.js/Express API backed by a PostgreSQL database (accessed via a db ORM object). Review request emails are already going out with a special link, but clicking that link currently leads to a 404. The engineering team needs to build the review form rendering and submission endpoints from scratch.
A key product requirement is that customers should be able to submit reviews without creating an account or logging in — the review link should carry enough authentication context on its own. The team also wants the system to capture the star rating a customer clicked in the email, so the form feels pre-filled and reduces abandonment. Photo uploads should be encouraged, with an incentive automatically queued for later fulfillment once the review passes quality checks.
Output Specification
Implement the following in a file named review-endpoints.ts (TypeScript, Express handlers):
- A
generateReviewToken(orderId, productId, customerId)function that returns a signed link token - A
GET /review/:tokenhandler (renderReviewForm) that verifies the token and renders the form - A
POST /review/:tokenhandler (submitReview) that validates and saves the review
You may assume the following are available as imports: jwt (jsonwebtoken), db (ORM with db.products, db.productReviews, db.pendingIncentives), processReviewPhotos, onReviewSubmitted, and an Express Request/Response types. Use process.env.REVIEW_JWT_SECRET for the JWT secret. Do not implement the actual email sending or photo storage — focus on the endpoint logic.
Also produce a short NOTES.md describing the token lifecycle (how it's generated, what it contains, when it expires) and the photo incentive flow.
{
"name": "finsi/review-generation-engine",
"version": "0.1.0",
"summary": "Automatically request and collect product reviews post-purchase with timed email/SMS sequences, photo incentives, and fraud detection for fake reviews",
"skills": {
"review-generation-engine": {
"path": "SKILL.md"
}
}
}