ROI (Return on Investment)

Return on investment measures what an investment returned relative to what it cost. It answers: for every dollar spent, how much profit came back?

\[ \text{ROI} = \frac{\text{gain from investment} - \text{cost of investment}}{\text{cost of investment}} \times 100\% \]

For a campaign, gain should be the incremental contribution (incremental revenue minus the variable costs of producing it), measured before the campaign cost is subtracted, with the cost scope stated to avoid double counting. Using \$15,000 incremental revenue and \$10,000 spend gives a naive revenue-based 50%; it is not profit ROI unless the revenue has no other associated cost. The examples below show the correction.

Two words in that formula carry the weight — “gain” and “incremental” — and the shape of the ratio carries a third problem.

Gain, incremental, and the shape of a ratio

Revenue is not gain

Start with the worked example: \$15,000 of incremental revenue for \$10,000 of spend. ROAS divides the revenue by the spend, and the revenue-based ROI subtracts the cost first. Then let the gross margin vary, so that the gain is the gross profit instead of the revenue.

import numpy as np

rev, cost = 15_000.0, 10_000.0
print(f"ROI on revenue = ({rev:,.0f} - {cost:,.0f}) / {cost:,.0f} = {(rev - cost) / cost:.0%}")
print(f"ROAS = {rev:,.0f} / {cost:,.0f} = {rev / cost:.2f}")

for gm in (1.00, 0.70, 0.50, 0.40, 0.25):
    gp = rev * gm
    print(f"gross margin {gm:>4.0%}: gross profit {gp:>6,.0f}, ROI on gross profit {(gp - cost) / cost:>4.0%}")
ROI on revenue = (15,000 - 10,000) / 10,000 = 50%
ROAS = 15,000 / 10,000 = 1.50
gross margin 100%: gross profit 15,000, ROI on gross profit  50%
gross margin  70%: gross profit 10,500, ROI on gross profit   5%
gross margin  50%: gross profit  7,500, ROI on gross profit -25%
gross margin  40%: gross profit  6,000, ROI on gross profit -40%
gross margin  25%: gross profit  3,750, ROI on gross profit -62%

The first is that revenue is not gain. Putting incremental revenue in the numerator treats every dollar of sales as though it were profit, and one correction, when it captures all relevant variable costs, is the gross margin. The same campaign reports 50% on revenue and 5% at a 70% margin, and a loss of 62% at 25%. For a software business the two are close; for anything with real cost of goods they can differ even in sign. Related measures split on exactly this point: ROAS is revenue over ad spend and is deliberately a revenue ratio, so a ROAS of 1.50 and an ROI of 50% are not the same statement.

Incrementality

Now a campaign that cost \$25,000 and was followed by 3,000 orders worth \$40 each at a 40% gross margin. The question is how many of those orders the campaign caused, so the code compares counting every buyer with assuming that 60% or 85% of them would have bought anyway.

orders, order_value, gross_margin, spend = 3_000, 40.0, 0.40, 25_000.0

anyway = np.array([0.0, 0.60, 0.85])          # share who would have bought anyway
incremental = orders * (1 - anyway)
gross_profit = incremental * order_value * gross_margin
roi = (gross_profit - spend) / spend
for a, inc, gp, r in zip(anyway, incremental, gross_profit, roi):
    print(f"{a:>3.0%} would have bought anyway: {inc:>5,.0f} incremental orders, "
          f"gross profit {gp:>6,.0f}, ROI {r:>4.0%}")
 0% would have bought anyway: 3,000 incremental orders, gross profit 48,000, ROI  92%
60% would have bought anyway: 1,200 incremental orders, gross profit 19,200, ROI -23%
85% would have bought anyway:   450 incremental orders, gross profit  7,200, ROI -71%

The second is incrementality. The same 3,000 orders support a 92% return if every buyer is counted and a 71% loss if 85% of them would have bought anyway. The anyway share above is the sure things, the customers who buy regardless of the campaign. Only the persuadable customers, who buy because of it, add incremental orders, and the lost causes never buy either way. Uplift modeling aims spend at the persuadable group, where the incremental benefit exceeds the treatment cost. Counting observed orders alone does not identify orders caused by the campaign. An incrementality estimate needs an evaluation design and identification assumptions appropriate to that causal question.

The shape of a ratio

Finally, three projects of different sizes, each with the gross profit it returns.

names = ["small tweak", "campaign", "new channel"]
cost = np.array([8_000, 120_000, 600_000])
gross_profit = np.array([26_000, 210_000, 840_000])

roi = (gross_profit - cost) / cost
for name, c, g, r in zip(names, cost, gross_profit, roi):
    print(f"{name:<12} cost {c:>9,}, gross profit {g:>9,}, ROI {r:>4.0%}, profit made {g - c:>8,}")
small tweak  cost     8,000, gross profit    26,000, ROI 225%, profit made   18,000
campaign     cost   120,000, gross profit   210,000, ROI  75%, profit made   90,000
new channel  cost   600,000, gross profit   840,000, ROI  40%, profit made  240,000

The third is structural. ROI is a ratio, so it rewards small denominators: a \$8,000 project returning 225% makes \$18,000, and a \$600,000 project returning 40% makes \$240,000. A team told to maximize ROI will choose the first. Ranking by ROI can allocate a budget for divisible investments with comparable horizons and risks, but need not maximize profit for indivisible projects. With a budget of 10, a cost-6 project returning net 6 has higher ROI than each of two cost-5 projects returning net 4, yet the pair returns net 8. Optimize the feasible portfolio, not the ratio alone.

Variants and use

Marketing ROI is the ratio with incremental contribution as the gain and the stated campaign costs as the cost. Return on ad spend is revenue over ad cost, with the revenue caveat above. Risk-adjusted ROI accounts for the spread of outcomes rather than the expectation alone. Time-adjusted versions — net present value, internal rate of return — discount future returns, which matters whenever the payback runs past a few months.

What it is for is comparison and accountability: ranking projects against each other, allocating budget toward the ones that return most per dollar, and showing after the fact whether an action created value. All three uses depend on the numerator being measured the same way across the things being compared, which is the practical reason to fix the definition before the comparison rather than after.

References


Discover more from Insightful Data Lab

Subscribe to get the latest posts sent to your email.

Similar Posts

Questions, corrections, or additional insights?

This site uses Akismet to reduce spam. Learn how your comment data is processed.