You know your total revenue. Open the CRM, look at the month, there’s the number. What almost no home-service owner can tell me on the spot is which job types, keywords, and channels produced the profit inside that number — and which ones quietly lost money. That gap is where most ad budgets bleed.
Here’s the uncomfortable part: some of your jobs and some of your keywords are losing money right now, and your reports are hiding it behind a healthy-looking top line.
Why cost per lead isn’t enough
Cost per lead is the metric every dashboard hands you, and it’s nearly useless on its own. A lead isn’t money — it’s a phone that rang. To know if a channel works, you have to walk the lead all the way down:
Cost per lead → booking rate → average ticket → margin → profit.
Two channels can post the same $40 cost per lead and live in completely different worlds:
- Channel A: 30% of leads book, $600 average ticket, 55% margin.
- Channel B: 8% of leads book, $180 average ticket, 40% margin.
Same cost per lead. Channel A earns roughly $99 of gross profit per lead; Channel B earns about $5.76. One is a machine, the other is a leak — and cost per lead can’t see the difference. The number you actually need is cost per booked job alongside margin by job type. Everything in this article is plumbing to get those two numbers honest.
Margin by job type is the variable everyone ignores
In the trades, margin isn’t flat — it swings hard by the kind of work. Current industry benchmarks for HVAC put service and repair at roughly 50–65% gross margin while install and replacement runs closer to 35–45%, because the equipment cost and the second tech’s labor eat directly into the job. Plumbing tends to run a few points higher at the gross level because one technician can knock out a high-value repair. Repair work is often 2–3× more profitable per dollar than installs. (Treat these as industry benchmarks — plug in your own job-costing before you act on them.)
Why this matters for marketing: if you optimize toward revenue, you’ll happily pour budget into the keyword driving big-ticket replacements — and watch your profit flatten, because you’re buying your lowest-margin work at scale. Revenue and profit point in different directions, and the only way to see it is to attach a margin to every job type before you judge a channel.
ROAS gets you in trouble; POAS keeps you honest
This is the cleanest mental model for the whole problem.
- ROAS (return on ad spend) = revenue ÷ ad spend.
- POAS (profit on ad spend) = gross profit ÷ ad spend.
ROAS is what the ad platforms optimize toward by default, and it treats two $600 jobs as identical even when one nets you $240 (40% margin) and the other $360 (60% margin). A campaign can show a strong ROAS and still lose money once you subtract the cost of actually doing the jobs. POAS is the metric margin-aware operators reach for instead: it subtracts the cost of the work before it judges the spend.
One honest caveat: POAS isn’t a button inside Google Ads — it’s a mental model and a calculation you run on your own job data. You don’t need a fancy POAS column to start. You need to stop pretending a dollar of replacement revenue and a dollar of repair revenue are worth the same to your bottom line — they aren’t.
The data plumbing: how the profit actually gets connected
This is where it goes from theory to a system. Four pieces, in order.
1. Tag every lead by service, keyword, and channel
Every inbound path has to carry its real source. Call tracking with dynamic number insertion stamps each call with the campaign, keyword, and channel that produced it instead of leaving a dispatcher to guess. Web forms capture UTM parameters and the gclid so a form fill already knows it came from “Google Ads / drain-cleaning campaign,” not just “website.” This is the foundation, and it’s exactly what our conversion tracking work is built to lock down.
One compliance note that’s load-bearing here: if your call tracking records calls, recording consent is governed by state law, and 12 states require all-party consent (CA, CT, DE, FL, IL, MD, MA, MI, MT, NH, OR, PA, WA). If you operate in or take calls from any of them, use a recording disclosure at the start of the call — a reputable call-tracking provider triggers the announcement automatically in two-party states. When in doubt, disclose; it’s a one-line greeting, not a project.
2. Tie the lead to its job value in the CRM
The lead now has a source and a click ID. Your CRM — Workiz, HouseCall Pro, ServiceTitan, Jobber — has the booking status and the job value. You stitch them together internally by phone number or email: this lead, from this keyword, became this $640 booked job at this margin. Now a channel isn’t “47 leads,” it’s “47 leads, 14 booked, $580 average ticket, 52% blended margin.”
3. Feed the outcome back to the platforms (gclid)
Here’s the loop most agencies skip. When a paid click lands, Google passes a gclid; you captured it in step 1. Once a job books and you know its value, you upload that outcome back to Google as an offline conversion import keyed on the gclid, with the real job value attached. Google’s smart bidding then optimizes toward clicks that become booked, paid jobs — not toward whatever rang the phone.
A current note, scoped accurately so you don’t panic over the wrong thing: the gclid itself is not going away — it remains the primary match key. What’s changing is narrow. Per Google’s published timeline, starting around June 15, 2026, the direct Google Ads API integration route for new developers stops accepting new adopters: developer tokens not already allowlisted (active roughly Dec 2025–May 2026) get rejected, and the path forward for new API builds is Data Manager. Manual GCLID file uploads in the Google Ads UI and standard CRM connectors (native HouseCall Pro / ServiceTitan / Zapier integrations) are not part of that deprecation — if that’s how your setup uploads conversions, it keeps working. Enhanced Conversions for Leads, which matches on hashed email and phone, is Google’s increasingly recommended companion to gclid and your fallback when the click ID is missing.
A timing reality most owners miss: this loop runs on a lag, not in real time. The default conversion-import window is 90 days, gclids have validity windows, and home-service jobs often book weeks after the click — a furnace replacement can close months later. That means your bidding is optimizing on lagged, sometimes still-incomplete data, and your POAS reads stabilize over weeks, not days. Don’t judge a campaign on three days of data; let the window fill.
4. Read profit by keyword and job type — and cut the losers (carefully)
With job value flowing back, you can finally rank not by cost per lead but by profit per keyword and per job type. This is where the money hides:
- A cheap-repair keyword that costs $55 in clicks and call handling to acquire a $140 job at 55% margin ($77 gross) is losing $/job — it earns less than it costs to win.
- A high-volume keyword that looks great on cost per lead but books at 6% and attracts price shoppers can quietly be the biggest drain in the account.
- A specific job type — say, one-off diagnostic calls — can be net-negative once you load in the acquisition cost.
The guardrail: don’t kill a keyword on three bookings. Most local accounts don’t generate enough conversions per keyword to judge profit reliably, and modern smart bidding and Performance Max often hide keyword-level granularity anyway. Wait for a meaningful sample before you cut, and act on patterns across job types and themes, not on a single noisy term. You can’t see any of this on a cost-per-lead report. You can only see it when profit is attached to the line item, which is the whole point of revenue attribution — it turns “we spent $4,000 on Google” into “drain-cleaning keywords returned a 6:1 POAS and this cluster of repair terms lost money over a real sample, so we paused them.”
What this looks like when it’s working
The difference between the before and after is stark. Before: “We did $90,000 last month and spent $4,000 on Google.” After: “We did $90,000; replacement keywords ran a 2.1:1 POAS at thin margin, four repair keywords lost money over the quarter so we paused them, and Local Services Ads booked jobs at a $42 cost per booked job — tracked separately, because LSA doesn’t pass a gclid through the same pipe.”
That second sentence is a business deciding where its next dollar goes. The first is a guess wearing a suit.
A note on that LSA line: Local Services Ads is tracked differently. It doesn’t pass a gclid, and its lead-to-job data lives in its own system, so you can’t feed LSA outcomes back through the offline-conversion loop in step 3. You still measure its profit — cost per booked job, close rate, average ticket — you just do it by reconciling the LSA lead log against your CRM, not through the gclid pipe. It’s one more channel in the profit view; it just gets there by a different road. If LSA is a real line in your budget, that’s our Local Services Ads work.
FAQ
Why isn’t cost per lead enough to know if my marketing works? Because a lead isn’t money. Cost per lead tells you what it costs to make the phone ring, not whether the call became a booked, paid, profitable job. Two channels can share a $40 cost per lead while one books 30% at a $600 ticket and the other books 8% at $180. You need cost per booked job and margin by job type to know which channel actually pays you.
What’s the difference between ROAS and POAS? ROAS divides revenue by ad spend; POAS divides gross profit (revenue minus the cost of doing the job) by ad spend. Margins differ by job type, so a 60%-margin repair and a 40%-margin replacement can show identical ROAS while earning very different profit. Optimizing to ROAS pushes budget toward high-revenue, low-margin work; POAS pushes it toward what actually makes you money. POAS is an operator metric you compute yourself, not a native Google Ads column.
How do I connect a Google Ads click to the job value in my CRM? Capture the gclid on every form and store it with the lead, stamp every call with its true source via call tracking, then pull the booked job’s value from your CRM and upload it to Google as an offline conversion import keyed on that gclid. The click ID ties the ad to the lead; the phone or email ties the lead to the booked job in Workiz, HouseCall Pro, or ServiceTitan. Local Services Ads is the exception — no gclid, so it’s reconciled separately.
Can a keyword or job type actually lose money? Yes, routinely. A cheap-repair keyword can cost more in clicks and call-handling time than the job earns at its margin. A high-volume keyword can look great on cost per lead and lose money on cost per booked job because it books rarely or attracts price shoppers. Only profit by keyword and job type exposes it — but read it over a real sample, not three bookings, so you cut losers and not noise.
See your real numbers
If you can name your total revenue but not your most and least profitable channel, you’re flying on a top line that hides the leaks. We build the tracking, the CRM stitching, and the offline conversion pipeline that turns cost per lead into profit by job type, keyword, and channel — and feeds it back so your ads optimize toward booked, profitable work, with the consent, attribution-window, and sample-size caveats handled honestly. See my real profit by channel and we’ll show you which line items to cut first.