Guides · Updated July 2026
How to Detect Bot Traffic in Your Ad Campaigns
You can't see bots in Google Analytics, and your ad platform grades its own homework. Detecting invalid paid traffic requires click-level signals collected on your own landing pages. These are the ones that matter.
Why aggregate analytics can't do this
A campaign with 30% bot traffic doesn't look broken in aggregate — it looks like a campaign with a mediocre conversion rate. Averages absorb the evidence. Detection has to happen per visit, at the moment the click lands, with the click identifier (gclid) still attached — that's the only way to tie a bad visit back to a specific paid click you can dispute or exclude.
The signal stack
1. Automation fingerprints (near-certain bots)
Automated browsers leak their nature into the page environment:
navigator.webdriverset — the WebDriver spec requires automation frameworks to announce themselves- Headless-browser markers (e.g.,
HeadlessChromein the user agent) - Framework artifacts: Selenium, PhantomJS, Nightmare leave detectable globals
- No user agent at all, or an empty
navigator.languages - A reported screen size of 0×0 — real devices always have a screen
Any one of these on a paid click is effectively conclusive: real customers don't browse with WebDriver on.
2. Synthesized input (bots driving real browsers)
The hardest class of bot hides the fingerprints above entirely: stealth automation (CDP-driven Chrome, patched Puppeteer) pilots a real, unmodified browser — genuine user agent, real screen, webdriver flag hidden. What it can't cheaply fake is the physical trail of a human hand. Synthetic events pass the browser's isTrusted check, but they skip the mess that surrounds real input:
- Teleport clicks: a human's cursor wanders toward a button, firing dozens of mousemove events on the way. A dispatched click arrives with zero mouse movement ever observed — the cursor teleported.
- Inhuman reaction time: a first input landing under ~150ms after navigation start is faster than a person can render, read, and decide.
- Wheel-less scrolling: humans scroll with a wheel, trackpad, touch, or keys.
scrollTo()moves the page with none of them.
Two honesty notes: these should be measured as aggregate counters (event counts and first-input timing — never keystroke content or cursor trajectories, which would be surveillance, not detection), and they're probabilistic — treat one anomaly as suspicious and let anomalies corroborate each other before calling a visit a bot.
3. Network origin (datacenter and proxy IPs)
Real shoppers connect from residential and mobile ISPs. Clicks from hosting providers — AWS, Hetzner, DigitalOcean and the like — are scripts, scrapers, or click farms routing through rented servers. Proxy and VPN exit nodes are weaker signals (privacy-conscious humans exist) but combine badly with other flags. IP-to-ISP resolution has to happen at collection time, because the click's origin can't be reconstructed later.
4. Behavior (the tiebreaker)
Between "certain bot" and "certain human" sits traffic you classify by what it does:
- Interaction: real visitors click, scroll, or touch. Bots overwhelmingly don't.
- Time on page: sub-second visits with zero interaction are a classic invalid-click signature — the click was the point, not the page.
- Combinations: a datacenter IP plus a one-second bounce is a much stronger call than either alone.
Three buckets beat a binary
Honest detection admits uncertainty. A practical scheme classifies each visit as:
| Class | Criteria | Use |
|---|---|---|
| Bot | Any automation fingerprint, two or more corroborating input anomalies, or hosting-provider IP with near-zero engagement | Dispute evidence; exclusion targeting |
| Suspicious | Proxy/VPN origin, a single input anomaly, or very short visits with no interaction | The honest gray zone — track it, don't over-claim it |
| Human | Passed all checks; interacted or stayed engaged | Your real audience baseline |
The bot/suspicious split also gives you an honest wasted-spend range: confirmed bots × CPC as the floor, plus suspicious clicks as the ceiling — a range you can defend, instead of a single scary number you can't.
What to record per visit
Detection without evidence is trivia. To act on what you find — exclusions, or an invalid-click claim — each flagged paid click needs: timestamp, click ID (gclid/gbraid/wbraid), campaign, IP address, ISP and hosting flag, device, the specific signals that fired, and time-on-page/interaction. Keep at least 60 days — Google's dispute window — and mind privacy: IP retention should be scoped to flagged paid clicks and time-limited, not a blanket log of every visitor.
All of this, from one line of JavaScript
BotAudit runs this exact signal stack on every visit, classifies it as human, suspicious, or bot, and keeps claim-ready evidence for 60 days. Free plan available.
Start Free