Search “Singapore bot traffic” and you’ll land on a Google Analytics community thread that’s become a rite of passage: a site owner watching GA4’s real-time report fill up with hundreds of “users” from Singapore, out of nowhere, and asking the two questions everyone asks next — is this ghost spam, or an actual bot attack, and either way, how do I make it stop?

That distinction matters more than it looks. Ghost spam never touches your site at all — it’s a fake hit fired straight at your GA measurement ID, so your real server or CDN logs show nothing unusual, and no firewall rule will fix it (you need a GA-side hostname filter instead). Real bot traffic actually requests your pages, which means it shows up in your own logs too — and that’s the case a firewall can do something about.

We spent a full investigation cycle on a WordPress site that had the second kind, and the fix that actually worked wasn’t the one guides usually recommend.

The advice everyone gives

Articles on this topic — this one from webnots is representative — point out (correctly) that Singapore hosts a huge concentration of cloud infrastructure, so it’s a natural source of crawler and scraper traffic. The recommended fix is almost always some form of country block: a Cloudflare rule, a WAF rule, or a hosting-panel geo-block, usually built from a standard “IP ranges by country” list.

We did exactly that. It was the right first move, and it worked — the firewall counters showed real packets being dropped, thousands of them, every day.

Singapore kept showing up in GA at close to the same volume anyway.

The traffic that should have been blocked, wasn’t

The instinct at that point is to assume the block is misconfigured. It wasn’t. The actual explanation only shows up if you stop trusting either data source at face value and go straight to the logs.

The key fact: analytics only records requests that actually load. A request a firewall drops never reaches WordPress, never fires the tracking script, and never becomes a GA session. So whatever GA is counting as “Singapore,” by definition, is traffic that is currently getting through every rule in place — the real question isn’t “why isn’t the block working,” it’s “which specific IPs is GA calling Singapore, and why aren’t they in the block’s data set.”

Pulling a broad, unbiased sample of live 200-response IPs and geolocating them answered part of it. A handful genuinely were edge/cloud infrastructure that commercial IP-intelligence services tag as Singapore, because Singapore is the default regional hub a lot of edge networks and CDNs use to cover Southeast Asia — the address block gets commercially geolocated to wherever the provider’s nearest point of presence is, which often has nothing to do with which country actually holds the RIR delegation for it. A country block built from official regional registry data (ipdeny.com and similar) and a GA label built from commercial IP-intelligence data are two different classification systems, and they don’t always agree on where a given block of addresses “is.” Switching from a country-label block to a route-table lookup against that traffic’s actual announced network closed that specific gap.

It barely moved the number.

The traffic that was never going to be “in Singapore” at all

The remaining volume didn’t belong to any cloud or edge network — geolocating it landed on real consumer ISPs, spread across dozens of countries, no two requests from the same IP twice. That’s the signature of a residential-proxy bot network: instead of running scrapers from its own datacenter IPs (cheap to detect and block), the operator routes each request through a different real household internet connection, harvested from ordinary consumer devices. Every request looks, at the network level, exactly like a genuine visitor on their home Wi-Fi — because it is one, just carrying traffic it didn’t originate.

That’s what made it invisible to every network-level defense we had. A country block can’t catch it (the IPs are correctly geolocated, just not to Singapore — GA’s per-session “Singapore” label turned out to be a mislabeling artifact layered on top of a completely different traffic source). An ASN block can’t catch it (there’s no single ASN — it’s rented address space across residential ISPs worldwide). Even an IP ban is close to useless, because the dominant pattern was one request per IP, ever; by the time any reactive block notices an IP, that IP has already made its only request and moved on.

What finally worked was giving up on blocking by address at all and matching the traffic’s behavior instead: the overwhelming majority of these requests shared one exact browser fingerprint and arrived with no referrer — a pattern a real visitor essentially never produces at that scale, but a scripted client reusing the same spoofed user-agent across thousands of borrowed IPs produces constantly. Intercepting on that signal, before WordPress even finished loading the page, is what actually collapsed the “Singapore” number — not the network-level fix above.

The broader lesson

“Singapore” in your analytics dashboard usually isn’t telling you where an operator sat. Sometimes it’s a cloud or edge network’s commercial geolocation disagreeing with official registry data. Often, once you dig further, it’s not a network location problem at all — it’s a residential-proxy botnet that was never going to have a coherent network fingerprint to block in the first place.

A country or ASN block only ever inherits the limits of whichever list built it, and against genuinely residential traffic, no list — however current — will ever be complete. The durable fix isn’t a bigger country list. It’s dropping the assumption that “where the request came from” is even the right question, and matching what a real request from that address space actually looks like instead.

This is the same investigation that led to Lubber, now live on WordPress.org — more of what came out of it in future posts.