Most ROI calculators end in a pitch. The number is a black box. I wanted the opposite: a calculator that shows the formula next to the result, so a reader can check the math, and a crawler can read a worked example without running the form.
These are seven free planning calculators for service businesses. No signup. Nothing is saved unless someone emails themselves the estimate. They live at keencraft.tech/tools.
Pure functions for the math
Each formula lives in a small function, separate from the UI. The missed-call one is the whole model:
export function missedCallRevenue(input: MissedCallInput) { const missed = input.callsPerMonth * (input.missRate / 100); const bookings = missed * (input.bookableShare / 100) * (input.bookingRate / 100); const monthlyLeak = bookings * input.jobValue; const paybackMonths = monthlyLeak > 0 ? input.buildCost / monthlyLeak : null; return { missed, bookings, monthlyLeak, annualLeak: monthlyLeak * 12, paybackMonths, }; } The dental starting example is 400 calls a month, 20% unanswered, 40% of those could have booked, a 50% booking rate when the call is answered, and $1,200 for one booking. That is 80 missed calls, 16 bookings, and $19,200 a month. The same function feeds the page, the starting example, and the share image.
Presets
Industry presets are plain objects. Picking one fills the fields, and every input stays editable.
const dentalPreset = { callsPerMonth: "400", missRate: "20", bookableShare: "40", bookingRate: "50", jobValue: "1200", buildCost: "8000", }; Dental, HVAC and trades, med spa, legal intake, fitness, and parking sit beside it. A preset is a starting point, not a locked scenario.
A worked example in the HTML
The formula, the starting numbers, and the FAQs are rendered on the server. The form is a client component on top of that. A crawler that does not run JavaScript still sees the dental example and the formula.
Shareable result links
Changing an input writes only the fields that differ from the defaults into the query string. history.replaceState updates the address bar without a new history entry. Opening that URL reads the same keys back.
const params = new URLSearchParams(); for (const [key, value] of Object.entries(values)) { if (value !== defaults[key] && value !== "") params.set(key, value); } const query = params.toString(); const url = query ? `${path}?${query}` : path; window.history.replaceState(null, "", url); Copy result link builds the same URL from the current values.
Dynamic Open Graph images
Each calculator has an opengraph-image.tsx route. It calls sharePreview(slug), the same helper as the page, so the card shows the starting example. The agency margin card is labeled monthly gross profit on that example. Next.js renders the card with ImageResponse at 1200 by 630.
export const runtime = "nodejs"; export const size = { width: 1200, height: 630 }; export const contentType = "image/png"; export default async function Image({ params, }: { params: Promise<{ slug: string }>; }) { const { slug } = await params; const preview = sharePreview(slug); return new ImageResponse( ( <div style={{ display: "flex", backgroundColor: "#07111f", color: "#fff", width: "100%", height: "100%", }} > <div style={{ display: "flex", fontSize: 84 }}>{preview.value}</div> </div> ), { ...size }, ); } Every element in that tree sets display: "flex". The image renderer lays elements out with flex, and a node without it comes out blank.
FAQ and related links
Each tool page lists its formula, an FAQ, and links to the matching article. The agency margin page links to the white-label article. The missed-call page links to the dental article. Those links are in the HTML, not only inside the form.
The seven calculators
- Missed-call revenue: unanswered calls, times the share that could have booked, times the booking rate, times the value of one booking.
- AI receptionist cost comparison: live answering, a SaaS receptionist, and a custom build over three years.
- Agency voice AI margin: gross margin on reselling, and when owning the stack beats the platform fee.
- Fixed-price vs hourly: what an overrun does to an hourly quote.
- Automation ROI: payback on an implementation from hours saved.
- Integration cost: a planning range for connecting two systems.
- Ad-to-booking leak: ad spend that becomes a call and never a booked job.
A small embed
The missed-call calculator also exists as a CodePen, with the same dental defaults.
The full version, with industry presets, is the missed-call revenue calculator.
