I've been running Fathom Analytics on our main production site for about three months, and I've hit a consistent, reproducible issue with UTM parameter parsing that is skewing our campaign attribution data. We rely heavily on UTM parameters for our marketing channels (Google Ads, social campaigns, newsletter links), and I'm seeing a significant portion of traffic being incorrectly bucketed as "direct" when it should be attributed to specific campaigns.
The core problem appears to be that Fathom is not consistently capturing or parsing the UTM query parameters from the landing page URL. I have verified that the links themselves are correctly formatted and that the parameters are present in the browser's address bar upon landing. Our setup is a standard Kubernetes ingress (NGINX) proxying to a Next.js frontend, with the Fathom script injected via their provided snippet.
Here is a simplified example of a URL we are using:
` https://example.com/product-launch?utm_source=newsletter&utm_medium=email&utm_campaign=spring_promo`
According to my dashboard, a large percentage of hits from such URLs show:
* **Source:** `(direct)`
* **Medium:** `(none)`
* **Campaign:** `(none)`
I have already performed the following debugging steps:
* **Confirmed script implementation:** The tracking script is placed correctly in the `` and loads on every page.
* **Checked for redirects:** There are no client-side or server-side redirects stripping the parameters before the Fathom script executes.
* **Verified SPAs:** Our Next.js app uses `next/router` and the `pageview` event fires correctly on route changes, but the UTM parameters from the initial page load are the ones being lost.
* **Reviewed Ad Blockers:** Tested in clean, blocker-free environments. The issue persists.
My current hypothesis is that there might be a race condition or timing issue where the Fathom script parses the URL before the Next.js hydration cycle completes, potentially missing the initial `window.location.search` string. Alternatively, there could be a configuration issue with how the ingress or Next.js handles query strings.
Has anyone else running a React/Next.js (or similar SPA) setup in a Kubernetes environment encountered this? I need to know:
1. Is there a known workaround or specific method to force UTM parameter capture on initial page load for SPAs?
2. Does Fathom's script have a specific API method to manually pass `utm_*` parameters that I should be calling on page load?
3. Are there any ingress or application-level configurations (e.g., related to `proxy_pass` or query string preservation) that are critical for this to work?
I'm looking for a technically detailed solution, as "check your links" is not the issue here. The data discrepancy is large enough to be a blocker for our marketing team's reporting.
– A
Show me the benchmarks.