You open GA4 Realtime, compare the web stream with the server-side stream, and server-side has fewer events than client-side? Most often it isn't an outage of our container — it's the configuration of the web GTM container, the GA4 property, or an ad-blocker. Here are 8 causes ordered by how often they show up in practice.
Before you start: verify the server-side container is actually delivering
Open Dashboard → Statistics and look at the Match rate and Error rate over the last 24 h:
- Match rate ≥ 99% and error rate < 1% → the container delivers, the problem is higher up (web GTM, GA4, or an ad-blocker). Continue below.
- Error rate > 5% → the container or the target platform has a real problem. Open Activity and look at the error message of the specific events. Write to us and we'll look right away.
Quick win — comparison without GA4 access: on Dashboard → Overview you'll find the "Top events via sGTM (24 h)" card. Compare the number next to page_view with GA4 → Reports → Realtime → "Events by name" for the same period. A difference < 5% is normal (timing + bot filter). A difference > 15% = one of the causes below.
1. The primary GA4 Configuration tag has no "Send to server container"
The most common cause of a gap in page_view and sessions. The web GTM has one GA4 Configuration tag that fires all GA4 Event tags and itself fires Enhanced Measurement events (page_view, scroll, click, file_download…). If it doesn't have Send to server container turned on, all these events go straight to google-analytics.com and the server-side stream never receives them.
How to verify (2 minutes):
- Open Google Tag Manager → your web container
- Tags → filter for the type
Google Analytics: GA4 Configuration - Open the tag → Show More Settings → Send to server container
- If it's unchecked or Server Container URL is empty = cause found
Fix: check Send to server container, put your tracking subdomain into Server Container URL (e.g. https://sst.yoursite.cz) → Save → Submit → Publish. Within 5 minutes you should see noticeably more page_view events in Dashboard → Overview.
2. The web GTM has two parallel GA4 Configuration tags
A typical migration scenario from Stape / another sGTM: the old GA4 Configuration tag that fires straight to googletagmanager.com stayed active + a new tag that sends to sst.yoursite.cz was added. If they don't have identical triggers, some events fire only client-side and others only server-side.
How to verify:
- Open Google Tag Manager → your web container
- Tags → filter
Google Analytics - If you see 2 or more GA4 Configuration tags — that's your problem
- Open each tag → Server Container URL: one is usually empty (= client-side direct), the other points to
sst.yoursite.cz(= server-side)
Fix: Delete the client-side GA4 Configuration tag (the one with the empty Server Container URL). The server-side tag covers 100% of events + resists ad-blockers + ITP.
3. The GA4 property has two data streams (web + sst)
If during onboarding a new GA4 data stream was created for sst.yoursite.cz instead of reusing the existing web stream, you have two separate sets of data in GA4. The Realtime view always shows only one stream.
How to verify:
- GA4 → Admin → Data streams
- If you see 2+ streams under the same property — you have a split
Fix: Send the server-side tag to the same Measurement ID as the web tag (G-XXXXXXXX). Server-side doesn't have its own data stream — it uses the existing web stream. Delete the second stream in GA4 Admin → Data streams (its historical data stays accessible in Explore).
4. An ad-blocker is blocking your sGTM subdomain
20-40% of EU users use uBlock Origin, AdGuard, Brave Shields, or Pi-hole. These tools are based on EasyList / EasyPrivacy and block everything that matches known tracking regexes. When your sGTM subdomain is too descriptive (e.g. analytics.yoursite.cz, tracking.yoursite.cz, gtm.yoursite.cz), ad-blockers catch it just like google-analytics.com — and client-side will see it in GA4 (the web tag fires before the block), but server-side won't (the request never arrives).
How to verify (3 minutes):
- Turn on uBlock Origin in Chrome (or install it for 5 minutes)
- Open your site → DevTools → Network → filter
collect - If requests to your
sst.yoursite.cz/g/collectlight up red (blocked), an ad-blocker is blocking them - Second test: open adblockanalyzer.com, enter your subdomain
Fix: rename the subdomain to something generic (e.g. data.yoursite.cz, m.yoursite.cz, api.yoursite.cz, cdn.yoursite.cz). In Dashboard → Domains add the new domain, generate SSL, deploy. The old subdomain stays active (for rollback); point the new web GTM Server Container URL at the new one. Recovery rate +20-40% within a week.
5. Ecommerce events (purchase, view_item, add_to_cart) go only client-side
A specific cause for stores with a gap in ecommerce events (page_view matches but purchase doesn't). The web GTM has separate GA4 Event tags for purchase, view_item, etc. that reference a different GA4 Configuration tag with no Server Container URL.
How to verify:
- GTM → Tags → filter
GA4 Event - For each ecommerce event open the tag → find the reference to the GA4 Configuration Tag
- Open that Configuration tag → check the Server Container URL
- If it's empty = ecommerce events go client-side
Fix — variant A (route everything to server-side): unify all GA4 Event tags so they reference one Configuration tag with a Server Container URL. Save → Submit → Publish.
Fix — variant B (parallel client + server): If you want to keep client-side reporting (e.g. to also see 3rd-party ad pixels), duplicate the GA4 Event tags: one without a Server Container URL (the current client-side), the other with it (the new server-side). In GA4 Admin set up deduplication via transaction_id on purchase events. GA4 merges them itself. Bonus: server-side gets through the events that an ad-blocker / iOS / Brave blocks client-side (typically 20-40% extra captured conversions).
6. Cookie Keeper is off → every Safari/iOS visitor arrives as a different user
Safari ITP shortens the lifetime of first-party cookies set via JavaScript to 7 days. Without Cookie Keeper, sGTM can't extend them (its cookies set client-side have the same limit). The result: after 8 days the same user returns with a new cid, attribution breaks, the session count doubles. It shows up as a gap in "users" and "sessions", not in page_view.
Fix: Dashboard → Power-Ups → Cookie Keeper → turn on. The default cookie list (_ga, _gid, _gcl_aw, _gcl_au, _fbp, _fbc, FPID, FPLC) covers GA4, Google Ads, and Meta. Set the cookie lifetime to 400 days (the max for first-party). The effect is visible in 1-2 weeks — the recovery rate grows as returning users come back.
7. Bot Detection is off → bot traffic inflates Realtime, but is filtered in reports
GA4 has its own bot filter (the IAB Bot List) — it filters out automated traffic in reports, but Realtime shows it. Bot Detection in DataNostro adds an X-Device-Bot header → a GTM tag template can filter bot events server-side before sending to GA4 → the server-side number in Realtime is lower, but the real data in reports is the same or better.
It's not a bug — it's cleaner data. Dashboard → Power-Ups → Bot Detection runs by default in headers_only mode (it only flags, doesn't block). If you want more aggressive filtering, switch to block_requests and set the threshold (default 75% = blocks typical scrapers, not crawlers).
8. Consent Mode v2 — server-side respects consent more strictly
If you have Consent Mode v2 on the site (a CMP banner) and the user declined analytics, client-side GA4 still sends a cookieless ping (basic_consent=denied). The server-side GA4 tag with default settings usually drops these pings or discards the cid → it doesn't show in Realtime.
How to verify: in the event URL (Activity → a specific event) look for gcs=G100 or gcs=G101. G111 = both consents granted, G100 = both denied. If you have more G100 than G111, most visitors declined.
Fix: in GA4 Admin turn on Modeled conversions + Behavioral modeling. GA4 fills in data about users who declined using ML. You won't see these modeled events in the server-side Realtime stream, but you will in reports (with a 24-48 h delay).
Triage checklist (5 minutes)
- Dashboard → Overview → "Top events via sGTM" — the page_view number. If it's < 80% of what you see in GA4 Realtime, continue.
- Dashboard → Statistics → Match rate ≥ 99%? If not, the container has a problem — write to us.
- GTM Web → Tags → GA4 Configuration tag → "Send to server container" checked? If not, cause #1.
- How many GA4 Configuration tags total? 2+ = cause #2.
- GA4 → Admin → Data streams → 2+ under the same property = cause #3.
- Try the site with uBlock Origin → blocked requests to your sGTM subdomain = cause #4. Rename the subdomain.
- Dashboard → Overview → "Top events" — do you see
purchase/view_item/add_to_cartthere? If not and you're a store, cause #5. - Power-Ups → Cookie Keeper on? If not and you have a sessions gap, turn it on.
- A sample of 10 events in Activity → how many
gcs=G111vsG100? Mostly G100 = cause #8 (turn on modeled conversions in GA4).
If after going through the checklist server-side is still significantly < client-side (a difference of more than 15%), DataNostro Care includes a 30-minute diagnostic session. We log into your GTM and GA4, go through it together, find the source of the difference, and show you the fix.
What is, on the contrary, normal
- A 1-5% difference between client and server-side: timing differences (the client sends events in a batch, server-side has per-event latency), no problem.
- Server-side has more than client-side: excellent — recovery from ad-blockers/ITP works, the client lost data, the server saved it.
- Server-side has less after deploying Bot Detection: cleaner data, not a bug.