> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hiveku.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Hiveku Reviews

> First-party, headless-compatible product reviews. Replaces Yotpo / Loox / Stamped / Okendo for headless storefronts. Server-rendered with aggregateRating in JSON-LD.

## What this is

Product reviews that work on a headless Next.js storefront. Yotpo, Loox, Stamped, and Okendo — the dominant Shopify review apps — are all Liquid-only and don't render on a custom storefront. Hiveku ships its own review system that's headless-native.

Three pieces:

1. **`<ProductReviews>`** server component on every PDP — rendered into the HTML on first byte, with full `aggregateRating` JSON-LD for Google rich snippets and AI search.
2. **Submission flow** — workflow email links shoppers to `/account/write-review?t=<token>`. Token is signed (HMAC, 30-day TTL) so we know which order, customer, and product the review is for.
3. **Moderation queue** — `/dashboard/commerce/shopify/reviews`. Pending submissions go here. One-click approve / reject / mark spam.

## Why this is the wedge over Yotpo / Loox / Stamped / Okendo

* All four are **Liquid-only**. They render via theme injection. Headless storefronts get nothing.
* Their pricing starts at $19/month and goes to $300+/month for the same merchant features.
* None of them ship `aggregateRating` JSON-LD on a headless storefront because they have no theme to inject into.

Hiveku Reviews is free with the Shopify integration, ships the same JSON-LD as Yotpo would (if Yotpo could), and is the alternative our [App Compatibility](/integrations/shopify/overview#app-compatibility) advisor recommends when it detects Yotpo / Loox / Stamped / Okendo on the merchant's store.

## What ships server-rendered

`<ProductReviews>` reads from the public list endpoint at render time. The PDP server component fetches reviews + computes the aggregate, embeds the result into the JSON-LD, and renders the review list:

```html theme={null}
<!-- Visible in view-source on the deployed site -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "...",
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": 4.7,
    "reviewCount": 23,
    "bestRating": 5,
    "worstRating": 1
  },
  ...
}
</script>

<section aria-labelledby="reviews-heading">
  <h2 id="reviews-heading">Reviews</h2>
  <!-- aggregate stars, count, histogram -->
  <ul>
    <li><!-- review 1 with stars + body --></li>
    <li><!-- review 2 --></li>
    ...
  </ul>
</section>
```

<Note>
  `aggregateRating` only renders when at least one approved review exists. Google's structured-data validator flags ratings with `reviewCount: 0` as invalid markup, which can suppress rich snippets across the entire shop.
</Note>

## The submission flow

Reviews are collected via the **workflow builder** — not a separate emailing system. Build a workflow that fires after `shopifyOrderCreatedTrigger`, waits N days, and sends an email with a signed review link.

<Steps>
  <Step title="Workflow trigger fires after an order">
    Use `shopifyOrderCreatedTrigger` (already exists from Shopify integration). Configure it with `onlyFirstOrders: false` (you want all customers, not just new) or scope by product.
  </Step>

  <Step title="Wait node delays delivery">
    Drop in a `wait` node with 14 days (or whatever cadence you want). Most merchants use 7–21 days post-purchase.
  </Step>

  <Step title="Email step builds the review URL">
    The email step uses `buildReviewRequestUrl()` from `@/lib/shopify/reviews` to mint the signed link:

    ```ts theme={null}
    const url = buildReviewRequestUrl({
      deployedSiteBaseUrl: 'https://yourshop.com',
      shopifyConnectionId: connection.id,
      accountId: account.id,
      customerEmail: order.customer.email,
      productHandle: line.productHandle,
      productTitle: line.productTitle,
      orderId: order.id,
    })
    ```

    Example output: `https://yourshop.com/account/write-review?t=<token>&handle=coffee-bag&product=Single-Origin%20Coffee%20Bag`
  </Step>

  <Step title="Shopper opens the link, fills the form, submits">
    Star rating (1-5), title, body, optional name. The form posts to Hiveku's public submit endpoint with the token.
  </Step>

  <Step title="Token is verified, review lands in moderation">
    Hiveku verifies the HMAC + TTL, decodes the embedded fields (no body fields can override identity), and inserts a `pending` review row.
  </Step>

  <Step title="Moderator approves or rejects">
    Notification appears in `/dashboard/commerce/inbox` (severity = urgent for 1-2 star reviews). Click through to `/dashboard/commerce/shopify/reviews`. Approve → it goes live and rich-snippet eligible. Reject → it disappears.
  </Step>
</Steps>

### Verified-purchase flag

Reviews submitted via a token that carries an `orderId` are auto-flagged `is_verified_purchase: true`. The PDP renders a small "Verified" badge next to the rating. This is the gold-standard reviewer trust signal.

Anonymous reviews (no token / token without `orderId`) are not supported in v1. The signed-link flow is the only submission path.

## Moderation queue

`/dashboard/commerce/shopify/reviews`:

* **Tabs**: Pending / Approved / Rejected / Spam
* **Per row**: rating stars, customer name + email, product handle, shop (multi-shop accounts), verified-purchase badge, body excerpt
* **Inline actions**: Approve / Reject / Mark Spam
* **Optimistic UI** — moves the row out of the current tab on click, no full refresh

Moderating is a per-account-member action. Owner/admin/member all qualify (intentionally loose — agencies want junior staff handling the queue). Every moderation event records the acting user\_id.

### Inbox alerts

When a review lands `pending`, it auto-seeds a row in `/dashboard/commerce/inbox`:

> **New review: ★★★★★ from [jane@example.com](mailto:jane@example.com) (verified purchase)**
> "These coffee bags arrived right on time and the flavor was..."
> Approve or reject from the moderation queue.

Severity: `urgent` for 1-2 star reviews (you want to read those first), `suggestion` otherwise.

## Workflow triggers on review events

Two trigger node types fire on review state changes:

| Trigger                         | Fires on                                                               |
| ------------------------------- | ---------------------------------------------------------------------- |
| `shopifyReviewSubmittedTrigger` | Every submission (any status, including pending)                       |
| `shopifyReviewApprovedTrigger`  | Moderator approval (the recommended trigger for "rewards" automations) |

A bare `shopifyReviewTrigger` matches both.

### Filter conditions

* `minRating` / `maxRating` — gate by star value
* `productHandles` — only react to specific products
* `connectionId` — multi-shop scoping
* `onlyFirstSubmission` — skip resubmissions
* `onlyVerifiedPurchases` — only fire on tokenized submissions
* `onlyApproved` — gate on moderation (recommended for any reward automation)

### Example automations

<CardGroup cols={2}>
  <Card title="Thank-you discount on a 5-star approved review">
    Trigger: `shopifyReviewApprovedTrigger`
    Filter: `minRating: 5, onlyApproved: true`
    Action: send\_email "Thanks for the kind words — here's 15% off your next order"
  </Card>

  <Card title="Internal alert on negative reviews">
    Trigger: `shopifyReviewSubmittedTrigger`
    Filter: `maxRating: 2`
    Action: notify slack #ops with reviewer email + body excerpt
  </Card>

  <Card title="UGC pull on photo reviews">
    Trigger: `shopifyReviewApprovedTrigger`
    (Phase 2 when photo upload ships)
    Action: log\_crm\_activity tagging contact 'ugc\_eligible'
  </Card>

  <Card title="Re-engagement to past reviewers">
    Use Hiveku CRM segment: `last_review_submitted_at < 90 days ago`
    Action: send\_email about a new product launch
  </Card>
</CardGroup>

## What gets scaffolded

Reviews ship **automatically** with `shopify_scaffold_product-detail-route` (the all-in-one storefront scaffold). For projects with a custom PDP that want to layer reviews in without re-emitting the storefront, run `shopify_scaffold_reviews`:

```
src/components/cro/
├── ProductReviews.tsx              # server component (fetches + renders)
└── ReviewSubmitForm.tsx            # client component (submit form)

app/account/
└── write-review/page.tsx           # form host page (noindex)
```

The PDP template imports `<ProductReviews>` and feeds it the pre-fetched aggregate data so the JSON-LD reads the same numbers as the visible review list (one fetch, two consumers).

## CRM linkage

Every review submission upserts the reviewer as a `crm_contacts` row (keyed by email). A future segment filter on `last_review_submitted_at` lets you build "thank-you" sequences targeted at reviewers without writing a new system.

## What we did not ship (Phase 2)

* **Photo upload** on reviews. Database column reserved (`photos JSON`); UI + S3 not wired.
* **Bulk import** from Yotpo / Judge.me CSV. Schema supports it; importer not built.
* **Q\&A** (questions and answers on product pages). Adjacent feature, separate scope.
* **Auto-approve high-rating reviews** from verified purchases. Schema supports it; UI toggle not exposed.
* **Cross-product review aggregation** (a brand-level rating across all products).

## What's next

<CardGroup cols={2}>
  <Card title="Workflow triggers" icon="bolt" href="/integrations/workflows">
    Build review-collection emails and reward automations.
  </Card>

  <Card title="Subscriptions" icon="rotate" href="/integrations/shopify/subscriptions">
    Reviews + subscriptions both share the customer-account scaffold.
  </Card>
</CardGroup>
