Half of Our Record Day Was Bots: How I Caught Fake Clicks in Google Ads
It was launch night. I run Google Ads for a diving center in Kaş; we had taken the new website live in the early hours. The next evening I checked the dashboard: 19 conversions, ₺56 blended CPA. Three times the volume of previous days, at half the cost. We had hit our target band of 10-20 contacts per day for the first time — on the very day the site launched.
Two days later, I learned that half of the Display campaign's conversions were not human.
This post is the story of those two days: how the suspicion arose, how my first diagnosis turned out to be wrong, which data delivered the definitive proof, and the three layers we used to fix it. No theory; real queries, real numbers, real feedback at every step.
Suspicion: "Conversions don't come this cheap"
The Display campaign had suddenly lit up: 6-7 conversions a day at a ₺12-25 CPA. While the Search campaign bought the same contacts at ₺64, Display "converting" at a quarter of the price was either a miracle or a lie.
First check: the placement report (detail_placement_view in the Ads API). Placements reporting conversions over 14 days:
| Placement | What is it? | Conversions |
|---|---|---|
| lsmagazineimg.com | Xiaomi/Oppo lockscreen magazine feed | 7 |
| fnyfeds.com | News feed inside a file-sharing app | 2 |
| apdownload.com | APK download page — with 2 conversions on 0 clicks | 2 |
| game sites (5-6 domains) | cheap inventory kids tap by accident | 5+ |
The industry has a name for this: MFA — Made for Advertising. Sites whose only purpose is to show ads and generate clicks. According to the ANA's study, ~15% of programmatic spend flows into this inventory.
My first diagnosis was sharp: "96% of the conversions are fake."
False alarm: The ground-truth test
Then we asked the business owner a single question: "How many calls and WhatsApp messages did you actually get yesterday?"
The answer: 5 calls + 20 WhatsApp = 25 real contacts. The dashboard said 19.
Reality was higher than reported. The counter wasn't inflating — on the contrary, it wasn't counting non-ad channels (organic, Maps) at all. I withdrew my "96% fake" claim.
Lesson 1: A placement signature generates suspicion; ground truth delivers the verdict. You can't declare traffic from a lockscreen feed "definitely fake" — no diagnosis is final until you compare reported numbers with real phone/WhatsApp activity. (We had run the same test on another account: 34 reported WA/day versus ~10 real messages — that's how fraud was proven there. Same test, two opposite outcomes.)
Definitive proof: Minute-level session forensics
But I wasn't at ease. The totals matched; was the credit right, though? Were the contacts Display claimed as its own really coming from lockscreens?
The breakthrough came with this GA4 analysis: I pulled every conversion event at minute precision (the dateHourMinute dimension) and matched it with the engagement time of the session in that same minute. The question was simple: how many seconds did the converting visitor spend on the site?
| Source | Converting sessions | Under 5 seconds |
|---|---|---|
| Search | ~45 | ~10% |
| Display | ~22 | ~50% (mostly 0-1 seconds) |
And one morning, a bomb in the middle of the table: a single session had clicked the WhatsApp button 16 times within one minute. Total engagement: 12 seconds. That is not a human.
The counter-example sat in the same hour: another Display visitor browsed for 8.5 minutes and called by phone. The real ones existed — but they were the minority.
The picture became clear: the total number of contacts was real (Search's long sessions were sending the messages), but half of Display's credit was reflex taps that never turned into a message. The guy trying to close his lockscreen touches the ad, then touches the WhatsApp button while trying to leave the site. The counter says "conversion"; the business's phone says nothing.
I audited the Search side with the same discipline — five tests, five clean results: Google's invalid-click filter in the normal band (4-9% vs Display's 21%), search partners off, healthy click/session ratio, conversions coming from 25-100 second reads, terms and cities consistent with the customer profile. The fraud was channel-specific.
Why it happens: MaxConv's spend-the-budget obligation
The mechanics here are skipped in most guides:
Untargeted Maximize Conversions has a contract: spend the daily budget, maximize conversions. Even when conversions are scarce, the money will be buried somewhere. Where is the cheapest "conversion"? In junk inventory that produces reflex clicks. The algorithm isn't broken — it works as designed; it's just that the success definition we gave it (a naked tel/WA click) can be faked.
An honest answer to those who say "set a tCPA, it'll fix itself": it won't. If junk conversions come at ₺5-15, a ₺50 tCPA sees them as "below-target opportunities" and scales them. tCPA's only difference is removing the obligation to finish the budget; it is not a fraud filter. Two things cut fraud: closing the inventory and making the signal unfakeable.
The fix: Three layers
Layer 1 — Placement blacklist (same day). 94 domains as account-level negative placements: lockscreen feeds, APK pages, game arbitrage. Account-level is critical — it survives campaign tinkering and covers everything including PMax. (We deliberately left real sites like espn.com off the list; one odd conversion doesn't make a site junk.)
Layer 2 — Signal hygiene (next day). The root of the problem was the bidding engine's definition of "success" being a naked button click. We added a single conditional event to the site: qualified_contact — a tel/WA click that fires only if the session is older than 5 seconds. (We picked the threshold from the data: the junk cluster was concentrated at 0-5 seconds; real fast deciders started at 6-8 seconds.) Raw counters stayed untouched for reporting; the Display campaign's bidding target, however, will lock onto this qualified event only. We didn't touch Search — someone who typed their intent and decides in 4 seconds is real; their signal is clean.
The implementation chain was live in 15 minutes: 20 lines of site code (session age via sessionStorage) → a GA4 tag with a custom-event trigger in GTM → a firing test in a real browser (click before 5 seconds: no event; after: event) → verification in GA4 realtime.
Layer 3 — Natural experiment. Whether the two interventions worked would be told not by an attribution report but by three independent counters: conversions reported by Ads + GA4's unique clicker count + the business's real tel/WA declaration, side by side for a week. If real contacts stay flat while Display's report drops → the credit was fake, and money moved to clean inventory. If both drop → the inventory was actually delivering, and rollback is one command away (every change has a before/after record).
The tools I used (practical rundown)
- Google Ads API / GAQL:
detail_placement_view(placement×conversion),metrics.invalid_clicks(what Google's own filter caught),click_view(gclid inventory),customer_negative_criterion(the blacklist itself). The dashboard UI can't answer most of these questions. - GA4 Data API: The real hero is the
dateHourMinutedimension — pinning the conversion moment to the minute and matching it with that minute'suserEngagementDurationis the no-dashboard path to session-level forensics. The Realtime API is also perfect for post-deploy fire-test verification. - GTM + 20 lines of site code: The qualified-contact gate. A filter not in the measurement layer, but in signal generation.
- AI agent (Claude): All of these analyses — GAQL queries, GA4 minute-matching, blacklist mutations, browser fire-tests — ran from a chat interface, in minutes per session. That's what lowered the cost of forensic analysis: the hypothesis → query → evidence loop turns once a minute instead of once per dashboard click-safari.
- NotebookLM: For the literature review after solving the case — I loaded a 24-source reading list on MFA/invalid-traffic/incrementality and cross-checked the methodology. (A note in reverse: two items on NotebookLM's generic fix list — "turn off Unknown demographics", "pause ads at night" — contradicted our data. Our bot attack was at 10:22 in the morning, and real customers were messaging at 00:30 at night. Generic advice doesn't get applied until validated against your own data.)
The verdict: What the experiment said (July 31 reading)
The blacklist went live on the afternoon of July 24. Six full days of data (July 25-30), side by side with the previous seven:
| Metric (Display) | Before (Jul 17-23) | After (Jul 25-30) |
|---|---|---|
| Reported conversions/day | 3.6 | 2.3 (−44%) |
| Clicks | 194 | 292 (+50%) |
| Click→conversion rate | 13% | 5% |
| Reported CPA | ₺29 | ₺53 |
| Google's invalid-click filter | 18% | 22% |
The reading:
The fake-credit thesis was confirmed — by the CPA rising. Clicks grew 50%, yet reported conversions nearly halved. The ₺5-15 "conversion miracle" lived in the blocked lockscreen inventory; once it was cut, Display's real price surfaced: ₺53. On paper the campaign "got worse" — in reality the counter approached the truth for the first time. Someone watching only the dashboard could have rolled the blacklist back for "hurting performance"; without an experiment design, cleanup looks like decline.
The signal gate measured the gap. Over the same six days, qualified_contact (the 5-second session-age gated contact) captured ~90% of raw tel/WA clicks on Search — one more confirmation that Search traffic is human. On Display, the gated event now runs neck and neck with the remaining conversions: the Display contact that survived the blacklist is the kind that passes the gate. With the reflex-click inventory gone, the remaining minority looks real.
The third counter closed too: the business's own declaration. The third independent counter in the experiment design was the business itself. We asked: in the post-blacklist period, how many calls and WhatsApp messages actually came in? The answer was clear: nearly all calls and messages were real, and the numbers matched the report. With real contacts intact while reported conversions fell 44%, what got cut is beyond debate: paper conversions the phone never rang for.
But the rabbit hole didn't close. The invalid-click rate rose to 22%, and new game/arbitrage domains appeared in the placement report — fresh inventory not on the 94-domain list. The difference: these generate clicks but can't generate conversions (mostly 0-conversion). The conversion-faking class, like lockscreen feeds, is closed; the click-burning class keeps rotating. MFA is not a list job, it's a maintenance job: the blacklist has to be a living document.
Where the money went: Over the same two windows, Search campaigns went from 7 conversions/day to 14.8, CPA from ₺121 to ₺81 (a separate intervention — a bid strategy fix — deserves part of that jump; crediting it all to the blacklist would be unfair). But the direction is clear: budget flowed from the channel buying fake conversions to the channel capturing real demand, and the account settled into our target band of 10-20 real contacts per day for the first time without fake credit.
Decisions: The blacklist stays permanent and account-level; a monthly placement sweep went on the calendar. We had deliberately left locking Display's bidding target onto qualified_contact until after the experiment window — moving two variables at once would have made it impossible to know which did what. The moment the experiment closed, the lock went on: the campaign's bidding engine now counts only the qualified contact that passes the session-age gate as "success". (A technical footnote for anyone walking the same path: the only way to install this lock at the action level in Google Ads is a custom conversion goal — campaign-goal settings work at the category level, so they can't separate the gated event from the raw button click in the same category.)
A 10-minute checklist for your own account
- If your Display campaign's CPA is far below Search, don't celebrate — get suspicious.
- Open the placement report; read the names of the top 20 converting placements one by one. If you see "lockscreen/download/game", keep going.
- A placement reporting conversions with 0 clicks = modeled attribution. Take note.
- Pull conversion events in GA4 by
dateHourMinute; look at that minute's engagement time. What share of conversions are 0-5 seconds, per channel? - Ask the business: how many calls/messages actually came in yesterday? Compare with the report. (This is the cheapest and most definitive test.)
- Check
metrics.invalid_click_rate— if Google's own filter removes 15%+ on a channel, what passes through is suspect too. - Are search partners off, and (on search campaigns) the Display network off?
- Is your conversion counting
ONE_PER_CLICK? (That's the setting that collapsed our 16-click bot into 1 conversion.) - Close dirty inventory with account-level negative placements; don't leave it at campaign level.
- Tie your bidding target to an unfakeable signal — not a raw button click; at minimum, a session-age gated event.
Frequently asked questions
How do I detect fake clicks in Google Ads? Look at four signals: a Display campaign CPA far below Search, lockscreen/download/game type domains in the placement report, placements reporting conversions with zero clicks, and 0-5 second engagement times on converting sessions in GA4. For a final verdict, compare reported numbers against the business's real phone and WhatsApp traffic.
What is an MFA (Made for Advertising) site? Sites whose sole purpose is to show ads and generate clicks: lockscreen news feeds, APK download pages, cheap game inventory. According to the ANA's study, roughly 15% of programmatic spend flows into this inventory.
Does a tCPA target block fake conversions? No. If junk conversions cost ₺5-15, a ₺50 tCPA sees them as below-target opportunities and scales them. tCPA only removes the obligation to spend the full budget; it is not a fraud filter. Fraud is cut by two things: closing the inventory and making the bidding signal unfakeable.
Isn't Google's own invalid click filter enough? It catches part of it, not all. In this case the filter was already removing 18-22% of Display clicks, yet half of the conversions still came from bots. If the filter removes more than 15% on a channel, treat what passes through with suspicion too.
The numbers are real account data; the business name is withheld for client confidentiality. The earlier chapter of the same account: the diving center case.
Share this post
Let AI Manage Your Google Ads
AI-assisted Google Ads campaign management over Slack with Hektera Ads. Optimize your performance.
Explore Hektera AdsRelated Posts
How a Dan Brown Style File Beat Google's AI Content Update
How I recovered traffic lost to Google's AI content update using a writing style skill file built from Dan Brown's prose — analysis, file structure, pipeline.
SEO in the AI Era: A Practical Guide to Generative Engine Optimization (GEO)
How is SEO changing in the age of ChatGPT, Perplexity, and AI Overviews? A hands-on guide to GEO tactics that get your site cited in AI answers.
I can do this for your account too
I consult on Google Ads, measurement setup and conversion-focused websites. Let's start with a short intro call.
Write for consultingWeekly Newsletter
New analyses, experiments and case notes, straight to your inbox.