Milly Software
InsightsEngagementPost-Purchase Engagement: The Shopify Chat Metric Most Analytics Miss
Engagement··6 min read

Post-Purchase Engagement: The Shopify Chat Metric Most Analytics Miss

Pre-purchase conversion is half the story. How a returning-customer support engagement metric reveals the chat value that pre-purchase tracking can't see.

V
Viet Le
co-founder · Milly Software

Most chat-widget effectiveness measurement focuses on pre-purchase conversion: did the visitor see the widget? Did they open it? Did they convert at a higher rate than the visitors who didn't see it? It's the right question for measuring acquisition lift, but it leaves a whole category of chat value invisible.

That category is returning customers. The widget's job for them isn't to convert — they're already converted. It's to handle the warranty question, the return policy lookup, the order-status check. That engagement keeps the customer in the merchant's ecosystem long enough for the next purchase to land. Pre-purchase tracking can't see any of it.

What post-purchase engagement captures

The metric is straightforward in definition, harder in practice: count orders that are followed by widget engagement within the merchant's configured attribution window. The Impact dashboard surfaces two cards backed by this idea:

  • ordersWithPostPurchaseEngagement — count of orders followed by a widget_opened event from the same visitor
  • revenueWithPostPurchaseEngagement — total revenue across those same orders

Same attribution window as the pre-purchase interactor metric (7 / 14 / 30 / 60 days, per-store). Same visitor-ID join. The difference is the time direction: pre-purchase looks backward from order to chat (was there chat in the 14 days before this order?), post-purchase looks forward (was there chat in the 14 days after?).

Why support-heavy and headless merchants need this

For a typical impulse-purchase store, post-purchase engagement is small relative to pre-purchase — the customer buys once and moves on. For support-heavy and headless merchants, the proportions invert.

UAG's setup is a clean example. Customers buy a phone case, then come back two months later asking about warranty coverage when their phone took a fall, or asking what the return policy looks like, or checking if a different model size is compatible with their existing gear. None of those conversations show up as "the widget caused a sale." All of them keep the customer engaged with UAG's catalog long enough to be present at the next case purchase six months later.

Without a post-purchase metric, the chat's contribution to that retention loop is invisible. The merchant looks at their pre-purchase lift number, sees an honest single-digit figure, and wonders why their interactor cohort feels more engaged than the lift suggests. The interactor cohort is more engaged — they're also coming back post-purchase, and that wasn't being counted.

The rollup architecture

Computing post-purchase engagement live would mean joining the orders table to analytics_events on visitor ID, for every order, every dashboard load. On a UAG-volume store that's a multi-second query. Worse, the same shape of query already runs for the pre-purchase interactor metric — so doing both live is double the cost.

The fix is precomputation. A nightly cron in milly-cloud-services (rollupWidgetAttribution.js) computes daily rows in a widget_attribution_dailytable:

widget_attribution_daily {
  store_id, order_date, window_days,
  interactor_orders_count,    interactor_revenue,
  post_purchase_orders_count, post_purchase_revenue
}

The table is keyed by (store_id, order_date, window_days) — one row per day per supported attribution window per store. The dashboard query becomes a sum over the date range:

SELECT
  COALESCE(SUM(post_purchase_orders_count), 0) as post_purchase_orders,
  COALESCE(SUM(post_purchase_revenue), 0) as post_purchase_revenue
FROM widget_attribution_daily
WHERE store_id = $1
  AND window_days = $2
  AND order_date >= $3 AND order_date <= $4

That's O(window-days) rows touched, not O(orders × events) joins. On UAG, Impact dashboard load went from seconds to milliseconds after the rollup landed. Same data, same truth, fundamentally different cost curve.

Both the interactor (pre-purchase) and post-purchase counts use the same rollup, so the savings apply to both metrics simultaneously. All four supported attribution windows get refreshed each night, so a merchant flipping their window from 7 to 30 days sees the new numbers on their next dashboard load — no backfill wait.

The Impact dashboard pair

On the Impact page, post-purchase engagement renders as a sibling card to Interactor Conversion. Same attribution-window label, same date range, same visitor-ID logic — different time direction. The merchant can see at a glance which side contributes more.

Pairing them on the same page surfaces the asymmetry in a useful way. A merchant whose interactor conversion is high but post-purchase engagement is low has a sales-funnel contribution that drops off after purchase — fine for impulse buys, signal of a missing retention loop for higher-LTV catalogs. A merchant with the opposite shape has a strong retention story without much new-acquisition lift. Most merchants land in between.

Either way, the math doesn't hide. Pre-purchase and post-purchase are both measurable, both shown side by side, both computed from the same source-of-truth rollup. The merchant doesn't have to choose which story to believe — the dashboard tells both.

Try Milly Chat

Want to see how this fits your store?
We'll set up a working session.

Get it on ShopifyTalk to sales →