Homeโ€บQuery Libraryโ€บShopify

Which Shopify products are being refunded the most?

A high refund rate on a specific product is a signal โ€” quality issue, misleading description, sizing problem, or shipping damage. This query surfaces it before it compounds.

๐Ÿ“Š Shopify๐Ÿ‘ฅ Shopify merchants๐Ÿ”ค Plain-English โ†’ SQL
Show me refund rate by product for the last 90 days, ordered by highest refund rate
โ†“
Shopify Refund Rate by Product โ€” generated by Taptic Data AI
WITH product_orders AS (
  SELECT
    li.product_id,
    li.title                         AS product_name,
    SUM(li.quantity)                 AS units_sold,
    ROUND(SUM(li.price * li.quantity)::numeric, 2) AS revenue
  FROM shopify_order_line_items li
  JOIN shopify_orders o ON o.id = li.order_id
  WHERE o.financial_status IN ('paid', 'partially_refunded', 'refunded')
    AND o.created_at >= NOW() - INTERVAL '90 days'
  GROUP BY li.product_id, li.title
),
product_refunds AS (
  SELECT
    li.product_id,
    SUM(li.quantity)                 AS units_refunded,
    ROUND(SUM(li.price * li.quantity)::numeric, 2) AS refund_amount
  FROM shopify_refunds r
  JOIN shopify_order_line_items li ON li.order_id = r.order_id
  WHERE r.created_at >= NOW() - INTERVAL '90 days'
  GROUP BY li.product_id
)
SELECT
  po.product_name,
  po.units_sold,
  COALESCE(pr.units_refunded, 0)   AS units_refunded,
  po.revenue,
  COALESCE(pr.refund_amount, 0)    AS refund_amount,
  ROUND(
    COALESCE(pr.units_refunded, 0)::numeric * 100
    / NULLIF(po.units_sold, 0), 2
  )                                AS refund_rate_pct
FROM product_orders po
LEFT JOIN product_refunds pr USING (product_id)
WHERE po.units_sold >= 10
ORDER BY refund_rate_pct DESC
LIMIT 25
Schema-aware SQL generated from plain English37 lines

This query was generated by Taptic Data from plain English against a real Shopify schema. In Taptic, you type the question โ€” the AI writes the SQL, runs it, and returns the result. You can edit the SQL, ask for explanations, and save it as a refreshable report.

Breaking it down line by line

  1. CTE "product_orders" gets units sold and revenue per product from line_items, joined to orders for status filtering
  2. CTE "product_refunds" gets units refunded and refund amount from the refunds table for the same period
  3. LEFT JOIN ensures products with zero refunds still appear (with 0% refund rate)
  4. HAVING units_sold >= 10 removes statistical noise from low-volume products
  5. Orders by refund rate descending โ€” your worst products appear first

Result description

A ranked table of products showing units sold, units refunded, revenue, refund amount, and refund rate percentage โ€” filtered to products with meaningful sales volume and sorted worst-first.

The business impact

Every refund costs you twice โ€” the lost revenue and the processing cost. A product with a 15% refund rate might look profitable on gross revenue but be destroying margin on net. Catching a 10% refund rate at its first sign is far cheaper than letting it run for a quarter.

Skip the SQL. Ask the question.

In Taptic Data, you type "Show me refund rate by product for the last 90 days, ordered..." and this SQL runs automatically against your real Shopify data.

Try Taptic Free โ€” $29.99/mo

No credit card required. Connect your data source in under 5 minutes.