From 6e213539ea01163bc7ecaf76805928faa077c043 Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Fri, 13 Mar 2026 09:07:49 +0100 Subject: [PATCH] feat: filter headless browsers and zero-screen bots client-side --- CHANGELOG.md | 1 + public/script.js | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f332f3..1487e8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), - **Traffic sources are no longer over-counted.** When a visitor arrived from Facebook (or any external source) and browsed multiple pages, every page was credited to Facebook instead of just the first. Now only the landing page shows the referrer, giving you accurate traffic source numbers. - **UTM attribution now works correctly.** Visitors arriving via campaign links (e.g. from Facebook Ads, Google Ads, or email campaigns) now have their traffic source, medium, and campaign properly recorded. Previously, this data was accidentally lost before it reached the server. - **More ad tracking clutter removed from page paths.** Facebook ad parameters and click IDs from various platforms are cleaned from your page URLs so your Top Pages stay tidy. +- **Better bot detection.** Automated browsers (used by scrapers and testing tools) and bots with no screen dimensions are now filtered out before they can send events, keeping your visitor counts cleaner. ## [0.15.0-alpha] - 2026-03-13 diff --git a/public/script.js b/public/script.js index f265e4e..8ccef86 100644 --- a/public/script.js +++ b/public/script.js @@ -13,6 +13,11 @@ return; } + // * Skip headless browsers and automated tools (Puppeteer, Playwright, Selenium) + if (navigator.webdriver) { + return; + } + // * Get domain from script tag const script = document.currentScript || document.querySelector('script[data-domain]'); if (!script || !script.getAttribute('data-domain')) { @@ -321,6 +326,11 @@ height: window.innerHeight || window.screen.height, }; + // * Skip bots with no screen dimensions (0x0) + if (screenSize.width === 0 && screenSize.height === 0) { + return; + } + const payload = { domain: domain, path: path,