Bot traffic filtering for links: what gets flagged and what slips through
Bot traffic filtering for links runs 3 tests: known crawlers, empty user agents and prefetch headers. See what a flagged click changes and what slips through.
Muzahid Maruf, FounderUpdated
On this page
Explore with AI
Opens this article inside the chosen assistant with a ready-made prompt.
Bot traffic filtering for links decides, request by request, whether a hit on a short link counts as a click.
TrackRev flags a request when its user agent matches the isbot 5.2.1 pattern list, when the user agent is empty, or when a purpose header marks it as a prefetch.
A flagged request still gets its 302 redirect, is stored with is_bot true, and stays out of every report.
That removes Googlebot, Slack and Facebook preview fetchers, curl and python-requests scripts, and Chrome's speculative loads. A scanner with an ordinary Chrome 120 user agent passes, and finding those takes a look at your own click data.
Key takeaways
- TrackRev flags a click as a bot when the user agent matches isbot 5.2.1, is empty, or carries a prefetch header, and still sends the 302 redirect.
- Flagged clicks leave dashboard totals, partner counts and the 30-day attribution window, and bots=include on the clicks API brings them back.
- An ordinary Chrome 120 string passes the filter, so look for clicks that bunch within a second and never produce a pageview.
- Credited revenue ignores phantom clicks, but conversion rates carry them, so a $0.25 per-click payout pays for every fake one.
Where non-human clicks come from
The Media Rating Council's invalid traffic addendum (June 2020 update) calls what list-based filtering finds general invalid traffic: bots and spiders, non-browser user agents, pre-fetch and pre-render traffic, and known data-center traffic.
Sophisticated invalid traffic takes advanced analytics and human review. The standard covers ad impressions, and the split carries over to links.
| Source | Identified by | Caught by a user-agent list |
|---|---|---|
| Search crawlers | Googlebot/2.1 in the user agent. Google publishes reverse DNS names and IP ranges to check the claim | Yes |
| Chat and social preview fetchers | Slackbot-LinkExpanding 1.0 from Slack and facebookexternalhit/1.1 from Meta | Yes |
| Browser prefetch and prerender | A Sec-Purpose header set to prefetch or prefetch;prerender in Chrome | No, a header test catches it |
| Scripts and HTTP libraries | curl/8.4.0 and python-requests/2.31.0 default strings | Yes |
| Headless browsers | HeadlessChrome/120.0.0.0 in the string unless the script overrides it | Yes, until the string is changed |
| Email security scanners | Microsoft Defender for Office 365 Safe Links scans URLs in mail flow and verifies them again at click time | Only when the scanner announces itself |
| Click farms and residential proxies | Ordinary browser strings from consumer networks | No |
Preview fetchers and email scanners
Slack's robots page says Slackbot-LinkExpanding 1.0 fetches links posted into channels with HTTP Range headers and caches responses across the service for around 30 minutes. Meta documents facebookexternalhit/1.1 as the crawler behind previews on Facebook, Instagram and Messenger.
Mailchimp's bot activity page names anti-spam filters at email providers, Apple's Mail Privacy Protection and link preview generators as tools that often click links or open emails before the recipient does.
Its bot-filtered email click data starts on August 10, 2025, and it hides flagged activity without deleting it, the design TrackRev uses. The newsletter guide and the Slack and Discord guide go deeper on those channels.
How bot traffic filtering for links works in TrackRev
- A missing or blank user-agent header is flagged.
- The user agent is checked against isbot 5.2.1, the version TrackRev's lockfile resolves. It is an open-source list of 209 patterns built from public crawler lists such as monperrus/crawler-user-agents and user-agents.net. It matches names like Googlebot and HeadlessChrome, any string where bot ends a word, and any string containing http, which is how Googlebot, Slackbot-LinkExpanding and facebookexternalhit point to their documentation.
- The headers x-purpose, purpose and sec-purpose are read, and a value containing prefetch flags the request. Chrome sends
Sec-Purpose: prefetchfor a Speculation Rules prefetch andprefetch;prerenderfor a prerender, and MDN says a server can treat such requests differently when counting visits.
| User agent sent | Verdict |
|---|---|
| Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html) | Bot |
| Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots) | Bot |
| facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php) | Bot |
| curl/8.4.0 | Bot |
| python-requests/2.31.0 | Bot |
| Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/120.0.0.0 Safari/537.36 | Bot |
| Empty header | Bot (TrackRev's own test; isbot alone returns false) |
| Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 | Counted as a person |
| Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1 | Counted as a person |
Results of TrackRev's check, isbot 5.2.1 plus the empty-header test.
What a flagged request changes
| Part of TrackRev | What happens to a flagged request |
|---|---|
| Redirect at /r/slug | 302 to the destination, because a person can sit behind a preview or a scan; click stored with is_bot true, no rate limit and no de-duplication |
| Dashboard, channel and per-link totals | Counted for unflagged clicks only |
| Attribution engine | Credits unflagged clicks inside the attribution window, 30 days by default |
| Partner click counts | Unflagged clicks only |
| click.created webhook | Not sent |
| Retargeting pixel page | Skipped, so a plain 302 |
| Pixel endpoints /api/collect and /api/identify | 200 with skipped set to bot, nothing written |
| Pixel endpoints, unflagged requests | 429 above 300 requests a minute per IP on /api/collect and 30 on /api/identify, 413 above a 16 KB body |
Behavior as of October 2026.
Why flagged clicks are kept
Google Analytics excludes known bots automatically, using Google research and the International Spiders and Bots List kept by the Interactive Advertising Bureau. The exclusion cannot be switched off, and Google does not report how much it removed.
TrackRev keeps the rows. The clicks API leaves them out unless you pass bots=include, and the CLI has the same switch, so you can measure your own bot share.
The API needs a paid plan and a secret key, and --all stops after 200 pages of up to 500 clicks, so on a large workspace add --link with one link ID.
trackrev clicks --bots --all --json \
| jq '.clicks | group_by(.is_bot) | map({is_bot: .[0].is_bot, requests: length})'What a user-agent list cannot see
The isbot README says the package identifies good bots that announce themselves and does not try to recognize malicious bots or programs posing as real users.
TrackRev stores each click's IP address and user agent but sets the flag from the three tests alone.
It checks no IP ranges, runs no timing or rate analysis and does not de-duplicate repeat requests, so a script that requests a link 10,000 times with a Chrome 120 string adds 10,000 counted clicks.
How much bot traffic to expect
For scale, Imperva's 2025 Bad Bot Report put automated traffic at 51% of all web traffic and bad bots at 37%, and its 2026 edition says bots now make up the majority.
Those figures cover web traffic as a whole and say nothing about your links, so measure your flagged share with the command above.
How to spot the bot clicks that got through
The clicks API returns a timestamp, city, device, browser, referrer and visitor ID per click, enough to catch bursts within a second of a send and every link in a message clicked from one city.
The visitor journey, in the dashboard or through trackrev visitors journey, lists pixel events after a click, so a click with no pageview behind it stands out.
| Click id | Time (UTC) | Link | City | Browser and OS | Pixel pageview |
|---|---|---|---|---|---|
| 90417 | 08:00:01 | /r/launch-a | Ashburn | Chrome on Windows | none |
| 90418 | 08:00:01 | /r/launch-b | Ashburn | Chrome on Windows | none |
| 90419 | 08:00:02 | /r/launch-c | Ashburn | Chrome on Windows | none |
| 90420 | 08:00:02 | /r/launch-d | Ashburn | Chrome on Windows | none |
| 90431 | 08:07:41 | /r/launch-b | Austin | Safari on iOS | 08:07:43 |
| 90466 | 08:19:15 | /r/launch-a | Berlin | Chrome on macOS | 08:19:16 |
| 90589 | 09:02:30 | /r/launch-c | Toronto | Firefox on Windows | 09:02:33 |
Invented log for 4 links sent at 08:00:00, every row with is_bot false. The first 4 rows look like software: all 4 links in 2 seconds, one city, no pageview.
Worked example with made-up numbers
A link logs 2,000 requests in a week and the filter flags 300, so 1,700 clicks are counted. If 340 of those are gateway scans with browser strings, 1,360 are people. With 34 signups, the dashboard shows 34 / 1,700 = 2.0%, the true rate is 34 / 1,360 = 2.5%, and a counter with no filter would show 34 / 2,000 = 1.7%. Cost per click and revenue per click shift the same way.
Revenue as the second filter
For each paid order, the attribution engine credits that visitor's unflagged clicks inside the 30-day default window under last-touch, first-touch or linear.
A scanner's click carries its own visitor ID, so it cannot take credit for someone else's sale, and credited revenue per channel stays clean even when click counts are not. Revenue attribution shows the join.
Click-based payouts are where phantom clicks cost cash. At $0.25 a click, 10,000 scripted requests earn $2,500 for someone who never sold anything.
TrackRev's affiliate commissions are calculated on payments synced from Stripe, Polar, Lemon Squeezy and Paddle, a refunded or disputed charge takes its commission back out, and a program's hold period (0 to 180 days, 0 by default) delays payout past the refund window.
The affiliate fraud guide covers the attacks that do complete a purchase.
When a header and list filter is not enough
For paid ads, the platform's own filter is the record.
Google Ads says it removes invalid clicks from metrics and billing and credits the next invoice when it finds them later, so the ad platform and a link tool report different click totals.
For attacks on a site, put a bot-management product such as Imperva's Advanced Bot Protection in front of it.
In TrackRev the link tracking redirect sets the flag, first-party tracking covers the server-side capture behind it, and the server-side versus client-side guide explains why a check on the server survives blockers.
Flagging runs on every plan, and pricing lists the rest.
| Plan | Price | Links and tracked events | Clicks API and revenue figures | Commission tracked a month |
|---|---|---|---|---|
| Free | $0 | 50 links, 1,000 events a month | No | None |
| Starter | $39 a month | Unlimited | Yes | Up to $10,000 |
| Growth | $99 a month | Unlimited | Yes | Up to $100,000 |
| Scale | $199 a month | Unlimited | Yes | Unlimited |
Plan limits as of October 2026. Bot flagging runs on all 4.
Found this useful? Share it.
Frequently asked questions
- No. Dashboard totals and the 25 most recent clicks on each link page show unflagged clicks only. Flagged rows come back from GET /api/v1/clicks?bots=include or from trackrev clicks --bots, and both need a paid plan.
- Email gateways such as Microsoft Defender Safe Links, anti-spam filters and chat previews request a URL on delivery or posting. Declared ones are flagged. One that sends a Chrome 120 string is not, so look for every link in a message clicked from one city in the same second.
- Run a reverse DNS lookup on the IP from your logs and confirm the hostname ends in googlebot.com, google.com or googleusercontent.com, then run a forward lookup and confirm it returns the same IP. In Google's example, 66.249.66.1 resolves to crawl-66-249-66-1.googlebot.com, which resolves back to 66.249.66.1. Google also publishes JSON range files such as common-crawlers.json. TrackRev does not run this check.
- The README gives no accuracy figure for the main pattern. For the less accurate fallback pattern, used where regex lookbehind is unsupported, its tests accept 1% false positives and 75% bot coverage.
- Click fraud is the deliberate part. Google Ads lists accidental clicks, automated traffic and manual clicks that raise costs or inflate publisher profits as invalid clicks. Crawlers and previews are harmless automation, while click farms and scripts aimed at payouts are fraud, and a header test cannot tell them apart.
- Each system applies its own filter at its own time. Google can remove invalid clicks after the fact, while a link tool filters when the request arrives.

Written by
Founder, TrackRev.io & Contant.io
Muzahid Maruf is the founder of TrackRev.io and Contant.io. He writes about marketing attribution, link tracking, and revenue analytics for SaaS teams.
Writes about Marketing attribution · Link tracking · Revenue analytics · SaaS growth
Stop guessing where your revenue comes from.
Set up TrackRev in about five minutes. The free plan covers 1,000 events a month, no card needed.
Start free