In my previous article "Refactoring Laravel Visit Analytics: The Path to Version 2.0.0" we took a deep dive into how I rebuilt the "engine" of my analytics. We replaced a bulky Middleware with an elegant chain of analyzers and taught the database to value every single millisecond. But as we know, any architecture is just a skeleton. The real adventure began when I started feeling like a "digital demiurge" and began cranking up the detection rules, turning my package into an uncompromising and very stern sheriff.
You know that feeling when you get a powerful tool in your hands and you want to take everything to the absolute extreme? I got carried away: blocking everything that smelled like "legacy," penalizing the slightest header mismatch, and purging any anomalies with a red-hot iron. At some point, my "sheriff" became so suspicious that he started eyeing even law-abiding citizens.
Today, I’ll tell the story of how excessive strictness and a belief in the "ideal internet" almost turned my site into a closed club for an elite few owning the latest iPhones. We’ll analyze two real visits from the past that forced me to hit the brakes and completely rethink the very philosophy of Bot Score. This is a tale of how I taught my code to distinguish a cunning bot from a real human being stuck in the digital Paleozoic.
Stage 1: Dictatorship and the Vietnamese "Ghost" on Windows 98
It all started when I decided to tighten the screws as much as possible. Windows XP, Windows 2000, and old versions of IE went straight to the penalty list in my config. I was full of youthful (adjusted for experience) maximalism: in 2026, no one in their right mind would be surfing the web on 20-year-old hardware. I was certain I had set the traps perfectly.
And then, a guest from Vietnam pops up in the logs.
At first, the system went into a stupor. My blacklist had XP, but I simply forgot that Windows 98 even existed! It was a "blind flight"—the bot was using a system so ancient it was off the radar of my primary settings. However, the updated logic of version 2.0.0 and the analyzer pipeline didn't fail. Even without finding a direct ban on Win98, the system cross-referenced the fossilized OS and the dead browser.
The result? The cumulative weight of evidence broke through the psychological barrier. Here’s what that interrogation protocol looked like in the database:
{"ip_address":"14.177.144.0","user_agent":"Opera/8.15 (Windows 98; fi-FI) Presto/2.9.180 Version/12.00","url":"https://oleant.dev/uk/blog/mii-texnicnii-stek-iak-stvoriuvati-sucasni-ta-funkcionalni-vebsaiti","bot_score":"70","is_bot":"1","bot_reasons":["obsolete_os","obsolete_browsers"],"bot_evidence":{"os_signature":"Windows 98","browsers_signature":"Opera/8","analyzed_at":"2026-05-09 17:46:14"}}
Despite the "intelligent" behavior—the guest from Vietnam arrived via a direct link and was supposedly thoughtfully reading an article in Ukrainian about my tech stack—the verdict was harsh: Bot.
In 2026, the probability of a living person reading an IT blog via Opera 8.15 running on Windows 98 is near zero. It’s either a very specific script or an old botnet that hasn't been updated for so long it turned into a digital museum exhibit itself. My "digital customs" worked: the guest was classified as a bot, and their visit was annulled in the statistics.
Stage 2: My Son, a Sony Ericsson, and the "Amnesty"
My faith in the infallibility of rigid algorithms finally crumbled when my son visited the site. As a connoisseur of tech-retro, he decided to stress-test my blog using a rare Sony Ericsson running Opera Mini.
For a system I had just "loaded up" to fight digital pests, this visit looked like a typical clone attack:
Strange IP: The request came through Opera proxy servers (Germany, Teledata), which is often characteristic of botnets.
Missing Referer: Old mobile browsers saved every byte and often didn't transmit the referer header.
Suspicious Signature: J2ME/MIDP in 2026? To the code, this sounds like "I'm a Python script pretending to be a grandfather."
But when I opened the log, I didn't see a ban; I saw a "yellow card":
{"ip_address":"185.231.75.0","user_agent":"Opera/9.80 (J2ME/MIDP; Opera Mini/8.0.35626/191.396; U; de) Presto/2.12.423 Version/12.16","bot_score":"50","is_bot":"0","bot_reasons":["missing_referer","single_page_scan"],"bot_evidence":{"ptr_record":"host-185-231-75-1.teledata-fttx.de","visit_depth":"1_page_only","referer_source":"direct_navigation"}}
The score froze at the 50 mark. The system "squinted," noted the missing referer and the strange source, but didn't cross the "Rubicon" of 70 points. Why? Because in version 2.0.0, I implemented a "mercy coefficient" by separating the weights.
How it works in the config:
I’ve separated ancient browsers into a category of "functionally extinct," but assigned them a moderate penalty. Take a look at this configuration snippet:
/**
* List of browsers considered "extinct" for humans in 2026.
* MSIE, old Opera on the Presto engine — these are often used by cheap parsers.
*/
'target_browsers' => [
'MSIE', // Internet Explorer 10 and below
'Trident/', // Internet Explorer 11
'Opera/8', // Ancient Opera
'Opera/9',
],
'weights' => [
/**
* Penalty for fossilized OS and browser.
* Combined (35+35), they hit 70 — the bot detection threshold.
*/
'obsolete_os' => 35,
'obsolete_browsers' => 35,
],
The Fine Line Between "Retro" and "Bot"
This approach is exactly what saved my son's visit. His User-Agent showed Opera/9.80, which didn't fall under the rigid Opera/8 or Opera/9 filter. The system realized: we are looking at something very old (J2ME), but it’s not on my list of "guaranteed dead."
The Result:
BANNED
Vietnamese bot (Win 98 + Opera 8.15) received 35 for the OS and 35 for the browser. Total: 70. BANNED.
PASSED
Son on Sony Ericsson (J2ME + Opera 9.80) received a penalty for missing referer and suspicious activity, but only scored 50. PASSED.
This is humanity expressed in code. We don't just strike blindly. We give the "ghosts of the past" a chance if they behave decently. But the moment a retro gadget decides to scan your ports — the weight sum will instantly send it to the ban list.
The Solution: Smart Filters and "Anomaly" Logic
These two cases helped me calibrate the "threshold of pain." In version 2.0.0, the analyzers stopped being mere penalty calculators — they now engage in a meaningful dialogue.
1. Contextual Verification (Mitigation)
We still penalize for an old OS, but the system now understands historical context. If the browser matches its era (like Opera Mini on a Sony Ericsson), the penalty will be moderate. This allows retro-geeks and owners of niche gadgets to remain in the "green zone" (up to 70 points).
2. Anomaly Detector (Instant Ban)
However, there are things the system never forgives. I call this "digital schizophrenia." These are cases where the User-Agent header tries to sit on two chairs from different decades.
- The "Guest from the Future" Anomaly: When Windows NT 10.0 (modern Windows 10) pops up in the logs, but the browser claims to be MSIE 6.0 or an old Opera 8. In 2026, no one is going to install a 20-year-old browser on modern hardware that can't even render Google properly. This is a 100% bot mimic that simply grabbed an old preset and forgot to update the OS string.
- The "Artifact" Anomaly: The reverse situation — modern Chrome 140+ on Windows NT 6.1 (Windows 7). Browser developers ended support for "7" long ago, and seeing a fresh build there is a sure sign that a script is trying to appear "modern" while using an old server config.
3. The 70-Point Threshold: Our "Rubicon"
For everyone else, 50 points is a "yellow card." We observe, we record evidence, but we don't close the door. This gives people with specific privacy settings or rare software a chance to remain legitimate guests. But should such a guest show the slightest aggression — the threshold is instantly breached.
Epilogue: Data Purity vs. Digital Inquisition
Developing laravel-visit-analytics forced me to look beyond just writing code. It taught me an important rule: behind every IP address, behind every strange User-Agent string, there is a story. Whether it's an old scout-bot "cobbled together" somewhere in Hanoi, or my son deciding to breathe life into a vintage Sony Ericsson.
My goal in version 2.0.0 isn't to build a perfect digital prison with a checkpoint at every turn. My goal is to create a smart, contextual filter. One that ruthlessly sifts through noise and trash but leaves the door slightly ajar for exceptions. Because it is in those exceptions — the people with old phones, the retro-enthusiasts, and the privacy paranoids — that the spirit of the real, living internet we once fell in love with still lingers.
What's next?
The foundation is laid; the architecture has been battle-tested against real bots and relatives. Now, the main task is to make this data visual. I plan to move towards visualization so that all these "evidences" and "suspicion scores" turn from dry JSON strings into clear charts and dashboards. Most likely, Laravel Filament will be my faithful companion in this, but in the world of development, there is always room for surprises and new challenges.
So stay tuned — there's plenty more to explore "under the microscope"!
For further actions, you may consider blocking this person and/or reporting abuse
