Your Revenue Per Job Is a Vanity Metric — Track This Instead
Your Revenue Per Job Is a Vanity Metric — Track This Instead
In 2019, I sat across a conference table at Atlantic Comfort Partners and opened the P&L of a 14-truck residential HVAC shop we were considering acquiring. The owner had been in business for eleven years. He tracked revenue per job monthly. The number looked healthy every single year.
He had also been losing money on every install for three years.
Not dramatically. The company had positive cash flow because installs collected at job completion and the checking account never went to zero. But the actual economics of the work — what it cost to put a system in a house versus what the shop recovered — had been underwater since 2016, quietly, while the revenue-per-job number kept moving in the right direction and providing exactly the kind of reassurance that prevents owners from looking harder.
Revenue per job is a vanity metric. It moves. It is not a scorecard.
The Number That Feels Like Progress
Revenue per job is sticky for the same reason gross revenue is sticky: it's visible, it's simple, and it goes up when the business feels like it's going up. If your average job revenue was $1,400 eighteen months ago and it's $1,850 now, that feels like progress.
What it doesn't tell you is what stuck.
This is the same confusion underneath most small-shop pricing problems — the markup-versus-margin error, one level upstream. Markup tells you what you added to cost. Margin tells you what you kept from revenue. Most contractors know the difference in the abstract and confuse them in practice. Revenue per job is the upstream version of that error. The number tells you what came in the door. It says nothing about what walked out behind it in the form of labor hours that ran long, truck time that never got attributed to a job record, or materials burden that got absorbed quietly into cost of goods.
The 2019 shop had revenue per job trending up because they were installing more two-stage and variable-capacity equipment. Higher-ticket installs, right. The problem was that the more complex equipment required longer installation time, more callbacks, and a materials cost increase the shop had not passed through fully. Revenue went up. Hours went up faster. Margin went down. The owner could not see it because he was watching the wrong number.
What Revenue Per Job Leaves Out
I think about cost the way I think about heat transfer. In psychrometrics — the math of air properties that pulled me into HVAC in the first place, sitting in a classroom at De Anza in 2007 — every variable in the system balance has to be fully accounted for. Miss one and the system doesn't balance. Ignore latent load in a Manual J and you'll find out in July when the house starts growing mold. Ignore a cost variable in job accounting and you'll find out when the checking account finally catches up to the P&L.
Job costing has four variables. Leave out any one of them and the number cannot tell you whether a job made money.
Fully burdened labor hours. Not the hours on the invoice. The hours the technician spent on the job, including troubleshooting time that didn't get documented as extra work and the return trip for the part that wasn't on the truck. Payroll burden — FICA, workers' comp, benefits — lands meaningfully above the wage. Most shops I work with are capturing the wage and estimating the burden, or not capturing it at all.
Materials cost with realistic burden. The invoice cost of parts is not the cost of parts. There's freight on will-call orders, restocking fees on returns, shrinkage, and the carrying cost of parts sitting in a truck or warehouse that someone financed. I've seen the gap between invoice cost and actual landed cost run several percent in shop after shop. That gap is real and it shows up somewhere — usually in a margin that looks fine until you look closely.
Drive time. This is the one that gets me every time. Drive time between stops routinely goes unattributed to any job record, which means every job looks slightly more profitable than it was because those hours sit in total labor cost but are assigned to no revenue. Truck operating cost — commercial auto premiums, fuel at actual MPG on actual routes, maintenance reserves — disappears into overhead when it should be attached to jobs. If you're using the IRS standard mileage rate for management accounting, you're using a tax convenience, not a business tool. The right number varies dramatically by market. I've worked with shops where it ran under $30 per hour and others in high-traffic metros where it was pushing $60. Run your own.
Overhead allocation per job. The shop doesn't stop costing money when a truck is in a driveway. The office lease, dispatcher wages, software subscriptions, health insurance, liability coverage — all of that has to land somewhere. Without a consistent overhead allocation per job, you're calculating gross profit before you've charged the job for the building it operates out of.
The Metric That Actually Predicts Business Health
The number that answers the real question is gross profit dollars per billable hour.
A brief definition: gross profit dollars is the absolute dollar amount left after cost of goods sold — what the shop keeps before overhead. Gross margin is that figure expressed as a percentage of revenue. I use gross profit dollars rather than the percentage because percentages hide volume. A job with 60% gross margin that takes four hours produces less value than a job with 50% gross margin that takes two. The dollar-per-hour figure collapses that into something you can actually use.
Which brings me to the flat-rate pricing books. I've written about this before: those books are built to produce predictable revenue per ticket, not predictable margin per ticket. The vendors — and if you've been to any of the major industry trade events you know exactly which ones — are not optimizing for your margin. If your overhead is higher than the shop the book was built around (and in a high-cost metro, it almost certainly is), every job priced from that book is priced from an assumption that doesn't apply to your business. You end up with predictable revenue and unpredictable profit. That's the wrong direction.
Pricing from a flat-rate book without your own cost-of-doing-business calculation underneath it means you're pricing from someone else's overhead assumptions. That shop is not you.
How to Build the Calculation
After I left Atlantic Comfort Partners in 2021, I started working with independent shops, mostly under 25 trucks. Early in that work I took on a shop in the mid-Atlantic — six trucks, residential service and replacement — whose software was tracking revenue and parts cost but not attaching technician hours or drive time at the job level. Everything else was reasonably functional. They had a dispatcher, a price book, and they were collecting on time. The job records were just incomplete.
The owner thought his best technician was his most profitable. By revenue per job, that was true. The tech was fast, he sold well, his average ticket led the shop.
When I went back through three months of records and manually attached drive time and actual hours to each job, the picture changed. That technician's gross profit per billable hour came in well below the second technician on the team. The reason wasn't bad work. He was running long on diagnostics — real troubleshooting time that wasn't captured — and the jobs weren't billing for it. His tickets were high. His hours were higher, and nobody was flagging it.
The second technician had a lower average ticket. She also had clean job records, consistent diagnostic times, and drive routes that made geographic sense. Per hour of time invested, she was building the business.
My cost-of-doing-business template starts with annual fully burdened field labor cost per technician: wage, payroll taxes, workers' comp, benefits, tool allowance. It adds vehicle operating cost per hour at actual rates, not IRS rates. It allocates overhead per truck based on total overhead divided by field units. Then it divides the total by realistic billable hours per year.
That last number is where most shops are optimistic. Not 2,080. When you back out vacation, sick time, training days, callbacks that don't bill, and shop time that generates no revenue, billable hours per technician drop considerably. I've worked with shops budgeting 1,900 and finding out the hard way. Run your own number; don't borrow a default.
Why Your Software Isn't Fixing This Automatically
The job costing capability in most modern platforms is real. ServiceTitan's reporting suite is genuinely good — but it takes training to use, and in most of the shops I've worked with running that platform, the reports exist and nobody has built them out. Revenue and parts cost are captured reasonably well. Technician hours at the job level are inconsistently entered. Drive time is almost never attributed per job.
That's a people and process problem. The software doesn't create input discipline automatically.
I'll say the same thing about days sales outstanding, which is the average number of days between completing a job and collecting the revenue. Most contractors don't know theirs. Knowing it would change how they structure payment terms and how they sell. The data to calculate it is sitting in the same software. It's just not part of the weekly rhythm. Gross profit per billable hour has the same problem: the inputs are there, the calculation is possible, and the habit of running it is what's missing.
This is not an argument against software. It's an argument against treating software adoption as the work, when the work is building the input discipline that makes the software tell you something true.
What to Do Monday Morning
Pull ten completed job records from last month. Use a mix of service calls and installs if you have both. For each one, manually attach three numbers: total technician hours including drive time, total materials cost with any freight or restocking you can identify, and revenue collected. If multiple technicians worked a job, split the hours.
Calculate gross profit dollars per job: revenue minus labor cost (hours times burdened rate) minus materials. Divide by total hours. That's your baseline.
Then build the truck operating cost number for one truck. Pull the annual insurance cost from your binder. Calculate fuel cost using actual MPG on actual routes — your fuel card data has this. Add a maintenance reserve; I use a percentage of the truck's replacement value per year as a floor, and I'm conservative about it. Divide the total by annual hours dispatched. Attach that number to every job record that truck touches.
Do this for ten jobs and see what the spread looks like. In my experience, shops running this calculation for the first time find meaningful distance between their best and worst job types. That spread is the first useful signal — not because the low end is necessarily a problem, but because you need to know it exists before you can decide whether to price it differently, dispatch it differently, or stop taking it.
The shop in 2019 had healthy revenue per job right up until the acquisition conversation, when the actual job economics came apart in due diligence. The owner had spent three years making decisions with incomplete information. That's not unusual. Most of the shops I work with are in the same position — just earlier in the timeline.
Gross profit dollars per billable hour is the number that tells you whether the work is worth doing. Build it from real data once, and the revenue line stops feeling like enough.
FAQ
If my revenue per job has been going up every year, doesn't that mean I'm heading in the right direction?
Rising revenue per job can mean you're selling higher-value work, which is good. It can also mean you're taking on more complex jobs that run longer and cost more to deliver, with pricing that didn't keep pace. I've worked with shops that had several consecutive years of revenue-per-job growth while compressing margin the entire time — equipment costs and labor costs rose faster than average ticket. The direction of one number doesn't tell you the direction of the business. Attach costs to ten jobs and you'll know more in an afternoon than the revenue trend told you in a year.
What counts as a "billable hour" — is drive time in or out?
For job costing purposes, drive time is in. Your technician's time in the truck is real labor cost you're paying, and the truck is a real operating cost accumulating. The question isn't whether to count it — it's whether to bill for it explicitly or fold it into your labor rate. Most residential shops build drive time into the hourly rate rather than line-iteming it. That works, as long as the rate was calculated with drive time included. If it wasn't, you're recovering that cost from nowhere.
I'm on a flat-rate pricing system. Does that mean I can't calculate gross profit per billable hour?
You can calculate it, and you should. The flat-rate system controls what you charge. It doesn't control what it costs you to deliver the work. Run the calculation on completed jobs using your actual costs — burdened labor, actual materials, drive time — and compare it to what the flat-rate book assumed. If your overhead is higher than what the book was built around, you'll see it in the spread. The flat-rate price is your revenue input. The cost side is still your problem to measure.
How do I know what my fully burdened labor rate actually is?
Start with the technician's hourly wage. Add employer-side payroll taxes: FICA, federal and state unemployment. Add workers' compensation insurance cost per hour, which varies significantly by state and classification code. Add benefits — health insurance, any retirement contribution, paid time off converted to an hourly equivalent. The total burden lands meaningfully above the base wage; the exact number depends on your state, your comp rate, and your benefits package. If you're pricing labor at the wage rate, you're not recovering the full cost of that labor before you've touched overhead.
My shop uses ServiceTitan. Shouldn't the job costing report already be doing this?
The report is there. Whether it's populated with accurate data is a different question. In most shops I've worked with running ServiceTitan, revenue and parts cost are captured reasonably well. Technician hours at the job level are inconsistently entered. Drive time is almost never attributed per job. Overhead allocation is not built into the job costing report by default — it requires configuration. The software can produce the right number if someone built the report correctly and the field team is completing every job record on every call. Check both before trusting the output.
How often should I be looking at gross profit per billable hour?
Monthly is the minimum for a shop under 15 trucks, once you've built the baseline. More useful is calculating it by job type — service calls separately from installs — and flagging any job that comes in more than 15 percent below your target rate. You're not trying to review every job. You're looking for patterns: which job types, which technicians, which call sources are running below the line. Monthly you can act on what you find. Quarterly it's already history.
Enjoyed this article?
Get articles like this in your inbox every Monday. Free, no spam.
