Every chatbot pitch dies the same way: someone in finance asks "what's the payback period?" and the room goes quiet.
Most teams answer with vibes. "It'll save time." "Customers will love it." That's not a business case, it's a wish. Here's the actual math, plus a script you can run before writing a single line of bot logic.
The core formula
Chatbot ROI is not complicated. It's deflection times cost per contact, minus what the thing costs to build and run.
Monthly Savings = (Tickets/mo × Deflection Rate × Cost per Ticket) - Monthly Running Cost
Payback Months = Build Cost / Monthly Savings
Annual ROI % = ((Monthly Savings × 12) - Build Cost) / Build Cost × 100
The entire debate lives in four numbers: how many tickets you get, what fraction a bot can actually close, what each ticket costs you today, and what the bot costs to run. Get honest about those and the rest is arithmetic.
The numbers people get wrong
Deflection rate
This is the killer variable, and it's where optimism goes to inflate spreadsheets. Vendors love quoting 80%. Reality for a well-scoped support bot on FAQ-heavy traffic is closer to 30-50% in year one.
Deflection means the bot fully resolved the issue without a human touching it. A bot that answers then escalates deflected nothing. Measure it as: conversations closed by bot / total conversations.
Cost per ticket
Don't use salary alone. Fully loaded cost includes benefits, tooling, management overhead, and idle time. A common realistic figure for a live-chat or email agent is $5-$15 per resolved contact depending on complexity and geography.
Running cost
Token costs, vector DB hosting, the platform fee, and the human hours to maintain content. People forget that last one. A bot with a stale knowledge base deflects less every month.
The calculator
Here's the whole thing as a script. Feed it your numbers and it tells you if the project survives contact with a CFO.
def chatbot_roi(
monthly_tickets: int,
deflection_rate: float, # 0.0 - 1.0
cost_per_ticket: float, # fully loaded USD
build_cost: float, # one-time
monthly_running_cost: float, # tokens + hosting + upkeep
):
deflected = monthly_tickets * deflection_rate
gross_savings = deflected * cost_per_ticket
net_monthly = gross_savings - monthly_running_cost
if net_monthly <= 0:
return {"verdict": "Do not build", "net_monthly": round(net_monthly, 2)}
payback_months = build_cost / net_monthly
annual_roi = ((net_monthly * 12) - build_cost) / build_cost * 100
return {
"tickets_deflected": round(deflected),
"net_monthly_savings": round(net_monthly, 2),
"payback_months": round(payback_months, 1),
"annual_roi_pct": round(annual_roi, 1),
"verdict": "Build it" if payback_months < 12 else "Marginal",
}
print(chatbot_roi(
monthly_tickets=4000,
deflection_rate=0.40,
cost_per_ticket=8.0,
build_cost=25000,
monthly_running_cost=1200,
))
Output:
{'tickets_deflected': 1600, 'net_monthly_savings': 11600.0,
'payback_months': 2.2, 'annual_roi_pct': 456.8, 'verdict': 'Build it'}
A 2.2 month payback is a strong case. But watch what happens when you dial deflection down to a more conservative 25% and running cost up to $2,000:
{'tickets_deflected': 1000, 'net_monthly_savings': 6000.0,
'payback_months': 4.2, 'annual_roi_pct': 188.0, 'verdict': 'Build it'}
Still good. The point isn't the happy number, it's stress-testing your assumptions until the case holds even when you're pessimistic.
Run the pessimist's version
Never present a single scenario. Present three.
scenarios = {
"conservative": dict(deflection_rate=0.25, monthly_running_cost=2000),
"expected": dict(deflection_rate=0.40, monthly_running_cost=1200),
"aggressive": dict(deflection_rate=0.55, monthly_running_cost=1000),
}
base = dict(monthly_tickets=4000, cost_per_ticket=8.0, build_cost=25000)
for name, override in scenarios.items():
result = chatbot_roi(**{**base, **override})
print(name, result["payback_months"], "months")
If your conservative case still pays back inside a year, you have a real project. If only the aggressive case works, you're gambling.
What the formula won't tell you
Three things live outside the spreadsheet but matter:
- Response time. A bot answers instantly at 2am. That deflection has a customer-satisfaction value the ticket-cost math ignores.
- Agent focus. Removing repetitive tickets lets your team handle the hard 40% better. Hard to quantify, real to feel.
- Scaling headroom. When volume doubles, headcount doesn't have to. The bot absorbs the spike at near-zero marginal cost.
Don't stuff these into the ROI number to inflate it. List them as upside, keep the hard math clean.
The one metric to instrument first
Before you build, tag your existing tickets by category. The share that are repetitive, low-complexity, and answerable from your docs is your realistic deflection ceiling. If that's only 20% of volume, no model tuning saves the business case.
Prove the number before you write the code. The bot is the easy part. The math is what gets it funded.
Originally published at getmichaelai.com
Top comments (0)