DocsRecipes

Recipes

Customer acquisition and unit economics

4 min readReviewed July 2026

Unit economics connect the cost of acquiring a customer with the contribution that customer produces over time. The arithmetic is simple; the definitions are not.

Use GraphJSON for decision-oriented acquisition and cohort analysis. Keep ad platform invoices, payroll allocations, accounting revenue, and cost-of-service models in their authoritative systems. Send governed snapshots or normalized facts into GraphJSON and reconcile them.

This recipe connects web attribution, revenue analytics, and retention curves.

Define the economic grain#

Choose one customer entity:

  • account or logo for B2B
  • purchaser or household for commerce
  • subscription for a subscription product

Do not calculate spend per acquired user and compare it with revenue per account. Document merges, subsidiaries, multi-workspace customers, and reactivations.

Then define the cohort date:

  • account creation
  • qualified lead
  • first paid date
  • first order
  • contract start

“CAC for July” is ambiguous until both the spend period and acquisition event are explicit.

Separate spend from attribution#

Spend is a cost fact. Attribution is a model that assigns customer outcomes to touches. Keep them distinct.

Publish a governed spend snapshot:

{
  "event": "acquisition_spend_snapshot",
  "spend_id": "google_search:2026-07-25:usd:v2",
  "channel": "paid_search",
  "source": "google",
  "campaign_id": "cmp_91",
  "window_start": "2026-07-25T00:00:00Z",
  "window_end": "2026-07-26T00:00:00Z",
  "spend_amount_minor": 482500,
  "currency": "usd",
  "cost_scope": "media_only",
  "definition_version": 2,
  "data_complete_through": "2026-07-26T09:00:00Z"
}

Specify whether spend includes agency fees, creative, sales labor, promotions, and allocated overhead. Media CAC and fully loaded CAC are different metrics.

Emit a durable acquisition outcome#

When the customer reaches the governed acquisition point:

{
  "event": "customer_acquired",
  "account_id": "acct_7",
  "acquired_at": "2026-07-25T19:30:00Z",
  "acquisition_definition": "first_paid_account",
  "attribution_model": "first_eligible_touch",
  "attributed_channel": "paid_search",
  "attributed_source": "google",
  "attributed_campaign_id": "cmp_91",
  "attribution_version": 3
}

Preserve raw eligible touch facts separately so a future model can be compared. Do not rewrite the same historical event when attribution changes; publish a new attribution version.

Calculate CAC with compatible scopes#

CAC
  = eligible acquisition cost in a period
  / acquired customers attributed to that same scope

If sales costs are included, the population may need to be sales-assisted customers. If campaign spend is in the numerator, customers must be assigned under a compatible campaign rule.

Query media CAC by channel:

WITH spend AS (
  SELECT
    JSONExtractString(json, 'channel') AS channel,
    JSONExtractString(json, 'currency') AS currency,
    sum(JSONExtractInt(json, 'spend_amount_minor')) AS spend_minor
  FROM growth_costs
  WHERE
    JSONExtractString(json, 'event') = 'acquisition_spend_snapshot'
    AND toDateTime(timestamp) >= toDateTime('2026-07-01 00:00:00')
    AND toDateTime(timestamp) < toDateTime('2026-08-01 00:00:00')
  GROUP BY channel, currency
),
customers AS (
  SELECT
    JSONExtractString(json, 'attributed_channel') AS channel,
    uniqExact(JSONExtractString(json, 'account_id')) AS acquired_accounts
  FROM customer_lifecycle
  WHERE
    JSONExtractString(json, 'event') = 'customer_acquired'
    AND JSONExtractInt(json, 'attribution_version') = 3
    AND toDateTime(timestamp) >= toDateTime('2026-07-01 00:00:00')
    AND toDateTime(timestamp) < toDateTime('2026-08-01 00:00:00')
  GROUP BY channel
)
SELECT
  spend.channel,
  spend.currency,
  spend.spend_minor,
  customers.acquired_accounts,
  spend.spend_minor / nullIf(customers.acquired_accounts, 0) AS cac_minor
FROM spend
LEFT JOIN customers USING channel

Do not sum currencies. Normalize under a reviewed FX policy or report separately.

Use contribution margin, not just revenue#

Customer contribution should match the business model:

contribution
  = recognized or collected value
  − refunds
  − payment fees
  − variable infrastructure
  − customer-specific service costs
  − other included variable costs

Document what is included. Gross revenue can make low-margin channels appear healthy. Finance should own the authoritative cost allocation and publish versioned account-period contribution snapshots when the calculation is complex.

Choose an LTV method#

Three common approaches:

Realized cohort contribution#

Sum actual contribution by months since acquisition. This is transparent but immature for newer cohorts.

Retention-curve model#

Estimate future contribution from survival and margin assumptions. This is model-dependent and should expose its horizon, discounting, and tail behavior.

Contracted value#

Useful in some B2B settings, but contracted, billed, collected, and realized value are not interchangeable.

Call a forecast “modeled LTV,” not “LTV,” and store:

method
model version
training or observation cutoff
horizon
discount rate
margin definition
uncertainty range

Calculate payback by acquisition cohort#

Payback is the first mature period where cumulative contribution per acquired customer equals or exceeds CAC:

cumulative contribution per acquired account
  >= cohort CAC

Keep accounts that churned at zero future contribution; excluding them biases the result. Do not compare a three-month-old cohort with a twelve-month payback target as if it failed. Label immature cells and show the number still observed.

Segment carefully#

Useful dimensions include channel, campaign group, acquisition month, region, plan, sales motion, and customer size. Before acting:

  • require a minimum customer count
  • show spend and customer denominators
  • compare cohort age
  • watch for one large account dominating contribution
  • distinguish organic customers from unattributed customers
  • preserve attribution version

A cheap channel can attract customers with lower retention. Evaluate CAC, activation, retention, contribution, and payback together.

Build the operating dashboard#

Include:

  1. spend and acquired customers by compatible scope
  2. CAC with denominators and cost definition
  3. activation and early value by acquisition cohort
  4. retained accounts and contribution by cohort age
  5. realized and modeled LTV, clearly separated
  6. payback curve and mature-cohort attainment
  7. unattributed share and source freshness
  8. reconciliation status

Do not put one blended LTV:CAC ratio at the top without showing its components and maturity.

Reconcile and govern#

For every closed period compare:

  • spend snapshots with platform billing and finance
  • acquired account IDs with CRM or billing
  • attribution coverage with eligible session data
  • revenue and refunds with the billing authority
  • contribution snapshots with the approved cost model
  • cohort entity counts across all calculations

Version changes to attribution, CAC scope, contribution margin, or LTV model. Run old and new definitions over an overlap window before replacing a series.

Launch checklist#

  • Spend, acquisition, and value use one compatible customer grain.
  • Media and fully loaded acquisition costs are labeled separately.
  • Attribution facts and attribution models remain distinguishable.
  • Currency conversion uses a reviewed policy.
  • Contribution scope is approved by finance.
  • Realized and modeled LTV are not mixed.
  • Payback keeps churned accounts and labels immature cohorts.
  • Segment views show spend, customer count, and cohort age.
  • Material definition changes create new versions.
  • Closed periods reconcile with cost, CRM, billing, and finance sources.
Need a hand?

Tell us what you’re building and we’ll point you in the right direction.

Contact support