I was recently reviewing a client’s project. Everything seemed fine: GA4 running, server-side GTM set up, FPID cookie in place. But in BigQuery — something was clearly off.
1. Way too many users.
2. Sessions inflated 1.5–2x.
3. Tons of unattributed traffic.
Like someone quietly opened a backdoor into the ID system.
Here’s where server-side + GA4 starts to break.
When you run server-side GTM (and properly use FPID via first-party server cookies), all identity logic should run through the server. FPID keeps users stable, sessions glued, and attribution intact.
But GA4’s automatic events — scrolls, clicks, downloads, virtual page_views — still fire directly via the JS tracker. And that tracker has no clue about your FPID. It happily generates its own JS-client_id.
Result? One real user gets counted twice — once via FPID, once via JS client_id. And this snowballs fast:
1. GA4 sees two users where there’s only one.
2. Sessions explode as IDs don’t match.
3. Unattributed traffic grows — GA4 struggles to connect the dots.
The charts look great, but your data quietly falls apart.
The real issue?
Server-side tracking is about full control. One entry point: the server container. All events should route through it. Only then you get consistent IDs and clean data.
The moment you let GA4’s automatic events run in parallel — you end up with two independent counting systems fighting over the same users.
My rule of thumb:
1. Disable all GA4 automatic events.
2. Manage every event manually in client & server GTM.
3. Set FPID strictly server-side to control identity.
4. Watch user counts & sessions in BigQuery — sudden spikes usually mean duplicated client_ids.
Automatic GA4 events look great in demos. But once server-side enters the game — they create expensive confusion.
If you work with GA4 to BigQuery exports, be sure to check out my SQL cheat sheet.