← All work

Case study · GA4 · Admin API · Data quality

A GA4 property that had
never recorded a conversion.

The business made decisions from GA4 every week. Nobody had opened its settings since the old WordPress site was replaced. I did, before trusting a single number in it.

Client
Innovation Campus, coworking in Málaga
Role
Growth engineer (freelance)
Tools
GA4 Admin & Data API, custom MCP server, Cloudflare Workers, Claude Code
When
Aug – Oct 2026
0
real conversions recorded before the audit
11
key events now, one per real action
88%
of “Direct” traffic carrying a bot signature

Summary

Problem

Two data streams, about thirty plugin leftovers, and one key event, “purchase”, for a business that sells nothing online. Real conversions recorded, ever: zero.

Solution

A clean property with one key event per service, channels that describe where people really come from, and bot traffic measured instead of guessed.

A tool first

Clicking through the GA4 admin for every check wasn't going to scale, so I built a small write-capable GA4 Admin connector (an MCP server on a Cloudflare Worker, authenticated with a service account that only has access to this one property). Every change below was made and read back through it.

Cleaning up, carefully

  • A second data stream from the old WordPress plugin. Before deleting it I checked its traffic: zero sessions in 30 days, while the real one was busy.
  • 29 custom dimensions from the same plugin archived (GA4 can't delete them). Two left alone, because they didn't clearly come from the plugin.
  • One key event per service (rooms, terrace, offices, coworking, business registration, general), plus the actions nobody tracked: WhatsApp, phone calls, directions, and the two highest-intent buttons on the site, “Book a tour” and the plan sign-ups, which handed visitors to the booking system with no trace at all.

A fix that silently never applied

Visitors from WhatsApp, Instagram and the newsletter were all landing in “Direct”, because GA4's default channels have no box for them. I created a custom channel group. Eleven days later, a health check showed it had never been applied: a new group isn't primary until you say so, and the API doesn't. I added that call to the connector and set it.

A month later the same group caused the opposite problem: it had only my custom rules, so everything else, organic, paid, direct, fell into “Unassigned”. I rebuilt it with the custom rules first and all of GA4's default channels after them, plus a rule for front-desk QR sign-ups, which turned out to be most of “Unassigned”.

Bots, measured twice

“Direct” was dominated by sessions from countries the business doesn't serve, with almost no engagement and a few seconds each: 88.6% of the channel. Cloudflare's free Bot Fight Mode was switched on. I re-ran the same breakdown eleven days later: 87.8%. It hadn't worked. These bots run JavaScript, which the free tier can't catch. I wrote that down instead of calling it fixed, and planned a phased, geo-targeted challenge rule instead of a paid upgrade.

What finally removed them was a side effect of real consent mode going live: with analytics off until a visitor agrees, bot sessions in “Direct” fell by more than 95%.

Why it matters

Total traffic halved the same week. That isn't a loss, it's the first honest number. I logged it so nobody compares before and after as if they measured the same thing.

“An analytics tool nobody has audited is a set of opinions with a dashboard.”