A trades business can spend five figures a month on Google Ads and still not know which campaign paid for which job. The form says 'contact us.' The phone rings from a missed-call widget. The invoice is raised three weeks later in a different tool. Analytics reports a conversion. The CRM reports a job. The two numbers never match.
That gap is not a reporting preference. It is how companies keep buying the wrong keywords. KeenCraft ran into it on a parking marketplace rebuild (PARKees) and again while building a multi-tenant CRM for trades. The rest of this article is the model we actually ship.
Why last-click lies to service businesses
Last-click is fine when the product is a SaaS checkout on the same domain as the ad landing page. It breaks when:
- The customer researches on mobile, then books on desktop by typing the brand name.
- The conversion is a phone call, not a form submit.
- The sale closes in a CRM days or weeks after the first visit.
- Staff create the booking record by hand and leave the source field blank.
Direct traffic then absorbs credit it did not earn. Paid search looks weaker than it is, or stronger than it is, depending on how cookies and call tracking were set up. Operators make budget decisions on that fiction.
Last non-direct-click, in operational terms
Last non-direct-click means: ignore pure direct visits when a known campaign or referrer already exists for that person. If someone clicks a Google Ad on Tuesday, comes back via bookmark on Thursday, and books on Thursday, the booking still belongs to the ad.
On PARKees, that model was implemented with dataLayer capture of UTM parameters and referrer data. The important part is not the Google Tag Manager checkbox. It is that the first-party site writes a durable source onto the session and then onto the booking.
What you have to capture on every landing
- utm_source, utm_medium, utm_campaign, utm_content, utm_term when present.
- The HTTP referrer when UTMs are absent (organic, partner, marketplace).
- gclid / wbraid / gbraid for Google Ads click identifiers.
- A first-party identifier (cookie or authenticated user id) that survives the booking flow.
- Landing page path, so you can tell a service page from a blog post from a homepage.
Closed-loop: ads spend in, invoices out
The trades CRM is a live multi-tenant system KeenCraft built for local services. It auto-scores leads 1–100, maps form submissions into CRM records, runs email automations by job stage, tracks jobs from lead to invoice, and attributes revenue back to source, including Google Ads through officially verified OAuth.
That last clause matters. Unofficial scraping of Google Ads is how integrations break during verification and how accounts get banned. Official OAuth is slower to set up and is the only version that survives a real audit.
A closed loop, in the form we implement under automation and CRM integrations:
- Click or call lands with UTMs / gclid stored first-party.
- Form, chat, or voice agent creates a CRM lead with those fields copied, not re-typed.
- Lead scoring and stage automation keep the job moving without a human re-entering source.
- When the invoice is paid, revenue is attributed to the stored source, not to whoever last edited the record.
- Google Ads (or the equivalent) receives an offline conversion so bid strategy can see real jobs, not just form fills.
Phone calls are first-class conversions
For appointment businesses, the highest-value conversion often never hits a thank-you page. That is why KeenCraft's voice agents are designed to write the same source fields a web form would. If VoiceCake books a dental appointment from a missed-call number that was advertised, the CRM still needs to know which campaign paid for the ring.
Practically: pass a tracking number or a call-source parameter into the agent context, persist it on the appointment, and do not let a receptionist overwrite it with 'phone' as a vanity source. 'Phone' is a channel. It is not a campaign.
A setup sequence that does not require a 40-page analytics RFP
- Inventory the money events: form, call, chat, in-person booking, invoice paid.
- Put first-party UTM and referrer capture on every public page, including the blog.
- Copy those fields into the CRM on create. Never rely on staff memory.
- Choose last non-direct-click as the default reporting model for paid search. Keep last-click as a secondary view.
- Wire offline conversions only after the CRM source field is trusted.
- Review weekly: spend vs booked jobs vs paid invoices, not spend vs 'leads'.
This is not a full marketing stack replacement. It is the minimum architecture that stops you from scaling ads into a black hole. If you already have HubSpot, Salesforce, or Zoho, the same pattern applies; the CRM brand is less important than whether source survives from click to cash.
Related on this site