No API key·Nothing to install in ServiceTitan·No card required
completed-jobs.csvExported from ServiceTitan · sample rowsClosed-sales file
customer_phone
invoice_total
completed_on
business_unit
(512) 555-0134
$11,840.00
2026-07-18
Install
(512) 555-0188
$389.00
2026-07-18
Service
512.555.0107
$14,210.00
2026-07-19
Install
(737) 555-0162
$245.00
2026-07-21
Service
greencarries the match greyslices the report
Called 12 Mar · Google Ads
Invoiced 18 Jul · $11,840
Called 12 MarInvoiced 18 Jul · $11,840
The gap
ServiceTitan knows exactly what every job earned. Your ad account knows exactly what every click cost. Nothing you own puts those two facts in the same row.
ServiceTitan sees
The technician dispatched, the estimate accepted, the job completed, the invoice paid.
no shared row
Your ad account sees
The click, the keyword, the call that lasted ninety seconds, and what each one cost.
The file
What the export needs in it.
Three things carry the match: who, how much, and when. Anything else is optional and only changes how the report can be sliced.
01Needed
Customer phone or email
The customer record on the job. Phone is the stronger key in this trade, because most of the demand arrives as a call.
02Needed
Invoiced amount
The job total or invoice total. Use what you actually billed rather than the estimate — estimates and finals diverge most on exactly the large jobs that decide the ranking.
03Needed
Completion or invoice date
Whichever date your bookkeeping recognises. Consistency matters more than which one you pick.
04Optional
Business unit or job type
The column that separates a service call from a system replacement. Without it the two average into a number that describes neither.
Step by step
Getting the file out of ServiceTitan.
Written for somebody with ServiceTitan open in the next tab. Report names vary by edition, so each step says what to look for.
1
Run a completed-jobs or invoice report
You want one row per job with a customer contact detail, an amount and a date. The report's exact name varies by edition and by how your account was configured, so look for the export that lists jobs with revenue rather than for a particular menu item.
2
Set the date range wide
Twelve months minimum. In this trade an estimate written in March is accepted in July, and a file that only covers the current quarter will match the fast jobs and miss the profitable slow ones.
3
Include the customer contact column
This is the one column that makes the file matchable. A job list with amounts and no phone number is an accounting export, not an attribution input.
4
Export to CSV and upload it
Drop it into a new import. Column mapping is suggested automatically and you confirm it — there is a manual mapping path and it never goes away.
5
Add the second file
Your Google Ads or Local Services export, and your call tracking export if you use one. Both are downloads from tools you already pay for.
What comes back
The page ServiceTitan cannot show you.
Revenue by channel, the count of sales behind each figure, and an honest bucket for the
ones nobody could trace. Sample figures, from the worked example on the HVAC Companies page — not from a ServiceTitan account.
app.closerev.com/reports · August 2026 · sample
Traced to a channel$349,20068% of $513,500
Sales matched81 of 144high confidence only
Average sale$3,620per paid sale
Channel
Share
Sales
Revenue
Google Ads
38
$241,400
Meta Ads
24
$61,600
Email marketing
19
$46,200
Direct / Unknown
63
$164,300
Unmatched sales stay in Direct / Unknown. They are never spread across the paid channels to make the total look better.
The argument
What changes when the job and the ad share a row.
01
The estimate that sat for four months is where the money is
Home services has two jobs wearing one uniform. A drain clear is booked and paid inside a week. A system replacement is quoted, sat on, financed, re-quoted after the first cold snap, and closed in the next quarter or the one after. The first is easy to attribute and worth a few hundred dollars. The second is hard to attribute and worth ten thousand.
Every attribution window on the market is built for the first one. A ninety-day cookie expires before a replacement closes; a platform conversion fires on the form fill and never learns what the form was worth. So the reporting systematically over-credits whichever channel generates cheap, fast, low-value work.
Matching a completed job back to the customer who enquired removes the window entirely. If the person ServiceTitan invoiced in July is the person who called in March, that is one match, and the campaign running in March is credited with the July revenue. The gap is not modelled, estimated or decayed — it is simply two rows naming the same person.
02
What the ad platform can never see, and why that is the whole problem
Google Ads sees a click and, if you have conversion tracking configured well, a form submission or a call that lasted longer than some threshold. It does not see whether a technician was dispatched, whether the customer accepted the estimate, whether the job was completed, or what it invoiced. That information exists only inside ServiceTitan.
This is not a shortcoming of the ad platform. It is a boundary: the revenue simply never crosses into the advertising system, and no amount of tag configuration moves it. Uploading offline conversions is the usual workaround, and it helps the bidding, but it does not give you a report you can take to a partner meeting — it gives the algorithm a signal and gives you nothing.
Reconciling the two exports produces the report instead. The output is a channel table with revenue in it, the count of jobs behind each figure, and an honest bucket for the jobs that could not be traced to any channel at all.
03
Membership revenue belongs to the channel that produced the member
A maintenance agreement is the most valuable thing a home services company sells and the hardest for any marketing report to value. The first year is a modest amount; the renewals, the priority service calls and the eventual replacement quoted by a technician already in the house are worth a multiple of it.
Because the match is on the customer rather than on a session, every later invoice against that customer credits the channel that produced them the first time. A channel that brings members rather than one-off calls stops looking equivalent, which for most contractors reorders the list.
Export ongoing revenue as its own rows against the same customer and the report handles it. Nothing is projected forward — only revenue that has actually been billed appears.
04
Business units, not a company average
A single ServiceTitan account commonly carries service, install, commercial and sometimes a second trade, each with a different average ticket and a completely different marketing profile. A blended cost per job across all of them is a number no manager can act on, because no manager owns all of them.
Carrying the business unit or job type through into the export splits the report along the same lines the business is actually run on. On Growth and above the same column supports comparing locations, which is where multi-branch contractors usually find the largest differences.
Fair questions
“ServiceTitan already does that.” Not quite.
They say
“ServiceTitan already reports on marketing.”
We say
It reports on what it can see, which is the source recorded against the job — usually a value somebody chose from a list at booking. That is a useful field and it is not the same as knowing which campaign and which keyword produced the customer, or what the ad cost. This joins the job's revenue to the ad data ServiceTitan never receives.
They say
“We upload offline conversions to Google already.”
We say
Good — that is the right thing for bidding. It is a signal going out, not a report coming back. You still cannot open a page that shows revenue by channel with the jobs behind it, and that is what this produces.
They say
“Our CSRs record the source on every call.”
We say
Then your Direct bucket will be small and the report will confirm that. Where the recorded source and the matched channel disagree, both are shown rather than one silently overwriting the other.
Completed jobs or invoices: one row per job carrying a customer phone or email, the amount, and a date. Business unit and job type are optional and useful.
Any export that lists jobs with revenue and the customer's contact detail. The name differs by edition and configuration, so we describe the shape rather than a menu path — if the file has those three things it will work.
No. This works from a CSV you export yourself, which means there is nothing to install, no permissions to grant, and no dependency on your edition's API access.
Twelve months at least. Replacement work routinely closes a quarter or two after the enquiry, and a short file understates exactly the channels that produce it.
The invoice. Estimates and finals diverge most on large jobs, which are the ones that decide which channel wins.
Yes, with a business unit or job type column. Blending them produces an average ticket that describes neither.
Yes. Export it as further rows against the same customer and it credits the channel that produced them originally.
They are one customer. The first job is the acquisition and the rest are revenue against it, all credited to the same original channel.
No, but this is a phone trade, so a call export is usually the strongest second file if you have one. Without it, the ad platform export alone still works.
They go to Direct / Unknown and stay there. Unmatched revenue is reported as unmatched, never distributed across the paid channels to make the total look better.
Encrypted in transit and at rest, isolated per workspace, deletable in one click, and we act as a data processor with a DPA available.
Yes, with a location column, on Growth and above.
By trade
Trades that run ServiceTitan.
What the report looks like once the export is in, written for each one.
ServiceTitan and the other product names and logos on this page belong to their owners and are
shown to identify the software a file comes from. CloseRev is not affiliated with or
endorsed by them, and connects to none of them: it reads a file you export.
Start today
Two exports, and you will know.
Nothing to install in ServiceTitan, no API key, and no need to have been tracking anything
until now. Last year works as well as this month.