MarTech

Fix utm_source=undefined in GA4 and Server-Side GTM

Anatomy of a Corrupted Source Tag

Seeing utm_source=undefined inside your Google Analytics 4 (GA4) Traffic Acquisition reports is a clear indicator of broken parameter execution. Instead of attributing session traffic to LinkedIn, a specific newsletter, or a paid campaign, GA4 logs the literal string "undefined" as the acquisition source. This breaks default channel group rules, pollutes BigQuery raw exports, and ruins campaign attribution across your team's dashboards.

This issue rarely stems from a single error. It is typically caused by a bad interaction between JavaScript execution, single-page application (SPA) routing, marketing automation link generation, or Server-Side Google Tag Manager (sGTM) event data mapping. JavaScript handles missing values by evaluating unassigned variables as the primitive undefined. When string concatenation or template literals format an unassigned variable into a URL, JavaScript converts that primitive into the literal string "undefined".

When this malformed string passes to GA4 through client-side collection or sGTM, the GA4 intake endpoint accepts "undefined" as a valid text string. It overrides organic or direct attribution credit and assigns the session to a broken source. Fixing this requires tracing parameter flow from origin links to sGTM server containers.

Root Cause 1: Client-Side Async Failures and SPA Route Overrides

Modern web applications built on React, Next.js, Vue, or Angular frequently alter URL paths without triggering full browser page reloads. When a user arrives from an ad with valid campaign tags (for example, ?utm_source=linkedin&utm_medium=cpc), the application initializes its client-side router. If your client-side Tag Manager setup attempts to read URL parameters before the application finishes routing, variable timing issues occur.

Consider a standard client-side GTM Custom JavaScript (CJS) variable designed to extract query parameters for custom dataLayer pushes or tag configurations:

function() {
  var params = new URLSearchParams(window.location.search);
  return params.get('utm_source');
}

If the native browser method returns null (because the user landed without campaign parameters), and that variable is interpolated into a custom page_location override like this:

'https://' + {{Page Hostname}} + {{Page Path}} + '?utm_source=' + {{CJS - Get UTM Source}}

The resulting string becomes https://example.com/page?utm_source=null or https://example.com/page?utm_source=undefined if an internal script passed an uninitialized variable. Once GTM sends this updated page_location value to GA4, the measurement protocol extracts undefined as the campaign source.

Single Page Applications exacerbate this during virtual pageviews. If your sGTM setup relies on client-side state pushes for virtual page views, and the router strips campaign parameters from the address bar on initial load without saving state, subsequent route changes trigger GTM tags with empty variables that resolve to undefined.

Root Cause 2: Link Builders and Marketing Automation Templates

Ad-ops and marketing automation workflows are common sources of malformed parameters. When marketing automation platforms like HubSpot, Marketo, or ActiveCampaign deploy emails, template variables dynamically populate query strings. If an email template is configured with an unpopulated dynamic token, such as:

https://yourdomain.com/landing-page/?utm_source={{contact.lead_source}}&utm_medium=email

And the contact field lead_source contains no value, the email platform's rendering engine often outputs empty text or the literal code string undefined. The subscriber clicks a link explicitly formatted as utm_source=undefined before even hitting your site.

Similarly, redirect wrappers, short links, or consent banners can break URLs. If an opt-in banner or a 301 redirect script reads inbound UTM parameters, manipulates the string, and forwards the browser to a destination URL without validation checks, empty parameters are regularly converted into literal "undefined" parameters during the redirect payload execution.

Root Cause 3: Server-Side GTM Event Data Model Mappings

Server-side tagging introduces another layer where unvalidated data can turn into literal strings. When client-side GTM sends a request to your sGTM tagging server (running on Google Cloud Run, Stape, or AWS), the sGTM GA4 Client parses incoming HTTP request parameters into the structured Event Data object.

Problems happen in sGTM when custom transformations, Client modifications, or outgoing HTTP Request tags attempt to reconstruct request payloads. If a Transformation in sGTM reads Event Data using a lookup variable that fails to match a key, or if a custom Tag template injects a variable that returns undefined, sandboxed JavaScript in sGTM may stringify that output when appending query strings for downstream collection endpoints.

Furthermore, if you use the sGTM Measurement Protocol tag to forward server-to-server conversion events (such as offline purchases or CRM updates to GA4), sending "cs": "undefined" in the protocol payload explicitly overwrites session source data in GA4's attribution processing pipeline.

Step-by-Step Debugging Checklist: From DevTools to BigQuery

1. Inspect Raw Hits via Browser DevTools

Open Google Chrome DevTools, navigate to the Network tab, and filter by /g/collect or your custom sGTM tracking domain. Trigger a page load or event, and examine the payload requests.

  • Search payload parameters for the key cs (campaign source) or inspect the dl (document location) parameter.
  • If dl contains utm_source=undefined, the issue is generated client-side before the hit leaves the browser.
  • If dl is clean in the browser network request but GA4 DebugView shows undefined as the source parameter, the transformation issue occurs inside sGTM or during server processing.

2. Trace Variables in GTM Client & Server Preview Modes

Run client-side GTM Preview and sGTM Preview concurrently.

  • In client-side Preview mode, click the event firing your GA4 Tag (e.g., Initialization or Container Loaded).
  • Select the Variables tab and check values for custom URL, page_location, or UTM variables. Verify whether any variable returns the string "undefined" versus an actual undefined primitive value or blank string.
  • In sGTM Preview mode, select the incoming request in the left panel. Inspect the Event Data tab. Verify if page_location or campaign source attributes already contain the corrupted text when arriving at the server container.

3. Query Raw Event Records in BigQuery

If you have enabled the GA4 BigQuery export, run a query to isolate affected records and identify correlation patterns (e.g., specific browsers, page paths, or operating systems):

SELECT
  event_date,
  event_name,
  traffic_source.name AS source_name,
  traffic_source.medium AS medium_name,
  (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location') AS page_location
FROM
  `your-project.analytics_123456789.events_*`
WHERE
  traffic_source.name = 'undefined'
  OR (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'source') = 'undefined'
LIMIT 100;

Reviewing landing page patterns in BigQuery reveals whether utm_source=undefined is isolated to specific ad campaigns, automated email templates, or dynamic routing pages.

How to Fix and Prevent 'undefined' Parameters

Fix 1: Sanitize URL Parsing in Client-Side GTM

Never allow a Custom JavaScript Variable in GTM to return undefined or null as part of a concatenated string. Update JavaScript variables to perform validation checks before returning values to tags.

Use this robust pattern inside a GTM Custom JavaScript Variable for extracting UTM parameters:

function() {
  try {
    var searchParams = new URLSearchParams(window.location.search);
    var source = searchParams.get('utm_source');
    if (!source || source === 'undefined' || source === 'null') {
      return undefined; // Returns primitive undefined, preventing string concatenation errors
    }
    return source.trim();
  } catch(e) {
    return undefined;
  }
}

When GTM variable output evaluates to actual primitive undefined, native tag templates automatically omit the parameter from the outgoing network request rather than casting it to a string.

Fix 2: Implement sGTM Event Data Transformations

If malformed traffic originates from external campaigns or third-party links beyond your immediate codebase control, filter or sanitize incoming values inside sGTM using Transformations.

  • Navigate to your sGTM Container, then click Transformations > New.
  • Select Modify Event Data.
  • Set the field to modify: page_location.
  • Write a Regular Expression replacement to strip malformed campaign parameters from the URL parameter string before tags send data to GA4:

Pattern to match: ([?&])utm_source=undefined(&|$)
Replacement: $1 (or remove the parameter string entirely when matching trailing params).

Alternatively, create a Transformation to override page_location or event parameters whenever their extracted value strictly equals "undefined".

Fix 3: Fix Single-Page Application (SPA) State Synchronization

If dynamic SPA pageview tracking overwrites valid parameters, update your site's dataLayer architecture. Store campaign attributes in browser session storage upon initial entry. Ensure the initial URL state is preserved before route updates alter the address bar.

Implement this execution sequence in your application codebase or site header:

(function() {
  var urlParams = new URLSearchParams(window.location.search);
  var utmSource = urlParams.get('utm_source');
  
  if (utmSource && utmSource !== 'undefined') {
    sessionStorage.setItem('first_touch_utm_source', utmSource);
  }
})();

Use this stored session variable as a backup lookup within GTM when direct URL parameters evaluate as missing or invalid, preserving attribution across complex SPA routing states.

Attribution Integrity Strategy

Allowing utm_source=undefined to persist pollutes session attribution, obscures true campaign ROI, and degrades machine learning models in connected platforms like Google Ads. Fixing it requires auditing parameter delivery at every step of your stack: link creation, client-side GTM execution, SPA router state updates, and sGTM transformations. Implement strict variable sanitization and validation transformations to keep your GA4 data clean and reliable.