TLDR: If you're pulling GA4 pagePath data via the Data API and using matchType: CONTAINS, your click counts are probably wrong. Use EXACT. For A/B variant pages, use inListFilter — it deduplicates across variants for free.

The Setup

I'm building an internal dashboard for an ecommerce business's webinar ops — tracks all the key metrics for a live event: affiliate revenue, halo-effect sales, and "Clicks to Registration Page."

That last one matters a lot.

It feeds the registration rate, and the registration rate is what the team uses to evaluate every webinar's front-end performance.

So it needs to be right.

The Number That Felt Off

I was testing the GA4 pull against a study results webinar and the click count looked… high.

Not obviously wrong. Just inflated in that quiet way that doesn't trip any alarm unless you're suspicious.

I was suspicious.

Turns out I had matchType: CONTAINS on the pagePath filter, matching anything that contained -rego in the path.

That was the bug. Two distinct failure modes:

  • Shopify web-pixel sandbox paths. Shopify emits pageview events from its tracking sandbox with paths like /web-pixels@<hash>/custom/web-pixel-…/sandbox/modern/pages/<slug>-rego. Same user, duplicate event, completely different-looking path. CONTAINS catches all of it.
  • Sibling pages share the slug stem. The thank-you page is -ty. The replay sales page is -replaysales. The A/B variant is -rego-b. Every one of those paths contains the word -rego in some form. You're not filtering the reg page — you're filtering a family reunion.

What Finally Fixed It

Switch to matchType: EXACT on the canonical path only: /pages/202605-af-studyresults-lweb-500-rego.

Done. Sandbox dupes gone. Sibling pages gone.

But then I hit the A/B variant problem.

We run A/B tests on the reg page, so there's a -rego-b path too. I can't just ignore it — those are real users. But if I query them separately and add the numbers, I'll double-count anyone who hit both variants.

The right move: inListFilter with both paths and no pagePath dimension in the response. GA4 collapses it to one row and deduplicates by totalUsers across the whole set.

Real numbers from the event:

  • -rego alone → 9,984 users
  • -rego + -rego-b via inListFilter11,933 users (deduped — less than the naive sum because some hit both)
  • Registrations: 5,079
  • Registration rate: 42.6%

That's the number I can actually hand to the team.

Why This Matters to Me

The reg rate isn't a vanity metric — it's the signal an ecommerce business uses to optimize every webinar's acquisition funnel.

A wrong number here means bad decisions. Quietly, invisibly bad.

The lesson I'm carrying forward: never assume your slug is unique in a platform's event stream. Shopify, GA4, any system that emits tracking events automatically — they inject paths you never authored. Substring matching trusts you own the namespace. You don't. Match the exact identifier, and when you need to union variants, use a filter that deduplicates by entity instead of summing rows.

P.S. The second non-obvious GA4 landmine from this build — service accounts can't be added to a Workspace-org property, so OAuth-as-user is the only path. That one's a post for another day.