Most call attribution stops at "this number was on this landing page." That is enough to know a channel works and not nearly enough to know which keyword to bid up.
Here is what a complete setup looks like, in the order worth building it.
Session-level number assignment
Static numbers per campaign are the common starting point and the first thing to outgrow. A single number on a landing page tells you the campaign produced calls; it cannot tell you which keyword, ad, or creative did.
Dynamic number insertion assigns a number per visitor session from a pool. When the call arrives — including the one that arrives eleven minutes after the tab was closed — it resolves back to that exact session and everything the session knew.
Pool sizing matters more than people expect. Size it from concurrent sessions, not daily visits. Two visitors sharing a number at the same moment produces attribution that is confidently wrong, which is worse than attribution that is missing.
Capture the click identifiers, not just UTMs
UTMs tell you what you tagged. Click identifiers tell you what the platform actually recorded, and they are what you need to push conversions back.
Capture GCLID, MSCLKID, and FBCLID alongside your UTM parameters, persist them for the session, and attach them to the call record. Without them, offline conversion import is not possible and you are limited to reading reports rather than feeding the bidding algorithms.
Push outcomes back into the platforms
This is the step that separates measurement from optimisation.
Smart bidding optimises against whatever you tell it a conversion is. If you report form fills, it will find you people who fill in forms. If you report billable calls, it will find you people who call and stay on the line long enough to qualify.
The mechanism is offline conversion import: when a call becomes billable, send that event back to the ad platform with the original click identifier and, ideally, a value. Within a few weeks the bidding shifts noticeably — usually toward keywords that looked mediocre on click-through rate and excellent on call quality.
Value, not just count
Reporting every billable call as one conversion tells the algorithm all calls are equal. They are not. A mass tort call worth $240 and an HVAC call worth $59 should not train the same bid.
Send conversion value. If you do not know the downstream value yet, send the payout as a proxy — it is imperfect and it is far better than treating them as identical.
Close the loop with the outcome, not the call
The last step, and the one most programmes never take, is reporting what happened after the call. Did the policy get written? Did the case get signed? Did the job get booked?
Once downstream outcomes flow back with the original click identifier, you can finally answer the question everyone actually asked at the start: which keyword makes money. Not which keyword makes calls.
What this costs you
Honest accounting: this is a few weeks of engineering, a number pool that scales with traffic, and ongoing maintenance whenever a platform changes its import format.
The reason to do it anyway is that every layer you add moves the optimisation target closer to revenue. A bidding algorithm pointed at clicks will faithfully find you clicks forever.