← Back to Blog
Content StrategyContentStrategyQuantitativeMarketingB2BMarketing

A Content Marketing ROI Model You Can Actually Run

A full payback model for a content programme — cost inputs, ranking probability, traffic and conversion assumptions, plus a sensitivity table and runnable Python. Every input is labelled an assumption.

SPSantosh Paudel· September 6, 2026· 11 min read
Table of contents

Content marketing ROI is a payback model, not a percentage. You need six inputs: cost per published post, posts per month, the probability a post ever ranks, monthly clicks if it does, visitor-to-client conversion, and gross profit per client. Multiply the last four to get monthly profit per cohort of posts, divide cumulative cost by it, and the payback month falls out. On the assumptions I use below, an agency spending $3,160 a month breaks even in month 22. Change the ranking probability from 6% to 2% and it never breaks even inside three years. That gap is the whole point of building the model.

Below is the model itself: a table of inputs, runnable Python, a month-by-month payback path, and a sensitivity grid. Then my own Search Console data as the honest counter-example.

The inputs, and why each one is an assumption

Every number here is an assumption you should replace with your own. I have marked where a published study gives you a starting point and where you are guessing.

InputValue usedWhere it comes from
Posts per month8Assumption — your publishing rate
Writer cost per post$250Assumption — freelance mid-market rate
Editor cost per post$80Assumption
Distribution cost per post$40Assumption — promotion, not production
Tools per month$200Assumption — rank tracker, CMS, images
P(post reaches top 10)0.06Anchored on Ahrefs (2025); see below
Clicks per ranking post per month60Assumption — depends entirely on keyword volume
Visitor to lead2%Assumption
Lead to client15%Assumption
Gross profit per client$6,000Assumption — margin, not revenue
Ramp: months before a post earns6Assumption

The ranking probability is the input people fudge hardest, so it is worth anchoring. Ahrefs published a study in May 2025 tracking 1 million URLs first crawled in September 2023: 1.74% of newly published pages ranked in the top 10 for any keyword within a year. Filtering a second sample of 2 million URLs to non-empty English content lifted that to 6.11%. Their earlier index-wide study, from December 2023, found 96.55% of 14 billion pages get zero traffic from Google. Six percent is the optimistic end of a defensible range for competent English content on a domain with some authority. If you are putting 30% into your model, you are not modelling, you are hoping.

The clicks-per-ranking-post number deserves a haircut too. Pew Research Center tracked 68,879 Google searches from 900 US adults in March 2025 and found users clicked a traditional search result on 8% of visits where an AI summary appeared, versus 15% where none did. AI summaries showed on 18% of searches in that sample. Rank one, get half the clicks you used to on the queries that trigger a summary.

The model, as code you can run

Python standard library, no dependencies. Edit the dataclass, run it.

from dataclasses import dataclass

@dataclass
class Assumptions:
    posts_per_month: float = 8
    writer_cost_per_post: float = 250
    editor_cost_per_post: float = 80
    distribution_cost_per_post: float = 40
    tools_per_month: float = 200
    p_rank: float = 0.06              # P(a post reaches top 10)
    clicks_per_ranking_post: float = 60   # per month, once ranked
    visitor_to_lead: float = 0.02
    lead_to_client: float = 0.15
    gross_profit_per_client: float = 6000
    ramp_months: int = 6              # months before a post earns anything

def monthly_cost(a):
    per_post = (a.writer_cost_per_post + a.editor_cost_per_post
                + a.distribution_cost_per_post)
    return a.posts_per_month * per_post + a.tools_per_month

def cohort_monthly_profit(a):
    """Steady-state monthly gross profit from one month's worth of posts."""
    ranking = a.posts_per_month * a.p_rank
    clicks = ranking * a.clicks_per_ranking_post
    clients = clicks * a.visitor_to_lead * a.lead_to_client
    return clients * a.gross_profit_per_client

def run(a, horizon=36):
    cost = profit = 0.0
    rows = []
    per_cohort = cohort_monthly_profit(a)
    for m in range(1, horizon + 1):
        cost += monthly_cost(a)
        mature_cohorts = max(0, m - a.ramp_months)
        profit += mature_cohorts * per_cohort
        rows.append((m, cost, profit, profit - cost))
    return rows

def payback_month(a, horizon=36):
    for m, _cost, _profit, net in run(a, horizon):
        if net >= 0:
            return m
    return None

if __name__ == "__main__":
    a = Assumptions()
    assert round(monthly_cost(a)) == 3160
    assert round(cohort_monthly_profit(a), 2) == 518.40
    assert payback_month(a) == 22
    for m, cost, profit, net in run(a):
        if m % 6 == 0:
            print(f"month {m:2d}  cost {cost:9,.0f}  profit {profit:9,.0f}  net {net:9,.0f}")
    print("payback month:", payback_month(a))

Two structural choices matter more than any input value.

Cohorts, not a single blob

Each month's posts are their own cohort with their own ramp. Month 1's posts start earning in month 7; month 10's posts start earning in month 16. Models that treat content as one undifferentiated spend line hide the fact that you keep paying full price for cohorts that have not proved anything yet.

Gross profit, not revenue

gross_profit_per_client is margin after delivery cost. Agencies that model on revenue produce payback periods roughly three times too short, because a $6,000 retainer is not $6,000 of contribution. This is the same discipline as any expected-value calculation on a promotion — the number in the EV term has to be the number that actually reaches the bottom line.

What the payback path looks like

Monthly cost is $3,160. Each cohort of 8 posts produces 0.48 ranking pages, 28.8 clicks a month, 0.086 clients a month, and $518.40 of gross profit a month once mature.

MonthCumulative costCumulative profitNet
6$18,960$0−$18,960
12$37,920$10,886−$27,034
18$56,880$40,435−$16,445
21$66,360$62,208−$4,152
22$69,520$70,502+$982
24$75,840$88,646+$12,806
36$113,760$241,056+$127,296

The worst month is month 12, not month 1. That is the counter-intuitive result and it is the reason content programmes get cancelled: the maximum drawdown lands at exactly the point where someone asks for a year-one review. If you have not shown this curve to whoever approves the budget before you start, you will be defending the programme at its ugliest point with no context.

The sensitivity table is the actual deliverable

One payback number is a guess with a decimal point. The grid is what you present. Payback month, or "—" if the programme has not broken even by month 36:

P(rank top 10) →20 clicks/mo60 clicks/mo150 clicks/mo
2%25
4%2917
6%2214
10%331712
15%251410

Read the top-left quadrant. If your posts rank 2–4% of the time and pull 20–60 clicks a month when they do, there is no payback inside three years at any publishing volume — the model is linear in posts, so publishing twice as much scales cost and profit together and moves the payback month not at all.

That is the finding. Volume does not fix a bad clicks-per-post number. The only two inputs that move payback meaningfully are ranking probability and clicks per ranking page, and both of those are set by keyword selection, not by output. Choosing keywords with real volume and beatable competition is a different job from producing posts, and most content programmes only staff the second one. I wrote more about which measurements actually tell you this in the five SEO metrics that matter.

My own site is the counter-example

This is where I have to be honest about my own numbers, because they are the strongest argument for building the model before you spend the money.

Over 85 days to 3 September 2026, santoshpaudel.me recorded 4,553 impressions and 22 clicks — a 0.48% CTR across roughly 390 indexed URLs. Russia sent 1,320 impressions and zero clicks. The United States sent 970 impressions at an average position of 38.8, also zero clicks. Nepal sent 8 clicks from 74 impressions at position 9.2, a 10.8% CTR — which tells you the site converts impressions fine when it ranks, and almost never ranks.

Feed that into the model. 22 clicks in 85 days is 7.8 clicks a month across the entire corpus. At the same 2% and 15% conversion assumptions, that is 0.023 clients a month, or about $140 a month of gross profit against a corpus of 279 posts. At the $370 per post the model uses, that corpus represents $103,230 of production cost. payback_month() returns None at a 120-month horizon. The programme does not pay back this century.

Nothing was broken. Posts were published, indexed, and served 4,553 times. Execution was fine. The keyword selection was wrong, and the model would have told me at month 3 rather than month 30. The split inside my own data makes the mechanism obvious: posts about building things with Claude Code, Supabase and Vercel sit at positions 2.8–15.5; posts about generic "[industry] content marketing" sit at 46–81. Same author, same domain, same quarter. The variable is not effort. It is whether anything on the page could not have been written by anyone else.

That is a keyword-and-differentiation problem, and it is upstream of everything the ROI model measures. If you want the operational version of fixing it, that is what a content system is — and the honest timeline is in how long SEO actually takes.

What I could not find

I searched for a controlled study measuring content marketing payback periods — a real one, with a holdout group, comparing firms that published against matched firms that did not. I could not find one. Every "content marketing ROI" figure I checked traces back to a self-reported vendor survey with no control group, which is why there are no benchmark percentages anywhere in this post. If you know of a properly controlled study, send it to me and I will update this page with it.

That absence is itself the argument for modelling. Nobody can hand you an industry payback number, so you have to build your own from inputs you can defend and then watch which ones turn out wrong.

FAQ

How do you calculate ROI on content marketing?

Model it as payback, not a ratio. Cumulative cost is posts × cost per post + fixed tooling. Cumulative return is posts × P(rank) × clicks per ranking post × visitor-to-lead × lead-to-client × gross profit per client, delayed by a ramp period. The month where cumulative return crosses cumulative cost is your answer. A single ROI percentage hides the ramp and the drawdown, which are the two things that actually get programmes cancelled.

What is a realistic content marketing ROI for an agency?

On the assumptions in this post — 8 posts a month at $370 each, 6% ranking probability, 60 clicks a month per ranking post, $6,000 gross profit per client — payback lands at month 22 and month 36 shows a cumulative net of $127,296. Change ranking probability to 2% and there is no payback within 36 months. Publish the sensitivity grid alongside any single number you quote, or you are quoting a coin flip.

How long before content marketing pays for itself?

In this model, 22 months, with the deepest drawdown at month 12. That is consistent with Ahrefs' 2025 finding that only 1.74% of newly published pages reach the top 10 within a year at all — the payback problem is mostly a hit-rate problem, not a patience problem. If your programme is nine months old and losing money, the model says that is expected. If it is nine months old with a 0.5% CTR and average position near 40, like mine was, the model says stop.

Not if clicks per ranking post is the binding constraint. The model is linear in publishing volume — doubling posts doubles cost and profit and leaves the payback month unchanged. Only ranking probability and clicks per ranking page move payback, and both are decided by keyword selection before a word is written.

Want the model run against your own numbers instead of mine? Send me your publishing rate, cost per post and Search Console export, and I will tell you which input is killing your payback. See my services or get in touch.

Sources: Ahrefs, "How Long Does It Take to Rank in Google?" (May 2025); Ahrefs, "96.55% of Content Gets No Traffic From Google" (December 2023); Pew Research Center, "Google users are less likely to click on links when an AI summary appears" (July 2025). Search Console figures are my own, 85 days to 3 September 2026.

Free resource

Get the AI-SEO Content Checklist

A practical checklist for getting your own content cited by Google AI Overviews, ChatGPT, and Perplexity — not just ranked.

No spam. Unsubscribe anytime.

Browse all free guides →

Run this on your own numbers

Content ROI & Payback Calculator — free, no signup, runs in your browser.

Open the calculator →

Want to implement this with guidance?

Santosh helps founders turn insights like this into real systems.

SEO Content Strategy

External Resources

Further Reading & Tools

Related Posts

01
11 min
SocialMediaContentStrategy
TodayCase Study

8 Reels, 41,423 Views, $0 Spend: The Build Log

Eight reels for a B2B automation services company did 41,423 views and 18,732 reach in five days with no ad spend. Here is the full per-reel distribution, the audience data, and everything the numbers do not prove.

Read article
02
12 min
PaidMediaContentStrategy
TodayPaid Media

Hook Rate vs Hold Rate: What Actually Moves

Across three video creatives in one Meta ad account, hook rate spanned 1.22x. Hold rate spanned 2.65x as reported, and 2.18x once the hook stage is divided back out. The funnel arithmetic, the counterexample, and a diagnostic table.

Read article
03
13 min
ContentStrategyContentMarketing
TodayContent Strategy

Content hit rate: how many posts before it means anything

Half of a client's reels found distribution and half died. I turned that into a planning model, with runnable Python, that answers how many posts a month you need before the number stops being noise.

Read article