What is contribution margin?

Contribution margin is what is left of an order's revenue after the costs that scale directly with it: the cost of the goods sold, the shipping it cost you to fulfil, and — for marketplace orders — the fees the marketplace reports against the order. It excludes fixed overhead — rent, salaries, software — on purpose: it answers "does selling one more of this make money," not "is the business profitable," which is a separate, larger question (net operating profit).

Formula

contribution margin % = (net revenue − COGS − shipping cost − payment fees − marketplace fees) ÷ net revenue

Worked example

A product line sells for €50,000 of gross revenue, with €2,000 of order-level discounts applied (net revenue €48,000), all sold through your own store. Cost of goods sold is €22,000 and shipping cost allocated to those orders is €3,000; there are no marketplace fees. Contribution margin is €48,000 − €22,000 − €3,000 = €23,000, or 47.9% of net revenue.

How Saldo Metrics computes it

canonical.v_contribution_margin is the line-item-grain source every other margin figure in the product rolls up from, counting completed sales only — cancelled orders, and orders refunded in full, are excluded, which is the intended definition of a countable sale across the app. For each order line it takes line_revenue_base, subtracts that line's pro-rata share of the order's discount (allocated_order_discount_base), the resolved unit cost from cost_source_record times quantity (line_cogs_base — the highest-trust confirmed cost record valid on the order date), and that line's pro-rata share of the order's shipping cost, any marketplace order fees the platform reports, and the order's payment fee (allocated_overhead_base). The payment fee comes from the merchant's own fee rules — a percentage plus a fixed amount per payment method, optionally by country and date range — priced against every order. The shipping cost comes from the merchant's own carrier tiers, priced by carrier, weight, destination and order value.

An order whose shipping cost no tier matches, or whose payment fee no rule matches, is treated exactly like an order with no confirmed product cost: its margin is unknown, not zero. contribution_margin_base is NULL for every line of that order (not just a partial figure with the missing charge silently read as free), the same order-grain rule described below for a missing product cost. This is deliberate: an org with no carrier tiers or no fee rules configured yet would otherwise show an inflated margin on every order until it finishes that setup. A platform-fulfilled marketplace order (FBA and equivalents) is not affected by the shipping leg of this rule — its shipping cost is already captured as a marketplace fee, not a merchant carrier charge — and a marketplace order's payment fee is always a resolved 0 (its referral commission already includes payment processing), never "missing." All four inputs are *_base (EUR) columns: every margin figure is arithmetic on amounts already converted to euros at the ECB rate for the transaction's own date, so no metric is computed from mixed currencies. Displaying that figure in a non-euro currency is a separate, final step applied to the finished number at one as-of rate.

Two populations read off this figure. The per-product, per-brand, per-category and per-supplier rollups below stay on v_contribution_margin's net-sale population. The P&L, net operating profit, order-level and SKU-level net profit, the store, channel and geo-opportunity margin and cost-coverage breakdowns, the v_country_revenue view, and order accounting's own margin column all instead read v_contribution_margin_all, which also books orders refunded in full — the shipping and marketplace fees those orders cost you were already spent and are not coming back, so leaving them out would erase real cost from exactly the figure meant to catch it, without erasing the revenue it earned. The revenue-by-country widget is not one of them: it reads order accounting filtered to net sales, so its margin covers net-sale orders only.

Two rollups aggregate that line-grain view to the grain their keys need: v_product_margin (top_margin_products, worst_margin_products, product_margin_pct) and v_brand_margin (brand_margin, brand_margin_pct). category_margin and supplier_margin group v_contribution_margin directly by each product's primary category or primary supplier, so they follow the dashboard's period and store filters. Each sums margin and net revenue at its grain and divides. avg_margin_pct is the average of v_product_margin.margin_pct across every product; margin_total_30d sums contribution_margin_base directly from v_contribution_margin over the trailing 30 days.

A refund is netted against the order it came from, not the month it happened in. When goods actually come back, both the revenue and the cost of those units reverse — so a March order refunded in April still corrects March's figure, because that is the sale being unwound. Shipping and marketplace fees are not reversed: you already spent them getting the order out, refunded or not. A refund with nothing returned — a goodwill credit for a damaged box, say — reverses only the revenue; the goods are still gone, so their cost stays charged. That distinction runs on the number of units the platform reports as returned, not on the refund amount: v_refund_reversal reads that count off each refund event, and when a platform cannot report one, the cost stays charged rather than being guessed, with the line marked refund_quantity_unknown so it can be told apart from an ordinary one.

Why it matters

Revenue tells you what sold. Contribution margin tells you what selling it was worth — a bestseller with thin margin can contribute less to the business than a slower mover with a healthy one. Reprice, delist and product-mix recommendations are all built on this figure, not on revenue.

Common mistakes

  • Reading contribution margin as net profit. It excludes fixed overhead by design — a business can have healthy contribution margin on every order and still lose money if overhead outgrows it. Net operating profit is the figure that includes overhead.
  • Comparing margin % across products at very different price points without checking absolute margin too — a low-price, high-margin-% item can contribute less cash than a higher-price item at a lower percentage.
  • Trusting a margin figure with a high missing-cost rate. A line with no confirmed cost record has no margin at all — it drops out of margin totals rather than counting at a COGS of zero — so a product with incomplete cost data is measured on its costed lines only. The same applies at order grain to an unresolved shipping cost or payment fee: it nulls out the margin for every line of that order, not just the missing charge. v_contribution_margin exposes the combined reason per line as missing_cost, and the specific one as missing_product_cost / missing_shipping_cost / missing_payment_fee; v_product_margin rolls the combined flag up per product as any_missing_cost. See also the shipping-cost coverage and payment-fee coverage panels in org settings, which report how many orders are still unresolved and why.
  • Comparing this month's figure against the same month on the P&L. The two date refunds differently on purpose — this figure corrects the order that was refunded, the P&L books the refund in the month the credit note cleared — so they can disagree on a month with late refunds. See net operating profit.

Where you see this in the app

Dashboard, in the average margin KPI and the top/worst margin product tables; and the brand, category and supplier margin breakdowns across the app's profitability views.