The short version
Your client asks whether their marketing is working. They don't want to hear about impressions, clicks, or form fills. They want to know if the spend turned into revenue. For B2B campaigns with long sales cycles, that answer lives in the CRM, not in the platform dashboard. This article walks the complete chain: tracking link → landing page → form → CRM pipeline → closed deal, and how agencies running multiple clients keep attribution clean without the data bleeding across accounts.
Why platform metrics don't answer the revenue question
Google Ads shows conversions. Meta reports ROAS. LinkedIn counts lead form fills. None of them know what happened after the lead landed in your client's CRM.
The conversion the platform counted might have been a junk form fill that sales never contacted. Or it might have been a $40,000 deal that closed four months later. The platform doesn't know which, because it can't see the pipeline.
This isn't a criticism of the platforms. It's a limitation of where their visibility ends. They optimise for the last trackable action before someone leaves their ecosystem. For B2B clients with multi-month sales cycles, that action is almost never revenue.
If you're reporting marketing performance to a client using only what the ad platform tells you, you're showing them activity, not outcomes.
What "prove revenue" actually means in a B2B context
For an ecommerce client, revenue attribution is relatively straightforward: someone clicked an ad, landed on a product page, bought something, and the transaction value is recorded. The purchase happens in the same session, or close enough that cookie-based attribution catches it.
B2B is different. The person who clicks your LinkedIn ad in June might not fill out a form until July. The lead sits in the CRM for three weeks before the first sales call. The deal doesn't close until October. By then, the LinkedIn campaign has ended, the budget has moved, and your client wants to know whether that spend was worth it.
Proving revenue in this context means connecting three separate systems:
- Your tracking link (the ad, email, or social post with UTM parameters)
- The form submission (where the lead's source gets captured or lost)
- The CRM deal record (where the sale happens and the revenue gets recorded)
If those three systems don't talk to each other, you're guessing. And your client can tell.
- Ad clickCampaign
The ad points to a tracking link
Consistent UTM parameters on every link, built from the same template for every client.
clientsite.com/offer?utm_source=linkedin&utm_medium=paid_social&utm_campaign=clienta-q3-retarget
- Site visitTrakt
The landing page keeps the UTMs
As long as redirects preserve the query string, the Trakt snippet records the visit with its source.
- Form leadTrakt
The lead is created with its source
Hidden fields capture the UTMs at submit, so the lead never arrives as Direct.
- utm_source
- utm_campaign
- clienta-q3-retarget
- CRM dealYour CRM
The pipeline carries the source forward
Map the source fields into the client's CRM through the form's field mapping or an export, then copy them from contact to deal.
- Closed wonWon
Revenue is attributed to the campaign
Months later the deal closes, and the value is still tied to the campaign that produced the lead.
- attributed to
- clienta-q3-retarget
- deal value
- $28,000
- Client reportReport
The report shows revenue, not clicks
Leads, opportunities, closed deals and revenue per campaign, filtered to this client only.
- campaign
- Q3 LinkedIn – Retarget
- closed
- 3 deals · $87,000
Each handoff is a place where the source can be lost. When all six hold, closed revenue can be reported against the campaign that produced it. Example values are illustrative.
The five places attribution breaks between click and closed deal
Attribution doesn't fail randomly. It breaks at predictable handoff points, and agencies running multiple clients see the same failures across every account.
1. The tracking link has no UTM parameters
A campaign launches without UTMs because someone on the team assumed the platform's auto-tagging would handle it. Or the UTMs exist but they're inconsistent: one campaign uses utm_source=linkedin, another uses utm_source=LinkedIn, and a third uses utm_source=li. When the data reaches the CRM, it fragments into separate buckets that can't be compared.
Fix: Use a UTM builder with saved templates so every link follows the same structure. For agency teams managing multiple clients, Trakt's campaign builder enforces naming conventions across accounts so UTM parameters stay consistent even when different people build the links.
2. The landing page redirects strip the query string
Your ad points to landing.clientsite.com/offer?utm_source=google, which redirects to clientsite.com/offer. If the redirect isn't configured to preserve query parameters, the UTMs are gone before anyone fills out a form. This happens often with URL shorteners, subdomain redirects, and page builders that rewrite URLs on load.
Test: Click through one of your live ads and check the URL in the browser's address bar after the page loads. If the UTM parameters aren't there, the redirect is the problem.
3. The form has no hidden fields to capture source data
This is where most B2B attribution dies. The person lands on your client's site with UTM parameters in the URL. They fill out a form. The form submits name, email, company, and job title to the CRM. But there's no hidden field configured to capture utm_source, so that value is never sent anywhere.
The CRM receives the lead with a blank source field, or it defaults to "Direct" or "Website." Sales follows up, the deal closes, and the revenue gets credited to nothing.
For agencies running dozens of client sites, setting up hidden fields manually on every form across every client is tedious and fragile. One form gets missed, or a client's web team rebuilds a landing page and forgets to add the hidden fields back. Trakt scans your client's site automatically and injects hidden fields across every form, so you don't have to configure each one individually.
4. The form integration doesn't map source fields to the CRM
Even when hidden fields exist, the data can still drop between the form tool and the CRM. This happens when:
- The form platform (Typeform, Gravity Forms, Webflow) sends data through a Zapier or Make workflow, but the Zap doesn't map the UTM fields through to the CRM
- The CRM field is set up as a dropdown, and it won't accept free text like "google" or "linkedin"
- Field names don't match: the form sends
utm_source, the CRM expectsLead_Source__c, and no one mapped the two together
Audit: Create a test lead on your client's site. Fill out the form with your own details. Then find that lead in the CRM and check whether the source fields are populated. If they're blank, the integration is broken.
5. The CRM doesn't tie deals back to the original lead source
Your client's CRM has the lead. Sales converts it to an opportunity. The opportunity moves through the pipeline. The deal closes. But when you pull a revenue report, the closed deal doesn't show where the lead came from, because the CRM doesn't automatically link the deal's source back to the original contact's UTM parameters.
This isn't a bug. Most CRMs (HubSpot, Salesforce, Pipedrive) require you to explicitly map source data from contacts to deals. If that mapping isn't configured, every closed deal looks like it came from nowhere.
Fix: set up lead-to-deal source mapping in the client's CRM so that when a contact becomes an opportunity, the UTM parameters carry forward to the deal record. Trakt makes sure the source is on the lead in the first place; the copy from contact to deal is a CRM workflow you configure once. That way, when you report revenue, you can filter by source and show your client which campaigns actually closed business.
How to report revenue without blending every client's data together
If you're managing attribution for more than one client, you need a workspace structure that keeps each client's tracking data separate. Otherwise, one client's LinkedIn campaign shows up in another client's Google Ads report, or a shared UTM template accidentally tags every client's traffic with the same source.
A clean multi-client setup has three requirements:
1. Each client has its own tracking domain and UTM namespace
Client A's links use utm_source=google, utm_medium=paid, utm_campaign=clientA-q3-retarget. Client B's links use the same structure but with clientB in the campaign name. That way, if data ever gets mixed (it shouldn't, but assume it will), you can still filter it back out.
2. CRM field mapping is scoped per client
If you're using an attribution platform, make sure each client workspace maps its form fields into that client's own CRM, not a shared agency CRM. That way, Client A's leads land in Client A's Salesforce, and you don't have to manually tag every record with a client identifier.
Trakt's agency workspace is built for this: each client gets their own sub-account with isolated tracking links, form detection, and leads, so one client's data never shows up in another's reports. The source fields reach each client's CRM through that client's own form field mapping (or an export).
3. Revenue reports filter by client, campaign, and source
When you pull a performance report, you need to be able to filter it by:
- Client (obviously)
- Campaign (so you can compare Q2 LinkedIn against Q3 Google Ads)
- Source and medium (so you can see which channels are actually driving deals, not just traffic)
If your reporting tool can't do this, you're building spreadsheets every month to reconstruct what the data should have shown in the first place.
The revenue report your client actually wants to see
Here's what a useful B2B attribution report looks like:
| Campaign | Spend | Leads | Opportunities | Closed Deals | Revenue | Cost per Deal |
|---|---|---|---|---|---|---|
| Q3 LinkedIn – Retarget | $4,200 | 23 | 8 | 3 | $87,000 | $1,400 |
| Q3 Google – Brand | $1,800 | 41 | 12 | 5 | $104,000 | $360 |
| Q3 Meta – Lookalike | $3,100 | 67 | 4 | 1 | $22,000 | $3,100 |
This report shows:
- Which campaigns generated leads (most marketing dashboards stop here)
- Which of those leads became qualified opportunities (sales accepted them)
- Which opportunities closed (revenue happened)
- Cost per closed deal (the number your client actually cares about)
Notice what's missing: impressions, clicks, click-through rate, cost per click. Those metrics exist, and they're useful for optimising campaigns in real time. But they don't answer the client's question, which is "did this spend make us money?"
Start tracking the full revenue path →
What to do when attribution isn't perfect (it never is)
Even with clean UTM parameters, hidden fields on every form, and proper CRM mapping, some leads will show up with no source. This happens when:
- Someone types your client's URL directly after seeing an ad elsewhere
- A lead comes in through an untracked channel (a referral, a podcast mention, a LinkedIn DM)
- A tracked link gets shared in a way that strips the UTM parameters (Slack, email forwarding, some mobile apps)
Perfect attribution is a myth. The goal is to capture enough source data that when you report revenue, the "Unknown" or "Direct" bucket is small enough that it doesn't undermine the story.
If 80% of your client's closed deals have a known source, you can make confident budget decisions. If 80% show up as "Direct," you're guessing, and your client knows it.
How to audit your current setup before the client asks
Run this checklist on each client account:
- ☐ Every active campaign has UTM parameters on every link
- ☐ UTM structure is consistent across campaigns (same source/medium values, same naming convention)
- ☐ Landing pages preserve UTM parameters after redirects
- ☐ Forms have hidden fields for
utm_source,utm_medium,utm_campaign,utm_content,utm_term - ☐ Form-to-CRM integration maps source fields correctly
- ☐ CRM ties deal records back to the original contact's source data
- ☐ Revenue reports can be filtered by campaign, source, and medium
- ☐ "Direct" or "Unknown" makes up less than 30% of closed deals
If any of those checks fail, that's where attribution is breaking. Fix it before the client asks why marketing can't show revenue.
Our free attribution audit is coming soon, see what it will check →
Where to start
The easiest place to start is with one client, one campaign, and one form. Set up clean UTM parameters, add hidden fields to the form, map them to the CRM, and track one lead all the way through to see where it breaks.
Once you've proven the path works for one campaign, expand it to the rest of that client's site, then replicate the setup across other clients.
For agencies running attribution across multiple B2B clients, Trakt's multi-client workspace automates the tedious parts (hidden field injection, per-client source capture, revenue reporting) so you can focus on the strategy rather than the plumbing.
Related reading
- Why your CRM lead source shows "direct" even when it shouldn't
- Closed-loop attribution: connecting first click to closed deals
- How to set up multi-touch attribution for B2B
- Why UTM data disappears at form submission
Frequently Asked Questions
How do I prove marketing ROI to a B2B client when sales cycles are 3-6 months long?
Track the complete path from click to closed deal in the CRM, not just platform conversions. Set up hidden fields on forms to capture UTM parameters, map source data from contacts to opportunities when deals are created, and report on closed revenue filtered by campaign source. Platform dashboards show activity; CRM reports show revenue.
Why do my Google Ads conversions not match the deals in my client's CRM?
Because Google Ads counts form fills as conversions, but has no visibility into what happens after that. Some leads get marked unqualified by sales, others sit in the pipeline for months before closing. The platform can't see the difference. To prove revenue, you need CRM attribution that ties closed deals back to the original campaign.
How do I manage attribution across multiple agency clients without data bleeding between accounts?
Use a multi-client workspace where each client has isolated tracking links, form detection, and leads. Give each client their own UTM namespace (e.g., clientA-q3-campaign), map each client's form fields into their own CRM rather than a shared agency CRM, and ensure revenue reports can filter by client, campaign, and source. That way one client's LinkedIn campaign never shows up in another's reports.