GA4 Ghost Referral Spam: How to Spot a Fake Traffic Spike Before It Reaches a Client Report
On 3 September 2026 our own Google Analytics property reported 510 users in a day. The normal number is about 15. Nothing had launched, nothing had been posted, and nobody had linked to us. The traffic was fake, none of it ever reached our servers, and if we had been an agency reporting that property to a client, a 25x uptick would have gone into the monthly report with a straight face.
This is ghost referral spam. It is old, it is boring, and it is still one of the fastest ways to put a wrong number in front of a client. Here is exactly what it looked like on our property, how to tell it apart from a real spike within about two minutes, and what you can and cannot do about it in GA4 today.
What the spike looked like
The day in question, against a property that usually sees 15 people:
- 3,040 events, 510 users, 519 sessions.
- 488 of those sessions carried a single referrer,
trafficheap.cc. - 100 percent of them were reported from Seychelles.
- 100 percent of them landed on
/. - All of them were recorded under the hostname
metricswatch.com, the bare apex. Our marketing site is served atwww.metricswatch.com. The bare apex is not a hostname we serve anything on.
That last line is the one that settles it. A visitor cannot generate a pageview on a hostname where no page exists.

The four tells
Real traffic is messy. Fake traffic is uniform, because it is generated by a loop. Four things showed up together here, and any two of them together are enough to make you check.
One referrer doing all the work. A real spike from a mention, a newsletter, or a link comes with a tail: some direct, some search, some from wherever the link was shared onward. Here one domain accounted for 488 of 519 sessions.
One country, at 100 percent. Not "mostly." Exactly one. Real audiences, even very local ones, leak a few percent across borders.
One landing page, at 100 percent. Ghost hits are usually fired at / because the sender does not know or care what pages you have.
Sessions and users almost equal. 510 users producing 519 sessions is 1.02 sessions per user. Every hit is a brand new person who visits once and never returns, because every hit carries a freshly invented client ID. Your real number is above that, and you know what your real number is.
The fifth tell, when you can get at it, is the hostname. Add Hostname as a secondary dimension in a report or as a dimension in an exploration. If a hostname appears that you do not serve, those rows never touched your site.
Why "ghost" and not "bot"
A bot is a program that actually loads your pages. It hits your server, your logs record it, and your tag fires because a browser ran your JavaScript. Annoying, but real, and GA4 filters a lot of it for you.
Ghost traffic never touches you at all. The events are sent straight to Google's collection endpoint with your measurement ID attached, which is a public string sitting in the source of every page you serve. Whoever is sending them has scraped that ID and is pointing a script at Google, not at you. The hostname, the referrer, the country, and the landing page are all just fields in that payload, and the sender fills them in with whatever they like. That is why the hostname can be a domain you do not run: nobody checked, because there was nothing to check.
The usual motive is that you go and look. The referrer is a domain the sender wants you to visit, and the whole campaign costs them nothing per property, so they aim it at thousands at once.
Confirm it against something that only fires on real page loads
This is the step that turns a suspicion into a fact you can put in an email, and it takes a minute.
Ghost hits are sent to one endpoint. They cannot appear anywhere else, because nothing else happened. So look at a second source that can only record a real page load:
- A second analytics tool on the same site. We run PostHog alongside GA4. It recorded 16 people on the marketing site that day, and no bare-apex hostname at all, on any day.
- Server logs or your CDN's traffic panel. 488 requests to
/from one place leaves an obvious mark. Its absence is just as informative. - Search Console, if the claimed traffic is organic rather than referral.
Two sources that disagree by 30x are not two opinions. The one that requires a real request to your infrastructure is right, and the one that will accept any payload sent to it is wrong. Write the comparison down; it is the whole explanation to a client, in two numbers.
Fixing it in GA4
Since June 2026 GA4 has a hostname data filter, which is the right tool and comes with a real limitation. It lives in Admin, under Data collection and modification, then Data filters, alongside the internal traffic and developer traffic filters.
It excludes, it does not allow. Universal Analytics let you write an include filter that kept only your own hostnames, which blocked every future spammer automatically. The GA4 version today takes a list of domains to drop, with no regular expressions, so you name each bad hostname as you find it. Google has signalled that an include option is coming; it is not there yet. Until it is, this is maintenance, not a one-time fix.
It is not retroactive, and it is permanent going forward. Filtered data is never processed, never appears in reports or BigQuery, and cannot be recovered. Everything already in your property stays dirty forever. Create the filter in Testing mode first, where GA4 keeps collecting and tags the affected rows with a "Test data filter name" dimension so you can see exactly what you are about to throw away, and leave it there for a few days before switching it to Active.
The unwanted referrals list will not help here. Admin, Data streams, Configure tag settings, List unwanted referrals only changes how your own tag attributes a visit. Ghost hits do not run your tag, so there is nothing for that setting to act on. It is the right tool for stopping your payment processor from appearing as a referrer, and the wrong one for this.
What to do about the history
Because filters only work forward, the day is still in the property and will be in the property in a year. Handle it at read time instead.
Put a hostname condition on the reports themselves: a comparison in a standard report, or a filter in an exploration, set to hostname exactly matching the domains you actually serve. That is an allowlist, it works on historical data, and it is what you should be building client reports on anyway. If you send scheduled reports, make sure the filter is on the saved report and not just on your screen while you look at it.
Then annotate the day. When somebody pulls a year-over-year comparison next September, the spike is going to come back and somebody is going to ask about it.
The checklist
- A traffic number is far above baseline. Do not report it yet.
- Break it down by referrer, country, and landing page. If any one of those is at or near 100 percent, keep going.
- Add hostname as a dimension. Anything you do not serve is fake.
- Check a source that only records real page loads. If it saw nothing, you have your answer.
- Add a hostname data filter in Testing mode, watch it for a few days, then set it Active.
- Filter your reports by your real hostnames so history reads correctly too.
- Annotate the day, and tell the client before they find it themselves.
Common questions
Does ghost spam affect my rankings or my site?
No. It never reaches your site. The only damage is to the numbers in your analytics property, and to whatever decision somebody makes from them.
Can I stop it at the source?
Not really. Your measurement ID is public by necessity; it ships in the page. GA4's Measurement Protocol requires an API secret for server-side events, which raises the bar, but the volume of this that still lands in properties every week is the answer to whether the bar is high enough. Treat it as weather, and filter.
Why did the spike show up in GA4 but not in my other tool?
Because your other tool records events from code running in a real browser on a real page, and GA4 also accepts events posted directly to its endpoint. That difference is a feature, and it is the same difference that lets you prove the spike is fake.
How often should I be checking for this?
Once per reporting cycle, before the report goes out, is enough for most agencies. The check that matters is not a scheduled audit. It is noticing that a number moved and asking why before you send it.
Who is behind Metrics Watch?
A small company, deliberately. It has been reporting on marketing data since 2015, it is run by its owner, and support emails get answered by the person who can actually fix things.
The part that actually costs you
Filtering the spam is the easy half. The expensive failure is the week between the spike landing and somebody noticing, because during that week the number is in a report, a client has read it, and you are now explaining a correction instead of a result. A wrong number that arrives on time is worse than a right number that arrives late.
We noticed ours the day after because something watches that property and told us the traffic had moved. That is the whole job of Metrics Watch Alerts: it monitors your GA4 properties and emails or Slacks you when a metric moves, so an unexplained 25x shows up while you can still do something about it rather than in the report a client already opened. You can also just set a GA4 custom insight to email you on a large jump in sessions, which is free and slower; either is better than finding out in a client meeting.
All the figures above are from our own property, and the incident is from 3 September 2026. The GA4 filter behaviour was checked against Google's own data filters documentation on 4 September 2026.