“HighLevel already has attribution reports.”
On what it can observe — the web and tracked numbers. The client's invoices are the part it does not see.
For HighLevel
Export leads from the client's sub-account, get the client's invoices, and report revenue by source that the client can check against their own books.
No API key Nothing to install in HighLevelNothing to install No card requiredNo card
HighLevel sits on both sides for an agency — it captures the leads and tracks each client's pipeline — while the client's actual revenue lives in the client's own invoicing system. CloseRev joins the agency's lead export to the client's invoice export on the contact detail and reports revenue by source per client. For an agency the result is a number the client can verify against their own books, rather than a count of opportunities the agency marked won. Revenue with no traceable lead is reported as Direct / Unknown.
Last checked against HighLevel's own documentation on September 25, 2026.
The gap
The monthly report shows leads, appointments and pipeline, and the client keeps asking what any of it was worth.
What was sold, to whom, and for how much.
The click, the keyword, the call, and what each one cost.
The file
Three things carry the match: who, how much, and when. Anything else is optional and only changes how the report can be sliced.
On the contact in the client's sub-account. It is what joins your leads to the client's invoices.
How the contact first arrived, from the forms, funnels and tracking the agency set up.
When the lead arrived, so revenue can be grouped against the month the agency's work produced it.
Customer contact detail, amount and date from whatever the client bills from. This is the half the agency does not have.
Step by step
Written for somebody with HighLevel open in the next tab. Report names vary by edition, so each step says what to look for.
One row per contact with the contact detail, source, campaign and created date.
Contact detail, amount, date. It is the only half that says what the leads were worth, and it is the client's own record.
Never pool sub-accounts. Each client is its own file with its own window.
Days for a trade, months for a considered purchase. Agree it with the client before the first report.
The join runs on the phone and the email, normalised, and the report shows revenue by source for that client.
What comes back
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 Marketing Agencies page — not from a HighLevel account.
| Channel | Share | Sales | Revenue |
|---|---|---|---|
| Google Ads | 61 | $186,400 | |
| Meta Ads | 48 | $93,200 | |
| Email marketing | 19 | $46,600 | |
| Direct / Unknown | 44 | $97,400 |
Unmatched sales stay in Direct / Unknown. They are never spread across the paid channels to make the total look better.
The argument
Pipelines in a CRM move when somebody moves them. In an agency-run account that is sometimes the client's staff and sometimes nobody, and a won stage can mean a booking, a quote or a sale.
Reported to the client, it is a claim about their business made from inside the agency's tool.
The client's invoices are a record they created themselves, for their own reasons, and they are the one number the client will not argue with.
Matching the agency's leads against those invoices gives revenue by source that the client can reconcile to their own accounts.
That is a harder report to produce and a much easier one to renew a retainer on.
Attribution inside a marketing platform comes from what it can observe: forms, funnel pages, tracked numbers and the parameters on a landing page.
Customers who call the client's main line, walk in, or reply to a text from their own phone are invisible to it, and some of them came from the agency's work.
Matching on the customer rather than on the session catches the ones whose contact detail appears in the lead file, however they eventually got in touch.
Whatever still cannot be matched is reported as Direct / Unknown, which is honest and is also a useful number to show a client: it is the part nobody can attribute, including the agency.
An agency may run dozens of sub-accounts with different sales cycles, prices and definitions of a sale.
Pooling them to show an agency-wide result produces an average that describes no client and invites the question of which client is subsidising which.
The report is built per client, with the window, the revenue basis and the sources agreed with that client.
That also makes the method explainable in the client meeting: two files, joined on the customer, with everything unmatched shown.
Agencies generate leads and clients follow them up, and when results disappoint each tends to blame the other.
Because the lead file carries the time each lead arrived and the invoice file the sales that followed, the report can show whether leads contacted quickly closed at a different rate from leads contacted late.
Where they did, the conversation moves from whose fault it is to what the client's team can change, which is usually a better conversation for everyone.
It is one of the few things an attribution report can do for the relationship rather than just the budget.
Fair questions
On what it can observe — the web and tracked numbers. The client's invoices are the part it does not see.
Some will not. The ones who do get a report they can check, and that tends to be the account that renews.
That is fair, and it is also why clients discount it. Revenue is the number they are paying for.
No. It reads exported files, so your sub-accounts, funnels and automations stay where they are.
Both, partly: it holds the leads and the pipeline. The client's invoices are the revenue side.
Contacts from the client's sub-account with a contact detail, source and created date, plus the client's invoices.
Because a won stage is a record inside the agency's tool. The client's invoice is the record they trust.
No. Each client is its own file with its own window and its own definition of a sale.
If their contact detail is in the lead file, they match however they got in touch. The rest stays in Direct / Unknown.
Whatever fits the client's sale, agreed with them before the first report.
Yes, because both files carry dates, and it often moves the conversation from blame to fixes.
The report is yours to present. Its method — two files joined on the customer — is the part worth explaining.
Any client revenue with no matching lead. Showing its size is part of an honest client report.
A contact detail, a source and a date on one side; a contact detail, an amount and a date on the other. No conversations, no pipeline notes, no payment details. Encrypted in transit and at rest and deleted with the import.
Client revenue by source, per client, with the window stated, speed to lead where the dates allow, and everything unmatched kept visible.
By trade
What the report looks like once the export is in, written for each one.
Other systems
Running more than one system, or comparing? The method is the same and the columns are not.
HighLevel 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
Nothing to install in HighLevel, no API key, and no need to have been tracking anything until now. Last year works as well as this month.