Review request emails
Last updated: April 20, 2026
Most stores collect reviews through automated request emails — sent a set number of days after a trigger event (order fulfilled by default, with order created, paid, or delivery-confirmed as alternatives), with a link to the BetterReviews chat. This page covers how those emails work, when they’re sent, and how to tune the timing.
How it works
When the trigger event fires, BetterReviews schedules the review request email for the trigger’s timestamp plus your configured delay. Fulfilled and delivered triggers fire per physical shipment — if an order ships in two boxes, the customer gets two emails, each scoped to that shipment’s products. Created and paid triggers fire per order (they’re order-level events, nothing to split). The delay options depend on which trigger you pick:
- Order fulfilled (default): 3, 5, 7 (recommended), 14, or 30 days
- Order paid: 1, 7, 14 (recommended), 30, or 60 days
- Order created: 1, 7, 14 (recommended), 30, or 60 days
- Order delivered: 0, 1, 3 (recommended), 7, 14, or 30 days
The delay runs from the event’s actual Shopify timestamp, not from when BetterReviews receives it. An order that was paid three days ago with a 7-day delay will send four days from today, not seven.
Time-of-day: BetterReviews picks the date from your trigger plus delay, then picks a sensible time-of-day inside a 9am–9pm window — with a small per-row deterministic jitter so we don’t fire 400 emails at the same minute. The window comes from a 3-step fallback chain:
- Customer’s shipping country + province resolves → we send in the customer’s local 9am–9pm. (Best case — works for most US, UK, EU, JP, AU, BR, CA shoppers.)
- Customer address missing, store timezone known → we send in your store’s local 9am–9pm. (Common for digital products and gift cards. Customers in distant timezones may get suboptimal hours; coverage is logged for ops review.)
- Both missing → legacy “send at trigger-event time-of-day” behavior. Telemetry alerts ops when this fires so we can fix the upstream gap.
The window prevents midnight-burst delivery for international customers and helps open rates. You can disable the local-window logic per store by setting send_time_strategy: "off" via the Settings API — that reverts to legacy timing.
The email includes:
- A friendly short message
- A prominent Leave a review button linking to their personal review chat
- Your store’s logo and branding (see customizing the email template)
- A CAN-SPAM-compliant footer with the BetterReviews business address and an unsubscribe link
Each email includes a unique 32-byte random token in the link. Anyone with the link can open the hub or chat, so treat the link itself as the credential — don’t forward review-request emails. The token expires after 90 days by default (configurable 30–180 in Settings).
What triggers a review request
A review request email is scheduled when all of these are true:
- Collection is enabled in your Collect settings — off by default on new installs. You explicitly opt in so nothing goes out until you’re ready. Collection also flips off automatically if your BetterReviews subscription is cancelled, frozen, or uninstalled, and pending requests are bulk-cancelled at the same time. Re-subscribing does not auto-resume sending — you re-enable it manually in Collect → Review collection.
- The configured trigger event fired on the order. Shopify tells us when each order is created, paid, and fulfilled. We only create a request for the event you’ve chosen in Collect → Request timing.
- The order had at least one line item.
- The customer hasn’t explicitly withdrawn consent. BetterReviews sends review-request emails as transactional post-purchase messages by default — non-promotional, no discounts, no incentives, scoped to the product the customer bought. Under CAN-SPAM, PECR’s soft-opt-in, CASL’s transactional exemption, and GDPR’s Article 6(1)(f) legitimate-interest path, that classification covers customers without explicit marketing opt-in. We still always hard-skip customers whose Shopify
emailMarketingConsent.marketingStateisUNSUBSCRIBED(explicit withdrawal),REDACTED(GDPR Article 17 erasure marker), orINVALID(Shopify-flagged undeliverable) — regardless of any merchant setting. If your store needs the stricterSUBSCRIBED-only rule, see the marketing-consent model below. - The trigger fired recently enough. If the event is more than ~90 days old, or its timestamp puts the send date in the past (e.g. you install today but the trigger fired a month ago and your delay is 7 days), the request is marked
skippedinstead of being queued. This keeps install day from dumping a month of backlogged emails. - The customer isn’t on our suppression list (they haven’t unsubscribed, bounced, or complained). Suppression is rechecked right before delivery, not just at the time the request is created — if a customer unsubscribes between queue and send, the email is cancelled.
- The customer hasn’t already received a request for the same shipment or order. Dedup is per shipment for fulfilled/delivered triggers (one email per fulfillment, so a retry from Shopify won’t double-send), and per order for created/paid triggers. Switching triggers mid-flight doesn’t double-send.
If the order includes multiple products, the customer is sent to the customer review hub — a single page where they can choose which product to review first.
Timing
You set both the trigger event and the delay in Collect → Request timing.
Trigger event — which Shopify order event starts the countdown:
- Order fulfilled (recommended) — the countdown starts at each fulfillment. Every physical shipment triggers its own email, scoped to that shipment’s products. Split-warehouse orders and gift-card-plus-physical orders produce one email per physical shipment. Closest to when the customer actually receives the product, without relying on carrier tracking.
- Order delivered — the countdown starts when Shopify confirms the carrier delivered the package. The most accurate signal when it works, but not every carrier reports delivery reliably. See “Carrier reliability” below.
- Order paid — the countdown starts when payment is captured. Useful for pre-orders or dropship flows where “fulfilled” lags far behind the purchase decision.
- Order created — the countdown starts when the customer places the order. Useful for digital products or made-to-order where fulfillment may never fire.
Send request after — how many days after the trigger event to send. The option list adjusts based on your trigger:
- Fulfilled: 3, 5, 7 (recommended), 14, 30
- Delivered: 0, 1, 3 (recommended), 7, 14, 30
- Paid / Created: 1, 7, 14 (recommended), 30, 60
Stores with short-lived excitement (novelty items, food) typically prefer shorter delays. Stores selling products with a break-in period (shoes, skincare, kitchenware) do better at 7–14 days. Subscriptions and pre-orders usually pair “Order paid” with a 14–30 day delay. “Order delivered + 3 days” is a popular choice for merchants migrating from Okendo or Yotpo.
Changing trigger or delay. Saving a new trigger or delay routes you through a dry-run preview first — “X cancelled, Y rescheduled, Z newly overdue” — with two confirm choices:
- Apply. Commits the change AND cascades the queue. The semantics depend on what changed:
- Trigger change (or trigger + delay together): every in-flight request —
pending,scheduled,claimed,enqueued,awaiting_delivery— is cancelled. The new trigger produces a fundamentally different cohort, so the queue is wiped. To rebuild it, re-enable collection from the Collect → Review collection toggle, which runs the same backfill preview you saw the first time you turned it on. - Delay-only change:
scheduledrows are rewritten in-place against the new delay (their original event timestamp + new delay). Requests already past the scheduling stage (claimed/enqueued/awaiting_delivery) are left alone — they’re already in flight, and touching them would race with the email worker. Requests whose new send time is in the past fire on the next scheduler tick (within ~15 min).
- Trigger change (or trigger + delay together): every in-flight request —
- Apply to new orders only. Writes the new settings but leaves every existing request alone. Use this when you want the new trigger/delay for future orders but don’t want to disturb in-flight emails.
Past orders that didn’t make it into the queue (e.g. because their send window had already passed) are not retroactively included in either case.
Delivery fallback (for the “Order delivered” trigger)
Shopify’s carrier tracking data drives the delivered trigger, but not every carrier reports delivery. Major US carriers (USPS, UPS, FedEx, DHL Express) are reliable. Many European regional carriers (DPD, Evri, Royal Mail non-tracked, Yodel) and most smaller Latin American / Southeast Asian carriers rarely send a “delivered” status. International shipments often lose tracking at cross-border handoffs.
To make sure no customer is silently skipped, BetterReviews runs a fallback timer. When you pick the delivered trigger, every physical fulfillment creates a placeholder row with status awaiting_delivery. If delivery is confirmed, we promote that row to scheduled and send on time. If delivery is never confirmed within your fallback window, a background worker promotes the row anyway and sends the email. Each shipment gets its own placeholder — split shipments produce two emails, one per delivery.
The fallback window is configurable per merchant (3–30 days, default 14). You’ll find it in Collect → Request timing, visible only when you’ve selected the delivered trigger. The shorter you set it, the more emails fire without a delivery confirmation. 14 days is a safe middle ground for most carriers.
Carrier reliability — which trigger should you pick?
If you ship primarily via USPS, UPS, FedEx, DHL Express, Canada Post, or Australia Post → delivered is the best signal. The email arrives while the purchase is freshest in the customer’s mind.
If you ship via regional or international carriers that don’t consistently report delivery → stick with fulfilled. The fallback timer will catch up, but a lot of your sends will be “fallback-fired” anyway, which defeats the point of the delivered trigger.
Not sure which carriers your shipments use? Check any recent order in the Shopify admin → the fulfillment detail shows the tracking company. If most of your orders have no delivered status after a week, your carriers are silent — use fulfilled.
Sending a review request manually
If you want to send a review link outside the automatic flow — say, to a customer who emailed asking to leave a review after-the-fact — you can generate a review link via the API without triggering an email:
curl -X POST https://api.betterreviews.app/api/v1/review-requests/send \
-H "X-API-Key: YOUR_API_KEY" \
-d '{"email": "customer@example.com", "product_ids": ["shopify-7125386199075"], "skip_email": true}'
The response includes a hub_url you can paste into your own reply. skip_email: true creates the request with status manual (not scheduled), so the scheduler never touches it. See the API docs for details.
Review requests can also end up in one of two audit-only statuses:
skipped— no email is sent and the token won’t authorize a submission. Most common causes: the trigger event is older than your delay window at the moment we process it (so sending now would be silently late), the customer’s ShopifyemailMarketingConsent.marketingStateisUNSUBSCRIBED/REDACTED/INVALID(always hard-skipped), or you have Require marketing consent turned on and the customer’s state isn’tSUBSCRIBED. Visible to you in Collect → Recent activity so you can see which orders fell out and why.awaiting_delivery— placeholder while we wait for the carrier-delivery signal (only used when you’ve picked the delivered trigger). The email is neither sent nor authorize-able from this state; it promotes toscheduledwhen the delivered event arrives or the fallback window expires.
Two more terminal cancelled reasons are worth knowing about:
consent_gate_tightened— fires when a merchant flips Require marketing consent fromfalse → trueand in-flight rows for non-SUBSCRIBEDcustomers are cancelled (they’d no longer pass the new strict gate). The dry-run preview shows the count before you confirm.promotional_content_detected— fires when your email template contains a promotional phrase (discounts, percent-off, dollar-amount offers, coupons, promo codes, referral incentives, free-shipping mentions, loyalty/rewards framing, gift cards, or cross-promo language). The transactional classification BetterReviews relies on requires the email body to be non-promotional. We block at three points: when you save the template (the save returns an error identifying the offending field — nicer in-editor surfacing ships with our next UI update), when you send a test (same error pattern), and at runtime as defense-in-depth (the row is cancelled and the BetterReviews ops team gets an alert). This applies in any language your customers read — promotional phrasing in German, French, or Polish (e.g.Rabatt,réduction,kod rabatowy) is rejected the same way as the English equivalents. If you hit this, remove the phrase or use a marketing email platform like Klaviyo for promotional sends.
Marketing consent
You probably assumed BetterReviews only emails customers who ticked the “Email me with news and offers” box at checkout. We don’t — and neither do Klaviyo, Loox, or Okendo. Here’s why.
By default, BetterReviews sends review-request emails to every customer who bought from your store, not just the marketing-opted-in subset. We classify these as transactional (non-promotional, post-purchase, scoped to the product the customer bought) rather than as marketing. Regulators recognize that classification under CAN-SPAM (US), PECR’s soft-opt-in (UK), CASL §6(6)‘s transactional exemption (Canada), and GDPR Article 6(1)(f)‘s legitimate-interest path (EU).
The transactional classification rests on three things being true. We enforce all three:
- No promotional content in the email body. No discounts, no incentives, no cross-promo, no rewards/loyalty framing, no promo codes. The email asks one question — “how was your experience?” — and links to the review form. If you save a template with promotional content (e.g. “get 20% off your next order” in
body_text), the editor rejects the save with a 422, the test-send button rejects it too, and the runtime scanner cancels any in-flight email that somehow slipped through with the reasonpromotional_content_detected. See Email template editor → save errors for the matched-phrase callout. - Working unsubscribe + immediate suppression. Every email carries an unsubscribe link. Clicking it adds the customer to your store’s suppression list, and BetterReviews never sends them another email — automated or manual — without checking the list first.
- Respect explicit “no.” We always hard-skip customers whose Shopify
emailMarketingConsent.marketingStateisUNSUBSCRIBED(the customer explicitly withdrew consent),REDACTED(GDPR Article 17 erasure marker), orINVALID(Shopify flagged the email as undeliverable). This hard-skip is non-overridable — even if you turn on “Require marketing consent” or leave it off, those three states never receive a BetterReviews email.
Strict mode: Require marketing consent
If your legal team requires the stricter marketingState == "SUBSCRIBED" rule — only sending to customers who explicitly opted in to marketing at checkout — turn on Require marketing consent in Collect → Marketing-consent gate. Effects:
- Only customers whose Shopify consent state is
SUBSCRIBEDreceive review-request emails. Everyone else (the defaultNOT_SUBSCRIBED, plusPENDING, plus the always-hard-skippedUNSUBSCRIBED/REDACTED/INVALID) is skipped. - Flipping
OFF → ONcancels in-flight rows where the customer’s stored consent state at row creation isn’tSUBSCRIBED, withcancelled_reason = "consent_gate_tightened". The dry-run preview shows the count before you confirm. - Flipping
ON → OFFis a no-op cascade — every existing scheduled row is still valid under the more permissive rule, so nothing is cancelled or rescheduled. - Effective send volume drops sharply. If 4% of your customers tick the marketing checkbox at checkout (typical for stores without a sign-up incentive), only 4% of your daily cap actually sends — the rest get
skipped. Most stores see 5–15% consent rates. Check the consent-rate badge next to the toggle before flipping; the rate × your daily cap is your real ceiling. (For the math: effective ceiling ≈daily_cap × consent_rate.)
What about EU/UK customers?
The default treatment is legally sound for EU/UK customers too, provided the four PECR soft-opt-in conditions hold (the contact details came from a sale, the marketing is for similar products, the customer had an opt-out option at the point of collection, and every subsequent message carries an opt-out). All four hold by construction for BetterReviews — Shopify’s checkout exposes the “Email me with news and offers” checkbox as the at-collection opt-out, and our emails carry the unsubscribe link. If your legal team prefers the stricter explicit-opt-in interpretation, turn on Require marketing consent.
The forensic record for every flip lives in two audit logs: the merchant-side SettingsAuditLog (visible to you in Collect → Recent activity) and an internal founder_audit_log row. A regulator inquiry can answer “who flipped consent gating, when?” — and “what was the customer’s consent state when BetterReviews decided to email them?” via the marketing_state_at_creation column we capture at the moment of every consent-gate decision.
Unsubscribes
Every email includes an unsubscribe link, as required by CAN-SPAM. When a customer unsubscribes:
- They’re added to your store’s suppression list
- No future BetterReviews emails will go to them
- They can still use a review link you share manually (e.g. from the API skip-email flow) — unsubscribe only blocks automated emails
You don’t have to do anything — suppression is automatic.
Turning off request emails entirely
Some stores prefer to collect reviews only via the widget “Write a Review” button. You can turn off automated review request emails without disabling review collection:
- Open Collect
- Toggle Review collection off
- In the confirmation modal that shows the number of pending requests, click Disable collection to confirm. (If you have no pending requests, the modal is skipped and the toggle flips immediately.)
Screenshot of the Collect page with the collection toggle — manual capture, drop in here.
Your widget continues to work — customers can still start reviews from your product pages. We just stop sending anything post-purchase.
Screenshot of the Request timing section with the four-option trigger dropdown (Order fulfilled, Order delivered, Order paid, Order created) and the conditional fallback-days input that appears when “Order delivered” is selected — manual capture, drop in here.
Customizing the email itself
The look and copy of the review request email are configurable — logo, colors, subject, body. See the dedicated page:
Customizing the email template →