Metric · E-commerce

What is average order value, and how do you measure it in Metabase?

Average order value (AOV) is the typical revenue per order. It's one of the three levers of e-commerce revenue — traffic × conversion rate × AOV — and the one you move with bundling, upsells, and free-shipping thresholds. Measure it in Metabase from store data synced into a database (Shopify, WooCommerce, or BigCommerce).

TL;DR — AOV = net revenue ÷ order count. Decide once whether "net" excludes tax, shipping, discounts, and refunds, and report the median next to the mean — order values are right-skewed, so a few big orders inflate the average.

How is average order value calculated?

AOV = total revenue over a period ÷ number of orders in that period. The judgment is in "revenue":

  • Net of discounts — subtract promo codes and automatic discounts; gross AOV overstates what you actually earn.
  • Excluding tax and shipping — usually yes, so AOV reflects product revenue, not pass-through charges.
  • Net of refunds — decide whether a refunded order still counts, and be consistent.

What data does AOV need?

  • An orders table with a monetary total and a created_at.
  • Discount, tax, shipping, and refund fields so you can define net revenue.
  • A financial/payment status to exclude unpaid or cancelled orders.
  • Channel or campaign fields for segmentation.

SQL patterns

AOV by month (mean and median)PostgreSQL

Net order total averaged monthly, with the median for the skew.

-- Average order value by month, with the median alongside the mean.
SELECT
  date_trunc('month', o.created_at)                       AS month,
  COUNT(*)                                                AS orders,
  ROUND(AVG(o.net_total), 2)                              AS mean_aov,
  ROUND(
    PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY o.net_total)::numeric, 2
  )                                                       AS median_order_value
FROM orders o
WHERE o.financial_status = 'paid'
GROUP BY date_trunc('month', o.created_at)
ORDER BY month;
AOV by acquisition channelPostgreSQL

Which channels bring bigger baskets over the last 90 days.

-- AOV by acquisition channel to see which traffic buys bigger baskets.
SELECT
  o.channel,
  COUNT(*)                          AS orders,
  ROUND(SUM(o.net_total) / NULLIF(COUNT(*), 0), 2) AS aov
FROM orders o
WHERE o.financial_status = 'paid'
  AND o.created_at >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY o.channel
ORDER BY aov DESC;

Pitfalls

Using gross totals with tax and shipping.→ That inflates AOV with pass-through money you don't keep. Use net product revenue.
Reporting only the mean.→ Order values are right-skewed; show the median so a few large orders don't mislead.
Ignoring refunds and cancellations.→ Counting refunded orders at full value overstates AOV. Decide the rule and apply it everywhere.
Mixing currencies.→ Convert to one reporting currency before averaging across regions.

Where this metric applies

Analytics

Metrics

FAQ

Should AOV include tax and shipping?
Usually no. AOV is most useful as a measure of product revenue per order, so exclude tax and shipping (pass-through amounts) and report net of discounts. The key is to define it once and keep it consistent across every dashboard.
How do I increase average order value?
The common levers are product bundling, cross-sells and upsells at checkout, volume discounts, and free-shipping thresholds set just above your current AOV. Track AOV alongside conversion rate so a bigger basket doesn't come at the cost of fewer completed orders.
Why report the median order value too?
Because order values are right-skewed — a handful of large orders pull the mean up and hide the typical customer's basket. The median shows what a normal order actually looks like, so report it next to the mean.