Persisting URL Parameters Across Pages

September 03, 20254 min read
attribution reporting - preserving clicks with javascript

When a visitor lands on your website from a paid ad or tracked link, their URL may contain important tracking data like UTM parameters or click IDs (e.g., ?utm_source=google&utm_medium=cpc&gclid=123abc). These values tell you how that visitor arrived—but if the user clicks through to another page before submitting your form, the parameters are lost.

The Problem

Many users don’t submit a form on the same page they land on. If the attribution data is only present in the initial URL and isn’t stored or carried forward, it won’t be available to populate the hidden fields in your form later.

This means your CRM won’t know how the lead found you—making campaign performance harder to track.

The Solution

To preserve attribution data across multiple pages, we use a JavaScript snippet that:

  1. Captures URL parameters on the initial page visit

  2. Automatically appends them to internal links

  3. Ensures the parameters follow the visitor throughout their session

This ensures attribution fields are still available when the form is eventually submitted—whether on page 1 or page 10 of their visiting session.


Implementation with Google Tag Manager:

We’ll solve this using a single JavaScript tag in Google Tag Manager (GTM).

Steps:

  • Go to your Google Tag Manager workspace.

  • Create a new tag:

    • Tag Type: Custom HTML

    • Trigger: All Pages

  • Paste the following code into the tag editor

  • Replace YOUR-DOMAIN.com with your actual domain name in the code below.

<script>

(function() {

  var domainsToDecorate = [

          'YOUR-DOMAIN.com',

      ],

      queryParams = [

          'utm_medium',

          'gclid',

          'utm_source',

          'utm_campaign',

          'utm_keyword',

          'ref'

      ]

  // do not edit anything below this line

  var links = document.querySelectorAll('a'); 

// check if links contain domain from the domainsToDecorate array and then decorates

  for (var linkIndex = 0; linkIndex < links.length; linkIndex++) {

      for (var domainIndex = 0; domainIndex < domainsToDecorate.length; domainIndex++) { 

          if (links[linkIndex].href.indexOf(domainsToDecorate[domainIndex]) > -1 && links[linkIndex].href.indexOf("#") === -1) {

              links[linkIndex].href = decorateUrl(links[linkIndex].href);

          }

      }

  }

// decorates the URL with query params

  function decorateUrl(urlToDecorate) {

      urlToDecorate = (urlToDecorate.indexOf('?') === -1) ? urlToDecorate + '?' : urlToDecorate + '&';

      var collectedQueryParams = [];

      for (var queryIndex = 0; queryIndex < queryParams.length; queryIndex++) {

          if (getQueryParam(queryParams[queryIndex])) {

              collectedQueryParams.push(queryParams[queryIndex] + '=' + getQueryParam(queryParams[queryIndex]))

          }

      }

      return urlToDecorate + collectedQueryParams.join('&');

  }

  function getQueryParam(name) {

      if (name = (new RegExp('[?&]' + encodeURIComponent(name) + '=([^&]*)')).exec(window.location.search))

          return decodeURIComponent(name[1]);

  }

})();

</script>


What This Script Does:

  • Detects all internal links pointing to your domain

  • Appends any available UTM parameters and click IDs from the current URL to those links

  • Ensures attribution data “travels” with the user as they browse your site

With this in place, we can now reliably capture attribution fields later—on any form, on any page.


Populating Hidden Fields with JavaScript:

Now that we’re preserving URL parameters across internal links, the next step is to insert those values into the hidden form fields before the form is submitted. This allows attribution data to be passed into your CRM along with the rest of the form data.

Because websites use different platforms and form builders (Gravity Forms, Elementor, HubSpot, native HTML, etc.), we’ll use a simple JavaScript approach that works across nearly all environments—as long as your hidden fields are properly named.


Basic Requirements

To populate hidden form fields with attribution data, your form must:

  • Include the correct hidden fields (e.g., utm_source, gclid, etc.)

  • Load after the page has access to the JavaScript snippet below

  • Use the exact field name attribute that matches the parameter


Universal JavaScript Snippet

Add this script to your website site-wide (in your page footer or in Google Tag Manager as a “Custom HTML” tag set to fire on All Pages):

<script>

(function () {

var search = window.location.search;

if (!search) return;

// Parse query params (ES5)

var params = {};

var pairs = search.replace(/^\?/, '').split('&');

for (var i = 0; i < pairs.length; i++) {

if (!pairs[i]) continue;

var kv = pairs[i].split('=');

var k = decodeURIComponent(kv[0] || '');

var v = decodeURIComponent((kv[1] || '').replace(/\+/g, ' '));

if (k) params[k] = v;

}

var keys = ['utm_medium','gclid','fbclid','utm_source','utm_campaign','utm_keyword'];

// If there may be multiple inputs per name, set them all

for (var j = 0; j < keys.length; j++) {

var name = keys[j];

var val = params[name];

if (!val) continue;

var nodeList = document.querySelectorAll('input[name="' + name + '"]');

for (var n = 0; n < nodeList.length; n++) {

nodeList[n].value = val;

}

}

})();

</script>


What This Script Does:

  • Looks at the current page URL

  • Finds any <input> elements with a matching name attribute

  • Sets the value of those fields to the matching parameter in the URL


Notes & Tips:

  • Works with most form builders that allow you to create custom hidden fields

  • If you’re using multiple forms on one page, make sure each one uses unique IDs or test that all hidden fields are being populated

  • For more complex setups (multi-step forms, AJAX-loaded forms), you may need to delay this script slightly or re-trigger it once the form loads

Richard has 20 years of experience in the digital marketing world. His skill sets includes advanced SEO, paid ad management, Local Service Ads, content that converts, analytics and trend analysis, cold email outreach, and project management.

Richard Whirley

Richard has 20 years of experience in the digital marketing world. His skill sets includes advanced SEO, paid ad management, Local Service Ads, content that converts, analytics and trend analysis, cold email outreach, and project management.

Back to Blog

© Copyright 2025 - All Rights Reserved.
FLTP, LLC - System X Designs

System X Designs is not affiliated with, endorsed by, or associated with Facebook in any way. FACEBOOK is a trademark of FACEBOOK, Inc.