AstroBaaS

Search & discovery

Post-Purchase Upsell & Recommended Products

Paid pluginsize Mplanned, not built

Indicative price, not an offer: $19-39/mo

Generated from docs/plan/paid/post-purchase-upsell-recommended-products/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.

A paid module that sends a post-purchase email offer within minutes of checkout, recommending complementary products with a limited-time discount. Merchants can A/B test offer variations and track email open rate, click-through rate, and second-order conversion to measure AOV lift.

The problem

After customers checkout, they leave. Merchants have 30 minutes to capture their attention with a timely offer, but they have no tool to do it. A single email with the right product can boost AOV by 10-20%, but merchants need ML to pick the right products and A/B test to optimize.

What it does

  • Create post-purchase offers: merchant selects products to recommend, sets discount (%, fixed amount, or free shipping), sets offer validity window (e.g., 24 hours)
  • Trigger offer email automatically within 1-2 minutes of order completion (webhook-based)
  • Email includes recommended products with images, prices, and discount details (‘Buy now, get 15% off these add-ons’)
  • Email includes a unique tracking link that auto-applies the discount when customer clicks through
  • A/B test offers: merchant can run two offer variations (variant A vs B) simultaneously; each new order is randomly assigned to A or B
  • Track email metrics: open rate (if email system supports open tracking), click rate (unique clicks on recommendations), conversion rate (% of emails that lead to second purchase)
  • Track second orders created from post-purchase offers and mark them with source=post_purchase_offer
  • Display analytics dashboard: open/click/conversion rates, AOV lift (average order value of second purchases vs baseline), A/B test winner
  • Disable offers globally or per-merchant without stopping existing offers (new emails stop, existing offers remain valid)
  • Webhook events: post_purchase_offer_sent, post_purchase_offer_clicked, post_purchase_offer_purchased

What it deliberately does NOT do

Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.

  • Does not create discount codes automatically — core pricing module creates codes; this module applies them to offers.
  • Does not segment customers (e.g., ‘only offer to new customers’, ‘only to high spenders’) — that’s paid CRM; this module uses all customers equally.
  • Does not handle subscription add-ons (e.g., ‘add a subscription to this product’) — that’s separate subscription module.
  • Does not do cross-sell on abandoned carts — that’s a separate ‘abandoned cart’ feature.
  • Does not handle inventory allocation for post-purchase products — fulfillment system handles inventory; offers do not reserve stock.

Data model

New tables: PostPurchaseOffer (id, shopId, productIds array, discountPercent or discountFixed, validityDays, isActive, createdAt); PostPurchaseOfferTest (id, shopId, offerId, variantA, variantB, startDate, endDate, status); PostPurchaseOfferAssignment (orderId, testId, variant ‘A’|‘B’, assignedAt); PostPurchaseConversion (id, offerId, emailSentAt, emailOpenedAt, offerClickedAt, secondOrderId, secondOrderTotal, conversionAt). Migration required on first upgrade: none if new shops; existing shops enable feature on demand.

API

  • POST /admin/post-purchase-offers — create offer
  • GET /admin/post-purchase-offers — list all offers
  • GET /admin/post-purchase-offers/{id} — view offer details
  • PUT /admin/post-purchase-offers/{id} — edit offer
  • DELETE /admin/post-purchase-offers/{id} — delete offer
  • POST /admin/post-purchase-offers/{id}/tests — create A/B test
  • GET /admin/post-purchase-offers/{id}/tests/{testId} — view A/B test results
  • PUT /admin/post-purchase-offers/{id} — toggle isActive to disable/enable

Every route added here must also appear in src/pages/openapi.json.ts — a test fails the build if it does not.

Admin

Post-purchase offers dashboard with sections: (1) Active offers list showing name, products, discount, validity, and edit/delete buttons; (2) Create new offer form: name, product picker (checkboxes), discount input (% or $), validity days; (3) A/B test builder: select offer, create variant A and B (different products or discounts), set duration; (4) Test results page: side-by-side comparison of variants, showing open rate, click rate, conversion rate, AOV lift, statistical significance, and ‘Declare winner’ button; (5) Global toggle ‘Post-purchase offers enabled’ (on/off for shop); (6) Analytics summary card: total emails sent (all time), average click rate, average conversion rate, total AOV lift.

The seam — why this is paid

Core provides: order completion event/webhook, customer data, product catalog, email sending infrastructure, discount code application, tracking of second-order source. Paid module provides: post-purchase offer logic (product selection, discount configuration), A/B test infrastructure (variant assignment, results aggregation), second checkout flow (post-purchase cart and checkout), recommendation ranking (which products to offer).

Paid module owns post-purchase offer logic, product recommendation ML, and second-checkout funnel; core handles order state only

Dependencies

  • Orders table (existing)
  • Customers table (existing)
  • Products table (existing)
  • Email system and event hooks (core)
  • Discount/pricing system to create and apply codes (core)
  • Checkout flow (core)
  • Background job system (for scheduled email sends)

Acceptance checks

Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.

  • Post-purchase email is sent within 2 minutes of order completion
  • Email includes recommended products with images, descriptions, and ‘Buy now with discount’ button
  • Discount code in email auto-applies to the cart when customer clicks the link (no manual entry needed)
  • A/B test assigns each order to either variant A or B randomly (50/50 split)
  • Conversion rate (second orders / emails sent) is calculated correctly and displayed in test results
  • Second order created from a post-purchase offer is tagged with source=post_purchase_offer
  • Offer expires after X days; no new purchases are counted as conversions after expiration
  • Disabling an offer (toggle isActive=false) stops new emails immediately; existing offers remain valid until expiration

Risks

If email is sent too late (>24 hours), offer is stale and conversion drops. If discount code doesn’t auto-apply, friction kills conversion (customer abandons). If A/B test variant is flipped or reassigned mid-test, results are invalid. If second checkout doesn’t pre-populate customer info, friction kills conversion (customer re-enters email/address). If post-purchase emails are spammed (too many tests or variations running), unsubscribe rate increases and damages sender reputation. If offer discount is too small, customer ignores it (wrong AOV lift).

Commercial context

Suggested price$19-39/mo
Rival anchorKaching, FBP mention upsells; freemium with $15-30/mo for AI recommendations

The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.


Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full catalogue and ../../AI-GUIDE.md for how to work on this repository.