GA4 QA: canonical fixes, not forum threads
One question per page, one original, tested-format answer per question - a fix, a verification step, and nothing copied from anywhere. Built for the GA4 problems that used to send people hunting through half-answered Stack Overflow threads.
Setup, SPAs and duplicate events (4)
How do I install GA4 correctly in a React, Next.js, Nuxt, or Vue single-page app?
The correct way to load GA4 in a single-page app: where the gtag.js snippet goes, why the default page_view has to be disabled, and how to fire route-change events manually.
How do I stop GA4 from double-firing page_view (and other events) in a single-page app?
Duplicate GA4 page_view events almost always come from having two firing paths active at once - the automatic default and a manual router hook, or two separate tag deployments.
How do I migrate an existing analytics.js / Enhanced Ecommerce setup to GA4's gtag.js without losing history?
Universal Analytics' historical data cannot be transferred into GA4 - the migration is really a parallel-run-then-cutover process, and Enhanced Ecommerce events need to be remapped to GA4's ecommerce event and item schema, not copied as-is.
How do I test GA4/analytics tags on localhost or staging without sending real hits to production data?
Test GA4 on localhost or staging with either a separate test data stream/property, or debug_mode plus DebugView, so test traffic never mixes into your production reports.
Debugging and data quality (4)
Why do GA4 event counts differ between the UI, the Realtime API, and the Data API for the same date range?
GA4's standard UI, Realtime, and Data API queries pull from different processing stages and apply different sampling/thresholding rules by default - matching numbers exactly across all three isn't guaranteed even when the underlying data is correct.
Why do my GA4 custom dimensions/parameters show as (not set) or never appear in reports?
A custom dimension shows (not set) or vanishes from GA4 reports when the parameter was never registered as a custom dimension, was registered after the data was collected, or is scoped wrong for the report using it.
Why do my GA4 events show in DebugView or Realtime but never appear in standard reports?
DebugView and Realtime show events the instant they arrive; standard GA4 reports run on a processing delay and drop events that fail validation - here's how to tell which one is happening.
What do the fields inside the _ga and _gid cookies actually mean, and why would one be empty?
The _ga cookie encodes a version marker, a domain-tracking depth indicator, a random client ID, and a first-visit timestamp; an empty or missing value usually means the cookie was blocked, cleared, or never set due to a consent or third-party-cookie restriction.
Measurement Protocol and server-side (4)
What exact client_id and session_id format does the GA4 Measurement Protocol require, and where do I get a valid one?
GA4's Measurement Protocol requires client_id in a specific randomNumber.timestamp format and will silently misattribute or reject events sent with an invented or malformed one.
Why does the GA4 Measurement Protocol return a 204 success but the event or user data never shows up in reports?
A 204 from the Measurement Protocol only confirms the request reached Google's collection endpoint - it does not confirm the payload was valid, attributable, or kept through processing.
How do I send GA4 events server-side without gtag.js/GTM, and without leaking my Measurement Protocol API secret?
Server-side GA4 events go through the Measurement Protocol, and the API secret that authorizes them must be called from your own server, never embedded in client-side JavaScript where it's visible to anyone.
Why does my GA4 purchase event report the wrong price (extra zeros / wrong currency scale)?
A GA4 purchase or item value inflated by a factor of 100 or 1000 is almost always a units mismatch between minor-currency-unit values from a payment processor and GA4's expected decimal major-unit format.
APIs and BigQuery (2)
Why does the GA4 Data/Admin API reject my service account with a permissions error even though access looks correct?
A GA4 Data or Admin API permissions error almost always means the service account's email was never added as a user on the property itself - project-level API enablement and property-level access are two separate steps.
Why is my GA4-to-BigQuery export missing rows, or why does linking BigQuery fail with a permission error?
Missing BigQuery export rows are usually intraday/daily table timing, not data loss; a 403 on the link step is almost always a missing BigQuery IAM role on the account doing the linking, not a GA4-side problem.
Platform and privacy (2)
Can I still anonymize IPs or disable cookies in GA4 the way Universal Analytics allowed?
GA4 anonymizes IP addresses by default for all traffic, unlike Universal Analytics which required an explicit anonymizeIp flag - and it can operate on a cookieless, modeled basis when consent is declined, rather than offering a manual cookie toggle.
What is the actual difference between GA4 and Firebase Analytics, and which should own app events?
Firebase Analytics is the same underlying engine that powers GA4 for apps - there's one event schema, not two competing tools, and the real decision is which console you use to view and configure it.
Attribution, ads and cross-domain (4)
Why do GA4 key events not match the conversion counts Google Ads reports?
GA4 and Google Ads use different attribution models, different counting rules (event-based vs. conversion-based), and different lookback windows by default - so a mismatch in counts is expected, not automatically a tracking bug.
Why does GA4 show the wrong (or missing) source/medium for a session that came from another domain?
Cross-domain source/medium breaks when the second domain isn't configured for cross-domain measurement, causing GA4 to start a fresh session and attribute it to (direct)/(none) or the referring domain as a referral instead of the real original source.
Why does the _gl cross-domain linker parameter go missing or expire between my two domains?
The _gl parameter goes missing when a link is generated outside gtag.js's control (server-rendered redirects, cached HTML, link-shorteners) or expires because too much time passed between the click and the destination page loading it.
Why are Enhanced Conversions missing from my GA4 configuration tag inside GTM?
Enhanced Conversions for the web are configured on the Google Ads Conversion Linker/tag setup, not directly inside the GA4 Configuration or Event tag in GTM - looking for the setting on the wrong tag type is the usual cause of it appearing missing.