Organic CAC (Customer Acquisition Cost)

Organic CAC is the average cost of acquiring a customer from non-paid channels: organic search and SEO, referrals and word of mouth, direct traffic driven by brand awareness, unpaid social posts, and email to lists the company already owns. Direct advertising is excluded by definition.

\[ \text{organic CAC} = \frac{\text{organic marketing spend}}{\text{customers acquired from organic channels}} \]

Organic spend here means the salaries of the content and SEO team, the tools they use, hosting, PR and similar. Spend \$30,000 in a quarter and attribute 1,000 customers to organic sources, and organic CAC is \$30.

It is usually introduced with two claims: that it shows the long-run payoff of content, brand, SEO and referrals, and that it is typically lower than paid CAC but slower to scale. The second claim deserves scrutiny, because two features of the metric can distort it for reasons unrelated to efficiency: dividing one period’s spend by the same period’s customers, and the choice of which costs are counted.

Same-period division and the lag

The following hypothetical model fixes eventual acquisition cost at 30 per customer. Content spent in a month brings customers over eight months, starting in the month of the spend, with the shape in lag, and every 30 dollars of spend eventually produces one customer, in every month. Spend is 10,000 a month for 12 months, 30,000 for the next 6 months, and 10,000 again for 8 months. Changing spend under these assumptions changes the same-period ratio without changing that cohort cost.

import numpy as np

lag = np.array([0.05, 0.10, 0.18, 0.22, 0.20, 0.13, 0.08, 0.04])
lag = lag / lag.sum()      # share of a month's spend that arrives 0, 1, ... 7 months later
per_dollar = 1 / 30.0      # eventual customers per dollar of spend

spend = np.r_[np.full(12, 10_000), np.full(6, 30_000), np.full(8, 10_000)]
arrivals = np.zeros(len(spend) + len(lag))
for t, s in enumerate(spend):
    arrivals[t:t + len(lag)] += s * per_dollar * lag

print(f"total spend {spend.sum():,}, total customers {arrivals.sum():,.1f}, "
      f"cost per customer {spend.sum() / arrivals.sum():.2f}")
total spend 380,000, total customers 12,666.7, cost per customer 30.00

Over the whole window the cost per customer is exactly 30.00, so any other number a month reports is an artifact of dividing one period’s spend by another period’s arrivals. The next lines print the monthly ratio and its error against 30.00, starting with the months around the tripling.

def show(months):
    for m in months:
        t = m - 1
        cac = spend[t] / arrivals[t]
        print(f"month {m:>2}  spend {spend[t]:>6,}  customers {arrivals[t]:>6.1f}  "
              f"same-period CAC {cac:>6.2f}  error {cac - 30:>+7.2f}")

show([12, 13, 14, 17, 18])
month 12  spend 10,000  customers  333.3  same-period CAC  30.00  error   +0.00
month 13  spend 30,000  customers  366.7  same-period CAC  81.82  error  +51.82
month 14  spend 30,000  customers  433.3  same-period CAC  69.23  error  +39.23
month 17  spend 30,000  customers  833.3  same-period CAC  36.00  error   +6.00
month 18  spend 30,000  customers  920.0  same-period CAC  32.61  error   +2.61

While spend is flat (month 12) the ratio reads 30.00. When spend triples in month 13, only the first 5% of the new spend’s customers arrive that month, so the denominator is still mostly customers from the earlier 10,000 budget, and reported organic CAC jumps to \$81.82 against a true \$30.00. The overstatement shrinks as the delayed customers arrive (36.00 in month 17, 32.61 in month 18) but has not closed by the last month at the higher budget.

The cut in month 19 produces the mirror image.

show([19, 20, 22, 23, 26])
month 19  spend 10,000  customers  940.0  same-period CAC  10.64  error  -19.36
month 20  spend 10,000  customers  900.0  same-period CAC  11.11  error  -18.89
month 22  spend 10,000  customers  633.3  same-period CAC  15.79  error  -14.21
month 23  spend 10,000  customers  500.0  same-period CAC  20.00  error  -10.00
month 26  spend 10,000  customers  333.3  same-period CAC  30.00  error   +0.00

Spend falls to 10,000 in month 19, but the customers produced by the earlier 30,000 months are still arriving, so the ratio drops to \$10.64 and recovers to 30.00 only in month 26, once the last of those customers has arrived. Under these assumptions the same-period ratio overstates cohort cost while spend is rising, understates it while spend is falling, and equals it only after spend has been flat for the full eight-month lag. The metric moves in the wrong direction at precisely the moments someone is deciding whether to invest more or less — a budget increase looks immediately wasteful and a cut looks immediately smart.

The fix is cohort matching: attribute spend to the customers it eventually produced rather than to the customers who happened to arrive alongside it. That is harder than it sounds for organic, because the lag distribution has to be estimated, and a same-period ratio should be read as that period’s spend per arrival rather than assumed to equal eventual cohort cost.

The cost base

The second distortion comes from which costs are counted. Consider one month in which the paid and organic channels have the following costs and customers. Paid costs here cover media and agency fees as well as the paid team’s salaries; organic costs are the content team’s salaries and tools.

ChannelMediaAgency feesTeam salariesToolsCustomers
Paid50,00014,00045,0000400
Organic0024,0006,0001,000

A comparison in which paid CAC counts media and agency fees but not the paid team’s salaries, while organic CAC counts the content team’s salaries and tools, is asymmetric. The code computes that comparison and two symmetric alternatives: salaries counted on both sides, and salaries counted on neither.

paid_media, paid_agency, paid_salary = 50_000, 14_000, 45_000
org_tools, org_salary = 6_000, 24_000
paid_n, org_n = 400, 1_000

bases = {
    "asymmetric (assumed)": ((paid_media + paid_agency) / paid_n,
                             (org_tools + org_salary) / org_n),
    "salaries in both":     ((paid_media + paid_agency + paid_salary) / paid_n,
                             (org_tools + org_salary) / org_n),
    "salaries in neither":  ((paid_media + paid_agency) / paid_n,
                             org_tools / org_n),
}
for name, (paid, org) in bases.items():
    print(f"{name:<22} paid {paid:>7.2f}  organic {org:>6.2f}  paid / organic {paid / org:>5.2f}x")
asymmetric (assumed)   paid  160.00  organic  30.00  paid / organic  5.33x
salaries in both       paid  272.50  organic  30.00  paid / organic  9.08x
salaries in neither    paid  160.00  organic   6.00  paid / organic 26.67x

In this example the asymmetric comparison produces the smallest of the three gaps: 5.33× as assumed, 9.08× with salaries counted on both sides, 26.67× with salaries on neither. Making the bases symmetric raises organic’s apparent advantage to about 1.7 times the asymmetric figure with salaries on both sides, and to 5 times with salaries on neither. The direction survives in this example and the magnitude does not, which is the general lesson — the paid-versus-organic ratio is a statement about accounting conventions as much as about marketing, and it means little without the cost base attached.

What it is genuinely good for

Organic investment is the part of acquisition that compounds. A piece of content that ranks keeps arriving customers after the spending stops, which is exactly what makes the same-period division misleading and also what makes the channel worth having. Measured over a long enough window, a low organic CAC is real and it is the thing that makes a high paid CAC survivable.

The limits are the mirror image. Attribution is hardest here, because organic journeys are long and multi-touch and a customer who searched the brand name may have been sent by an ad weeks earlier. It scales slowly, so it cannot be the answer to a growth target with a date on it. And it looks cheap partly because some of its costs sit in other budgets — brand, PR, product — that no one allocates to it.

Three habits make it usable. Match spend to cohorts rather than to calendar months, and say which window was used. Use the same cost base as the paid figure whenever the two are compared. And read it alongside blended CAC, which is where the paid-organic mix shows up as a single number — organic CAC explains why blended CAC moves when the mix does.

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.