The GA4 audit checklist agencies actually use
Most agency-inherited GA4 properties have at least three silent bugs. This is the 12-point audit that finds the dead conversions, the misclassified events, and the missing cross-domain config — without breaking what's working.
Inherit a GA4 property that's been managed by 4 different freelancers since GA4 launched and you'll find the same pattern: half the marked conversions are misfires from 2023, custom dimensions registered against properties that no longer exist, and a "Direct" channel that's secretly 40% Stripe redirects.
The audit is mechanical. 12 checks, ~60 minutes, no cleverness required. This is the version we run on every new client before we touch a single optimisation.
Before you start
Get viewer access at minimum, editor if possible — some checks need to see the data-retention setting or the link configurations, which are admin-scoped. Pull the property in incognito + signed in to the agency Google account, not the personal Gmail. Several of the panels render differently based on which roles your account has across multiple properties.
Open a clean tab for the live site you'll cross-reference against. You'll need it for the Realtime check and for confirming that event triggers actually fire on real user actions.
The 12 checks
1. Property settings — time zone, currency, industry, data retention
Admin → Property settings. Four things:
- Time zone: matches the client's business reporting timezone, NOT the agency's. A US-based agency managing a UK client and leaving the property on
America/Los_Angelesproduces day-boundary bugs in every dashboard. - Currency: matches the e-commerce currency the storefront sends. A property set to USD but receiving GBP
purchaseevents shows revenue as 1.23 USD per £1.00. - Industry category: cosmetic but used by GA4 to seed benchmark comparisons. Set it correctly.
- Data retention: Admin → Data Settings → Data Retention. Default is 2 months for event-level data, which silently caps every YoY comparison and most cohort views. Change to 14 months (the free max). Do this on day one of a new engagement; it doesn't backfill.
2. Data streams — measurement ID + enhanced measurement
Admin → Data Streams → click the web stream. Check:
- The Measurement ID (
G-XXXXXXXXXX) matches what GTM is sending. Mismatched IDs are the #1 cause of "the dashboard shows nothing but Real-time works." - Enhanced measurement toggles (the gear icon): page changes, scrolls, outbound clicks, site search, video engagement, file downloads. Each toggle has its own opinion. The defaults are usually fine for content sites; e-commerce sites often want to disable
scrollandvideo_engagementbecause the events overwhelm the more important ones at the GA4 free-tier event-volume cap. - For app streams (iOS / Android): the bundle ID / SHA1 fingerprints, and whether the Firebase project link is still live.
3. Conversion events — what's marked, what should be
Admin → Events → Conversions column. Three buckets to triage:
- Real conversions that match the client's business outcomes (purchase, generate_lead, qualified_demo_booked). These stay.
- Vanity conversions (page_view-as-conversion, scroll, every form submit including the unsubscribe form). These get unmarked. Half the value of GA4 attribution depends on the conversion set being meaningful; "everything is a conversion" = nothing is.
- Stale conversions from old campaigns (Black Friday 2023 promo events). Unmark + archive.
Also: confirm conversion events use the GA4 recommended event names (purchase, sign_up, generate_lead, begin_checkout) where applicable. Custom names work but lose the GA4-side machine-learning enrichment that recommended names get.
4. Custom dimensions + metrics — registered vs used
Admin → Custom definitions. Two things:
- Cardinality: the free tier caps user-scoped dimensions at 25 and event-scoped at 50. A property at-cap can't add new dimensions without deleting an old one. Check the count and prune unused ones.
- Registered but never sent: open the dimension's "explore" view. If no rows have a value in the last 30 days, the GTM tag that's supposed to set the param is broken (or was removed). Either fix the tag or delete the dimension.
5. Audiences — orphans + bloat
Admin → Audiences. List view. Look for:
- Promo-campaign audiences that haven't been used since the campaign ended. They cost nothing to keep but clutter the picker in Google Ads + DV360 audience selection.
- Overlapping audiences ("Visited /pricing in last 7 days" + "Visited /pricing in last 14 days" + "Pricing page viewers"). Consolidate where the targeting strategy actually differs.
- Audiences with 0 users: definition probably uses a dimension that doesn't fire anymore.
6. Referral exclusions — the Stripe / PayPal / Klarna trap
Admin → Data Streams → click stream → "Configure tag settings" → "List unwanted referrals." Confirm the payment processors the client uses are listed:
stripe.comandcheckout.stripe.compaypal.comklarna.compay.google.com,apple.com(for Google Pay / Apple Pay flows)- Any 3-D Secure issuer domains your specific client routes through
Without this, every successful payment looks like a Stripe referral instead of a continuation of the original session, and your attribution data is silently corrupted.
7. Internal traffic filter — defined AND active
Admin → Data Streams → click stream → "Configure tag settings" → "Define internal traffic." Two failure modes:
- Defined but inactive: filter is created but the corresponding
traffic_typefilter under Data Filters is paused. Test mode counts as "inactive" for production. - Defined too narrowly: a single IP for the agency, missing the client's office IPs (which they use for QA). Their team's testing pollutes the funnels.
8. DebugView — does it work?
DebugView → check that at least one device is currently visible. Then on a clean browser tab, install Google Analytics Debugger (or pass ?_dbg=1 if the site supports it), reload the live site, and confirm:
- The browser shows up in DebugView within ~10 seconds.
- The critical events you care about (the purchase flow, the lead form) appear with all expected event_params, not just the event names.
- No
(not set)values on parameters that should always be populated.
This is the single fastest check for "is the dataLayer push shape correct?" — faster than waiting 24 hours for the standard reports.
9. Linked products — Google Ads, BigQuery, Search Console
Admin → Product Links. Confirm each is connected AND active:
- Google Ads link: enables conversion import + audience export to Ads. Common failure: the link was created when the Ads account was under a different MCC, then re-parented; the link goes "auth required" silently.
- BigQuery link: only set if you're paying for the data export. Daily-only is free up to 1M events/day; streaming export costs real money.
- Search Console link: enables the Search Console reports inside GA4. Easy to forget.
10. Attribution — model + lookback windows
Admin → Attribution settings:
- Reporting attribution model: GA4 defaults to data-driven; for properties with under ~3000 conversions over 28 days, data-driven falls back to "last click" silently. Verify the property has enough volume to actually use data-driven — if not, document that the displayed model is effectively last-click.
- Acquisition lookback window: 30 days default; bump to 90 if the client's sales cycle warrants. Acquisition is one-time per user so a wider window is rarely harmful.
- Conversion lookback window: 90 days default. Aligned with most B2C cycles; B2B may want longer.
11. Cross-domain measurement (if applicable)
If the client's purchase flow crosses domains (example.com → checkout.example.com → example.com/thanks), cross-domain measurement keeps the session unbroken:
- Admin → Data Streams → click stream → "Configure tag settings" → "Configure your domains."
- List every domain involved in the user journey.
- Test by clicking from one to the other with
?_gl=URL parameters; they should appear automatically.
Without this, the checkout step looks like a new session originating from your own domain.
12. Realtime + a real user journey end-to-end
Finally, the big-picture check. Reports → Realtime. With the live site open in a clean browser:
- Trigger the canonical user journey: home → product → add to cart → checkout → purchase (or whatever the client's primary conversion path is).
- Watch Realtime fire each event with the right params.
- Confirm the purchase event records the correct revenue value AND the right currency.
- Confirm the user attribution path shows the correct source/medium (this is where #6 — referral exclusions — pays off).
If any step doesn't appear, you have a broken tag or a misconfigured trigger. Fix it before touching anything else; the rest of the audit is meaningless against broken instrumentation.
What to do with what you find
Don't try to fix everything at once. Sort issues into three buckets:
- Now: misclassified conversions, missing payment-processor referral exclusions, broken cross-domain config. These corrupt attribution data live and cost the client money in misallocated ad spend every day.
- This sprint: data-retention bumped to 14 months, custom-dimension cleanup, audience consolidation, internal-traffic filter.
- Documented + deferred: everything that's working but suboptimal (vanity conversions someone's old report still relies on, a stale Google Ads link that hasn't been actively used in 9 months). Keep these in your tracking-map handoff doc; they're agency-level technical debt, not bugs.
The whole audit takes ~60 minutes on a property in average shape, ~2 hours on one that's been through five owners. Run it on every new client. Run it again every 6 months on retained clients, because GA4 properties drift even when nobody is actively editing them — new ad campaigns leak conversions in; recommended-event names change with Google's docs; data retention silently expires.
Where this fits with the rest of the tracking stack
GA4 is one node in the bigger picture. The audit above catches GA4-internal issues, but the more common bug class is integration drift between GA4 and the rest of the stack: GTM is sending an event but GA4 isn't receiving it (broken measurement ID), GA4 has it but Google Ads doesn't (broken product link), Meta is also receiving a duplicate (no event_id for dedup).
That's exactly the moat Phloz was built around: a typed graph of every tracking node (GA4 property, GTM container, ad pixels, conversion APIs) with health-checked edges between them. The map catches the drift before the audit does. Companion reading: the GTM container audit checklist and conversion tracking verification without trusting the dashboard.