I Knew the Dashboard Was Lying
There’s a specific feeling you get when the numbers are too clean. Ad metrics look fine and the platform says it’s learning. Everyone on the call nods, and you sit there knowing something is wrong. You can’t prove it yet.
I had that feeling for most of a summer on a recent engagement. The client was paying for traffic, and the dashboards said the traffic was working. The business said otherwise: almost nobody was signing up.
The dashboard wasn’t slightly off. It was wrong in at least seven ways at once, and each one made the others harder to see. This is the story of pulling that apart. It’s also a little bit of a victory lap. I’ve earned one.
What the dashboard said
One week of Meta delivery looked perfectly respectable:
- $2,340 spent
- 2,553 link clicks at a $0.92 CPC and a 1.9% CTR
- About 10% of landing page visitors clicking through to the signup page
That’s healthy for cold traffic. Meta was reporting conversions, and Google was reporting conversions. Taken as a whole, the reporting said we had a creative problem or a targeting problem.
That’s the trap. When the top of the funnel looks fine and the bottom looks bad, everyone blames the ads. The ads are the part you can see, and the part with a dashboard. So you swap creative, rebuild audiences, wait out another learning phase, and the bottom stays bad.
The real number was underneath. Signup page to account created was running about 0.7%. That week had 11 recorded form completions. About 2 were real people, and 1 came from Meta.
The mess
Here’s what I found once I stopped trusting the platforms and started reading raw events.
1. Landing page views that never happened. Meta’s landing page view optimization counts prefetches. In-app browsers load the page before anyone taps. In session recordings, 44% of signup pageviews never painted anything. Meta counted every one as a win.
2. The pixel over-counted by 43%. Meta reported 10 registrations from one campaign. Only 7 had a matching account in the backend.
3. One registration event fired several times per user. The backend sent the event to Meta from two code paths. One of them fired on every onboarding step, so a single signup could look like three. Deduplication was impossible because a refactor had deleted the event ID that would have caught the duplicates. Put together, platform-reported cost per lead ran 3 to 5x better than reality.
4. “Form started” fired when the page loaded. In a controlled test it fired 3.2 seconds after the ad click, before I’d touched anything. The “funnel step” was really a pageview.
5. Bots were filling the funnel. Farms ran through the signup flow in bursts, from datacenter IPs and disposable email domains. One wave created about 80 accounts in five hours, with company names like “Norton LifeLock” and “Heinz Tomato Ketchup.” Another came in on brand search UTMs. That burned real clicks and handed Google forty fake conversions to optimize toward.
6. One form had never worked. A lead campaign sent its traffic to a signup form for one specific offer. That form had produced zero accounts in its entire history. The leads were real and so was the spend. The backend rejected every submission.
7. Real people couldn’t sign up from the in-app browser. About 70% of paid traffic came in through the Facebook and Instagram in-app browsers. There, the form failed silently. One cause was a loading overlay that never cleared on cellular connections. Another was a bot check that waited for touch events the webview never sends. Desktop completed about 90% of starts, while the in-app browser completed 0 of 43. (I wrote up the full case study on that one.)
Bonus round: the server-side signup event dropped UTMs entirely. Facebook clicks with a click ID in the URL were getting labeled “direct.” A deploy quietly removed the client tracking calls. Hundreds of accounts were creating 20+ invoices each within minutes of signing up. Those weren’t customers. They were phishing, and they were padding the activation numbers.
Each issue covered for the others. Bots made broken forms look like they converted. Duplicate events made the pixel look healthy. Prefetches made the landing page look busy. With one fixed, the remaining six still produced a plausible dashboard.
How I proved it
A hunch doesn’t win a budget argument. Receipts do. Here’s how I got them.
I picked one source of truth and made everything else answer to it. That was the server-side “account created” event. It fires once, when an account actually exists in the database. Every platform number got checked against it, matched on email, because anonymous IDs broke between subdomains.
I split everything by user agent. Desktop, mobile browser, and in-app browser. The in-app split alone exposed the biggest problem in about an hour. It had been sitting in the data for weeks because nobody had cut it that way.
I watched the sessions. Session recordings show what aggregate charts hide. Visitors tapped the same element over and over, and 65 of 71 sessions never typed a single character.
I fingerprinted the bots. Datacenter networks, UTC browser timezones, and identical user agents. Fills done in seconds, often with brand-impersonation company names. Once I had the signature, I could exclude it from every count.
I reproduced the failures on a real device. I tapped a live ad on an iPhone and ran the signup through a proxy so I could watch every request. When an engineer says “it works on my machine,” a packet capture from the user’s machine ends the conversation.
I put the verified number in every readout, next to the platform number. Every week, the same table: the platform says X, the backend says Y. After a few weeks of the gap staying put, nobody argued with the backend number anymore.
Vindication
Once the signup path worked and the numbers were real, the picture flipped.
In the 18 days after the fixes, 151 of 166 real accounts came in through the in-app browser. That’s the environment that had produced zero a few weeks earlier. Verified cost per account was about $200 in the first clean window, and it dropped to about $100 a month later. Both numbers are backend-validated, not platform-reported.
And the ads? Mostly the same ads. The creative was never the main problem. The traffic had been good the whole time. It was hitting a wall nobody could see, and the dashboard was reporting a different story.
I’ll admit it felt good. Not because I was right and someone else was wrong. Spending weeks saying “I don’t believe this number” with nothing to point at is uncomfortable, and finally having the table that settles it is a relief.
The takeaway
A platform dashboard is the platform’s opinion of how well the platform is doing. Read it that way.
If you’re running paid acquisition:
- Pick a ground-truth event that lives in your own database. Measure cost against that, not against pixel fires.
- Cut every conversion by user agent before you touch creative. If most of your traffic arrives in an in-app browser, that’s your test device.
- Assume bots are in your funnel until you’ve proven otherwise. Then exclude them from every number you report.
- Make every failure visible. A form that fails silently gets blamed on the ads, every time.
- Show the gap every week. Platform number next to backend number. The argument ends itself.
When the numbers look too clean, they usually are. Trust the feeling, then go get the receipts.