Work / case study
Nobody could say which spend produced customers
- Client
- A high-ticket B2C services business running two brands, ~$200K/month in paid media
- Engagement
- Fractional CTO and CMO. Platform rebuild, measurement layer, outcome bidding, reporting engine.
- Named
- Nobody. The client, its brands, its staff and its agencies are anonymized throughout.
The cost per lead looked fine. Nobody could say what a lead was worth. Joining the website, the CRM, the ad accounts and the spend showed that the tracking had never been fully set up, that what existed had quietly broken, and that the majority of the budget had moved into the channel converting at a third the rate.
The setup
A consultative, high-ticket consumer service: an enquiry, a screening, a meeting, then a signed and paid client, weeks later. Two brands under one owner, competing in the same auctions. Around $200K a month in paid media, mostly Google, some Meta. Several years of ad history across two successive ad agencies, and a CRM going back over a decade.
No CMO. The agency reported leads and cost per lead. Tracking had been set up in parts by successive vendors and never finished; the part that reported outcomes back to the ad platform had broken without anyone noticing. Staff kept the real outcome count, meetings actually conducted, in a spreadsheet by hand. The website was a legacy PHP CMS with a separate back office. Nobody held the spend, the funnel and the systems at the same time.
What everyone believed
Cost per lead was acceptable and trending the right way. Performance Max, the cheaper channel per lead, looked like the best buy and had been given a growing share of the budget by both agencies in turn.
The staff spreadsheet said meetings were flat while applications rose. That was read as a capacity problem on the sales side, not a marketing problem.
What was actually true
Joining the enquiry records to the CRM stage history and the certified spend took the question off the spreadsheet and onto the data. The cheap channel converted an enquiry to a held meeting at a third the rate of Search, across 11,313 leads in 2025, separately at both brands, and still a year later.
The signal back to Google had been dark since November 2023. Every 2026 form conversion carried a value of $0. The platform had been optimising toward form count because that was the only thing it had ever been told.
The enquiry form already asked a question that predicted the outcome. Applicants under one income threshold booked 0 of 1,013 meetings. Priced by expected value, enquiries ranged from $1.38 to $1,557.95, and every one of them was being bid on at the same price.
- 8.70% vs 2.72%Held-meeting rate, Search vs Performance Max2025, across 11,313 leads. True separately at both brands and still true a year later. Search converted an enquiry into a real meeting 3.2 times more often.
- Nov 2023Last time a down-funnel outcome reached GoogleNo meeting, acceptance or payment was reported back to the ad platform after that date. Every 2026 form conversion carried a value of $0.
- 0 of 1,013Meetings booked by applicants under $50K household incomeA segment the enquiry form already identified, bought at the same price as every other enquiry.
- $1.38 to $1,557.95Expected value per enquiry, lowest to highest segmentA 1,129× spread, bid on as if every enquiry were identical.
Why nobody caught it
Not negligence. Structure. The agency saw the ad accounts and the form fills, and by that measure the cheap channel was winning. The CRM admin saw stages, with no cost attached. The web vendor saw uptime. The staff spreadsheet saw meetings, with no channel attached.
The finding needed the website, the CRM, the ad platforms and the spend data joined at once. No vendor had all four, and no seat on the org chart was responsible for joining them. The outcome feed had failed silently; a later CRM layout change removed the checkbox four automation rules depended on, and nothing alerted anyone.
What was built
The CTO half came first, because the measurement had nowhere to live. The legacy PHP CMS running both brands was migrated to Next.js and Postgres by tooling rather than by hand: pages extracted and rebuilt by script, redirects generated from the old address map, structured data carried across, and search rankings held through the cutover. A staff admin portal replaced the old back office, and two client-facing portals followed. CI/CD runs across Vercel and Railway. The work was delivered by one engineer directing agents: 2,095 commits and 213 merged pull requests over the engagement, with one backlog sweep shipping 22 pull requests and 8,440 passing tests in a day.
On that platform: a tracking package with click-id capture, consent, and server-side events deduplicated against the browser pixel. A corrected tag-manager container, staged by API with rollback versions recorded. Certified spend landing nightly from the ad platform. A CRM mirror with full stage history.
Then the ledger itself: one row per enquiry per outcome per destination, an expected-value model per segment from matured cohorts, and value-weighted outcomes dispatched to Google and Meta, run dark first. On top, a reporting engine that freezes each day’s numbers, revises them for 45 days, and refuses to publish a report whose sections do not reconcile. The staff spreadsheet was reproduced cell by cell before it was automated.
- 2,095 commits, 213 merged PRsDelivered over the engagementOne engineer directing agents: a legacy-CMS migration across two brands, a staff admin portal, two client portals, and the measurement layer on top.
- 22 PRs, 8,440 testsShipped and passing in one dayA single backlog sweep released as one build.
What changed
Measured, on the same pages and the same definitions, before and after.
- Enquiry-page conversion rose from 12.2% to 20.4% after the rebuild.
- Analytics that had counted form events ~4× now count them once, with browser and server events sharing an id.
- Click-id capture into the CRM, which had decayed to nothing on the legacy site, now covers the large majority of paid enquiries.
- Cost per held meeting by channel is reported monthly from reconciled numbers, for the first time in the business’s history. The budget allocation argument is now had with that number on the table.
- The largest leak was found where no ad platform looks: 77–79% of accepted customers were lost before payment, and booking lead time explained most no-shows (6.4% same-day vs 34.6% at 14–27 days). Both are now operational targets with a number attached.
- The value-weighted outcome feed is built and going live brand by brand. As it does, bidding moves off form fills and onto expected revenue, measured against the trailing-twelve-month baseline.
- 12.2% → 20.4%Enquiry-page conversion, before and after the rebuildMeasured on the same enquiry page, legacy CMS vs the rebuilt site.
- 6.4% vs 34.6%No-show rate, same-day booking vs booked 14–27 days outBooking lead time, not lead quality, drove most of the no-shows.
What it cost to build vs buy
Itemised against what the same components cost bought separately: the measurement layer at $69–130K replacement; the reporting engine at $68–90K built in-house or $105–160K through an agency; the retainer function, bought as separate fractional, analytics and development contracts, at $50.5–80K a month; specialist analytics engineering at $200–275 an hour.
The engagement was priced well under those anchors, and the measurement layer was delivered first and billed later. The commercial model on the services page exists so that the second part does not recur.
- Measurement layer (tracking, attribution, outcomes to the platforms, the value model)$69–130K
- Reporting engine, built in-house$68–90K
- Reporting engine, built by an agency$105–160K
- The retainer function bought separately$50.5–80K / month
- Specialist analytics engineering, hourly$200–275 / hour
Start
Your version of this starts with a teardown.
Same method, your accounts. The teardown is free and covers the ad accounts, analytics and website; the diagnostic adds the CRM, which is where the findings in step three came from. Most businesses with this shape have an equivalent sitting in the gap between their vendors.