⚙️ Webflow Script Builder

This is a collection of scripts that we have hand-crafted specifically for extending the capabilities of Webflow beyond what is currently offered. These should always be tested on staging before pushing live.

⚠️ Remember when you paste these scripts into your footer code, you'll want to make sure to paste them within the document ready function.
<script>
  $("document").ready(function() {
    // Code goes here
  });
</script>
Copy Code

📝 Form Enhancements

Append current page URL to all forms

This script appends the current page URL as a hidden text input to all forms on the website. It allows you to capture the URL from which the form was submitted.
jQuery
// Append current page URL to all forms as a hidden text input
$('form').append(`<input type="hidden" id="insertpageurl" name="Page URL" value="${location.href}" />`);
Copy Code

Append user's IP address to all forms

This script retrieves the user's IP address using an API and appends it as a hidden text input to all forms on the website. It helps in capturing the user's IP address along with form submissions.
jQuery
// Append user's IP address to all forms
$.getJSON("https://api.ipify.org?format=json", function(data) {
  $('form').append(`<input type="hidden" id="insertipaddress" name="IP Address" value="${data.ip}" />`);
});
Copy Code

Prevent empty dropdown form field options from being selected

This script disables all form dropdown options with no value set.
jQuery
// Disable empty dropdown form field option
$('form option[value=""]').attr('disabled', true);
Copy Code

Format phone number input to U.S. format

This script formats the phone number input field to the U.S. format when the user unfocuses the field. It ensures that phone numbers entered by users are displayed consistently.

⚠️ You must add a custom attribute to the field named "format-phone" and leave the value empty.
jQuery
$('input[format-phone]').focusout(function() {
  var phone = $(this).val();
  function formatPhoneNumber(phoneNumberString) {
    var cleaned = ('' + phoneNumberString).replace(/\D/g, '');
    var match = cleaned.match(/^(\d{3})(\d{3})(\d{4})$/);
    if (match) {
      return '(' + match[1] + ') ' + match[2] + '-' + match[3];
    }
    return null;
  }
  $(this).val(formatPhoneNumber(phone));
});
Copy Code

🎉 Fun Stuff

Cookie enabled popups

This script targets your popup to be shown after a 5 second delay, and cookies it for 24 hours upon closing it so it is not shown for 24 hours.

⚠️ You must add an ID of "sale-pop-up" to your popup wrapper AND you must add an ID of "close-pop-up" to the close or "x" icon within it.

⚠️ Make sure your '#sale-pop-up' element is set to {display: none; opacity: 0} by default using the Webflow style settings.
jQuery
    // Function to set a cookie
    function setCookie(name, value, days) {
      var expires = "";
      if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        expires = "; expires=" + date.toUTCString();
      }
      document.cookie = name + "=" + (value || "") + expires + "; path=/";
    }

    // Function to get a cookie by name
    function getCookie(name) {
      var nameEQ = name + "=";
      var cookies = document.cookie.split(';');
      for (var i = 0; i < cookies.length; i++) {
        var cookie = cookies[i];
        while (cookie.charAt(0) === ' ') {
          cookie = cookie.substring(1, cookie.length);
        }
        if (cookie.indexOf(nameEQ) === 0) {
          return cookie.substring(nameEQ.length, cookie.length);
        }
      }
      return null;
    }

    // Function to check if the pop-up should be displayed
    function checkPopUpDisplay() {
      var lastPopUpDate = getCookie("lastPopUpDate");
      var currentDate = new Date().toUTCString().split(' ').slice(0, 4).join(' ');

      // If the pop-up has not been seen today, display it with a delay
      if (lastPopUpDate !== currentDate) {
        setTimeout(function() {
          $("#sale-pop-up").css("display", "flex").animate({ opacity: 1 }, 500);
        }, 5000); // 5 second delay
      }
    }

    // Function to close the pop-up and set the cookie
    function closePopUp() {
      $("#sale-pop-up").animate({ opacity: 0 }, 500, function() {
        $(this).css("display", "none");
      });
      setCookie("lastPopUpDate", new Date().toUTCString().split(' ').slice(0, 4).join(' '), 1); // Set the cookie to expire in 1 day
    }

    // Check if the pop-up should be displayed when the page loads
    checkPopUpDisplay();

    // Event listener for the close button
    $("#close-pop-up").click(closePopUp);

Copy Code

Keep copyright year up to date

This script updates the copyright year dynamically to the current year. It ensures that the year displayed in the copyright notice is always up to date.

⚠️ You must add a custom attribute to an element named "update-year" and leave the value empty. This will replace the text inside your element with the current year.
jQuery
changeYear = () => {
  var newDate = new Date();
  var dateYear = newDate.getFullYear();
  $('[update-year]').html(dateYear);
}
Copy Code

Count Up Numbers

This script defines the easeInOutQuad easing function and then applies a count-up animation to elements with the attribute [countup]. Each element's text value will be gradually animated from 0 to the specified countTo value using the defined easing function. This animation will trigger when the element is scrolled into view

⚠️ You must add a custom attribute to an element named "countup" and the value should be the desired value to be counted up to.
jQuery

// Define the easeInOutQuad easing function
$.easing.easeInOutQuad = function(x, t, b, c, d) {
  if ((t /= d / 2) < 1) return c / 2 * t * t + b;
  return -c / 2 * ((--t) * (t - 2) - 1) + b;
};

// Listen to the scroll event on the window
$(window).on('scroll', function() {
  // Iterate through all elements with the 'countup' attribute
  $('[countup]').each(function() {
    var $this = $(this);
    var countTo = parseInt($this.attr('countup'));
    var windowHeight = $(window).height();
    var scrollPosition = $(window).scrollTop();
    var elementPosition = $this.offset().top;

    // Check if the countup animation has not been triggered and the element is within the viewport
    if (!($this.data('countup-triggered')) && elementPosition < (scrollPosition + windowHeight)) {
      $this.data('countup-triggered', true);

      // Animate the countup
      $({ countNum: 0 }).animate({
        countNum: countTo
      }, {
        duration: 2500,
        easing: 'easeInOutQuad',
        step: function() {
          $this.text(Math.floor(this.countNum));
        },
        complete: function() {
          $this.text(this.countNum);
        }
      });
    }
  });
});
Copy Code

Confetti

This script enables a confetti effect on an element when it has the attribute confetti-target set with a class of ".active". It uses CSS animations and dynamically adds confetti particles to create a festive visual effect

⚠️ [confetti-target] is used to identify the element that will display the confetti effect, while [confetti-trigger] is used to identify the element that triggers the activation or deactivation of the confetti effect. When [confetti-target] is given the ".active" class, the confetti will begin.

Here's an example of toggling the ".active" class on a [confetti-target] element.
Confetti Trigger

Confetti Target

CSS
[confetti-target].active {
    position: relative;
}

[confetti-target].active > .particle {
    opacity: 0;
    position: absolute;
    animation: confetti 3s ease-in infinite;
    z-index: 0;
}
[confetti-target].active > .particle.c1 {
    background-color: #f47929;
}
[confetti-target].active > .particle.c2 {
    background-color: #f47929;
}

@keyframes [confetti-target] {
    0% {
        opacity: 0;
        transform: translateY(0%) rotate(0deg);
    }
    10% {
        opacity: 1;
    }
    35% {
        transform: translateY(-800%) rotate(270deg);
    }
    80% {
        opacity: 1;
    }
    100% {
        opacity: 0;
        transform: translateY(2000%) rotate(1440deg);
    }
}
Copy Code
jQuery

function initparticles() {
    confetti();
}

function confetti() {
    $.each($("[confetti-target].active"), function(){
        var confetticount = ($(this).width()/50)*5;
        for(var i = 0; i <= confetticount; i++) {
            $(this).append('<span class="particle c' + $.rnd(1,2) + '" style="top:' + $.rnd(10,50) + '%; left:' + $.rnd(0,100) + '%;width:' + $.rnd(6,8) + 'px; height:' + $.rnd(3,4) + 'px;animation-delay: ' + ($.rnd(0,30)/10) + 's;"></span>');
        }
    });
}

jQuery.rnd = function(m,n) {
    m = parseInt(m);
    n = parseInt(n);
    return Math.floor( Math.random() * (n - m + 1) ) + m;
}

initparticles();

$("[confetti-trigger]").on("click", function() {
   $(`[confetti-target=${$(this).attr('confetti-trigger')}]`).toggleClass("active");
   initparticles();
});
Copy Code

🎯 Sticky CTA Bar

Fixed Footer CTA Display logic

This script controls the display logic of a fixed footer call-to-action (CTA) element. It shows the fixed CTA when the user scrolls up and hides it when the user scrolls down.
jQuery
var lastScrollTop = 0;
var fixedNav = $('.fixed-footer-cta');
$(window).scroll(function() {
  var st = $(this).scrollTop();
  ((st < lastScrollTop)) ? fixedNav.slideDown(150) : fixedNav.slideUp(150);
  lastScrollTop = st;
});
Copy CodeCopy Webflow Component
{"type":"@webflow/XscpData","payload":{"nodes":[{"_id":"f5032ea6-3af0-b220-b5a1-66b1db3e0a24","type":"Block","tag":"div","classes":["91b1675b-f2f6-6b38-ecb9-b566d0ab8103"],"children":["e549b15b-dc65-567b-60f5-474fb670aa63"],"data":{"search":{"exclude":false},"xattr":[],"text":false,"displayName":"","devlink":{"runtimeProps":{},"slot":""},"attr":{"id":""},"visibility":{"conditions":[]},"tag":"div"}},{"_id":"e549b15b-dc65-567b-60f5-474fb670aa63","type":"Block","tag":"div","classes":["989b8211-9a25-2dd9-6dc5-d95b60618e3b"],"children":["2ddea78a-fe47-fb9a-2a9c-636c9c1e607d","0e91b977-4b0a-4ab8-cde8-c7fefdada272"],"data":{"search":{"exclude":false},"xattr":[],"text":false,"displayName":"","devlink":{"runtimeProps":{},"slot":""},"attr":{"id":""},"visibility":{"conditions":[]},"tag":"div"}},{"_id":"2ddea78a-fe47-fb9a-2a9c-636c9c1e607d","type":"Block","tag":"div","classes":["319311ed-2992-ebee-1dc8-aeebe4767702"],"children":["078a18bb-2091-1de3-4d97-8a7a2541b988"],"data":{"search":{"exclude":false},"xattr":[],"text":false,"displayName":"","devlink":{"runtimeProps":{},"slot":""},"attr":{"id":""},"visibility":{"conditions":[]},"tag":"div"}},{"_id":"078a18bb-2091-1de3-4d97-8a7a2541b988","type":"Block","tag":"div","classes":[],"children":["078a18bb-2091-1de3-4d97-8a7a2541b989"],"data":{"search":{"exclude":false},"xattr":[],"text":true,"displayName":"","devlink":{"runtimeProps":{},"slot":""},"attr":{"id":""},"visibility":{"conditions":[]},"tag":"div"}},{"_id":"078a18bb-2091-1de3-4d97-8a7a2541b989","text":true,"v":"Contact us to learn how our water systems are better than the rest!"},{"_id":"0e91b977-4b0a-4ab8-cde8-c7fefdada272","type":"Block","tag":"div","classes":["7d2e8abb-ae07-e6d7-ae9a-fe88cc9674c1"],"children":["ea06b163-1e10-5007-0bd1-f7b6944f313d","812ff0d9-4806-ad32-1117-126a281098dd"],"data":{"search":{"exclude":false},"xattr":[],"text":false,"displayName":"","devlink":{"runtimeProps":{},"slot":""},"attr":{"id":""},"visibility":{"conditions":[]},"tag":"div"}},{"_id":"ea06b163-1e10-5007-0bd1-f7b6944f313d","type":"Link","tag":"a","classes":["29f08a7e-59e0-9f0e-abfa-0e1a78b75cf4","f1f16c0d-1e29-db5b-511b-d04786a00088"],"children":["733450b5-1dd0-7caf-80e7-acf8b108014f"],"data":{"search":{"exclude":false},"xattr":[],"block":"inline","displayName":"","devlink":{"runtimeProps":{},"slot":""},"attr":{"id":"","href":"#"},"visibility":{"conditions":[]},"button":false,"link":{"mode":"external"}}},{"_id":"733450b5-1dd0-7caf-80e7-acf8b108014f","type":"Block","tag":"div","classes":[],"children":["733450b5-1dd0-7caf-80e7-acf8b1080150"],"data":{"search":{"exclude":false},"xattr":[],"text":true,"displayName":"","devlink":{"runtimeProps":{},"slot":""},"attr":{"id":""},"visibility":{"conditions":[]},"tag":"div"}},{"_id":"733450b5-1dd0-7caf-80e7-acf8b1080150","text":true,"v":"Contact Us"},{"_id":"812ff0d9-4806-ad32-1117-126a281098dd","type":"Link","tag":"a","classes":["29f08a7e-59e0-9f0e-abfa-0e1a78b75cf4","f1f16c0d-1e29-db5b-511b-d04786a00088","f84765fc-b784-85ef-eab2-2f07603fdd18"],"children":["812ff0d9-4806-ad32-1117-126a281098de"],"data":{"search":{"exclude":false},"xattr":[],"block":"inline","displayName":"","devlink":{"runtimeProps":{},"slot":""},"attr":{"id":""},"visibility":{"conditions":[]},"button":false},"bind":{"type":"Record","val":{"link":{"type":"Select","val":{"from":{"type":"Variable","val":"data"},"prop":"a8392d8d-9208-66cd-bed1-f41ccfe736a8"}}}}},{"_id":"812ff0d9-4806-ad32-1117-126a281098de","type":"Block","tag":"div","classes":[],"children":[],"data":{"text":true,"tag":"div","displayName":"","attr":{"id":""},"xattr":[],"search":{"exclude":false},"visibility":{"conditions":[]},"devlink":{"runtimeProps":{},"slot":""}},"bind":{"type":"Record","val":{"children":{"type":"Select","val":{"from":{"type":"Variable","val":"data"},"prop":"30b3dc42-769c-2efa-893f-e11cd5ca65d5"}}}}}],"styles":[{"_id":"91b1675b-f2f6-6b38-ecb9-b566d0ab8103","fake":false,"type":"class","name":"fixed-footer-cta","namespace":"","comb":"","styleLess":"position: fixed; left: 0px; bottom: 0px; z-index: 5; display: none; width: 100%; max-width: 100vw; padding-bottom: 0px; justify-content: space-between; align-items: center; border-top-style: solid; border-top-width: 1px; border-top-color: hsla(0, 0.00%, 0.00%, 0.10); background-color: whitesmoke; line-height: 1;","variants":{"small":{"styleLess":"border-top-style: none; background-color: transparent;"}},"children":[],"createdBy":"5e456b522ed599ad7ad8608c","selector":null},{"_id":"989b8211-9a25-2dd9-6dc5-d95b60618e3b","fake":false,"type":"class","name":"flex-apart-center","namespace":"","comb":"","styleLess":"display: flex; justify-content: space-between; align-items: center;","variants":{},"children":[],"createdBy":"5e456b522ed599ad7ad8608c","selector":null},{"_id":"319311ed-2992-ebee-1dc8-aeebe4767702","fake":false,"type":"class","name":"fixed-footer-cta-text","namespace":"","comb":"","styleLess":"padding-top: 1.1rem; padding-right: 1.1rem; padding-bottom: 1.1rem; padding-left: 1.1rem; font-weight: 700;","variants":{"small":{"styleLess":"display: none;"}},"children":[],"createdBy":"5e456b522ed599ad7ad8608c","selector":null},{"_id":"7d2e8abb-ae07-e6d7-ae9a-fe88cc9674c1","fake":false,"type":"class","name":"fixed-footer-cta-buttons","namespace":"","comb":"","styleLess":"display: flex; justify-content: flex-end;","variants":{"medium":{"styleLess":"width: 60%;"},"small":{"styleLess":"width: 100%;"}},"children":[],"createdBy":"5e456b522ed599ad7ad8608c","selector":null},{"_id":"29f08a7e-59e0-9f0e-abfa-0e1a78b75cf4","fake":false,"type":"class","name":"btn","namespace":"","comb":"","styleLess":"margin-top: 1rem; margin-right: 1rem; margin-left: auto; padding-top: 0.75em; padding-right: 1.5em; padding-bottom: 0.75em; padding-left: 1.5em; border-top-style: none; border-top-width: 1px; border-top-color: hsla(0, 0.00%, 0.00%, 0.00); border-right-style: none; border-right-width: 1px; border-right-color: hsla(0, 0.00%, 0.00%, 0.00); border-bottom-style: solid; border-bottom-width: 0.25rem; border-bottom-color: hsla(0, 0.00%, 0.00%, 0.10); border-left-style: none; border-left-width: 1px; border-left-color: hsla(0, 0.00%, 0.00%, 0.00); border-top-left-radius: 0.25rem; border-top-right-radius: 0.25rem; border-bottom-left-radius: 0.25rem; border-bottom-right-radius: 0.25rem; background-color: hsla(51, 100.00%, 45.00%, 1.00); transition-property: all; transition-duration: 300ms; transition-timing-function: ease-in-out; color: hsla(37.633136094674555, 0.00%, 100.00%, 1.00); line-height: 1; font-weight: 900; text-align: center; letter-spacing: 0.75px; text-decoration: none; text-transform: uppercase; white-space: normal;","variants":{"main_hover":{"styleLess":"background-color: hsla(51, 98.23%, 44.06%, 1.00); transform: translate(0px, -2px); color: hsla(37.633136094674555, 0.00%, 100.00%, 1.00);"}},"children":["29f08a7e-59e0-9f0e-abfa-0e1a78b75cf5","a43d9803-e949-fc82-512a-37c0833ab6d6","9b31c3cf-3344-33ed-2141-29f16842e011","20b4e55a-7004-3294-fc9a-82a9ef748b8c","823416bc-a671-b998-4d45-5fef28de3053","35098cc0-1fb8-3f49-95cc-a59c1cd63da2","f1f16c0d-1e29-db5b-511b-d04786a00088","b625920f-98f5-29ab-e3ae-900573856db4"],"selector":null},{"_id":"f1f16c0d-1e29-db5b-511b-d04786a00088","fake":false,"type":"class","name":"fixed-footer-cta-btn","namespace":"","comb":"&","styleLess":"height: 100%; margin-top: 0.5rem; margin-bottom: 0.5rem; margin-left: 0px;","variants":{"small":{"styleLess":"width: 50%; margin-top: 0rem; margin-right: 0rem; margin-bottom: 0rem;"},"tiny":{"styleLess":"display: flex; height: auto; justify-content: center; align-items: center;"}},"children":["f84765fc-b784-85ef-eab2-2f07603fdd18"],"createdBy":"5e456b522ed599ad7ad8608c","selector":null},{"_id":"f84765fc-b784-85ef-eab2-2f07603fdd18","fake":false,"type":"class","name":"btn-2","namespace":"","comb":"&","styleLess":"","variants":{},"children":[],"createdBy":"5e456b522ed599ad7ad8608c","selector":null}],"assets":[],"ix1":[],"ix2":{"interactions":[],"events":[],"actionLists":[]}},"meta":{"unlinkedSymbolCount":0,"droppedLinks":1,"dynBindRemovedCount":0,"dynListBindRemovedCount":0,"paginationRemovedCount":0}}

🤖 SEO Scripts

Canonicalize a paginated blog

This script adds canonical links to paginated CMS pages. It retrieves the previous and next page URLs from the pagination links and appends the appropriate tags to the website's head. Additionally, if the current page has a query parameter _page, indicating a paginated blog page, it adds a canonical link to the main CMS page.

⚠️ You must add this to the page-level footer code, no need to run this globally.
jQuery
var cms_prev_link = window.location.origin + window.location.pathname + $('.w-pagination-previous').attr('href');
var cms_next_link = window.location.origin + window.location.pathname + $('.w-pagination-next').attr('href');

if ($('.w-pagination-previous').attr('href')) {
  prev_canonical = "<link rel='prev' href="" + cms_prev_link.toString() +"" />";
  $('head').append(prev_canonical);
}

if ($('.w-pagination-next').attr('href')) {
  next_canonical = "<link rel='next' href="" + cms_next_link.toString() + "" />";
  $('head').append(next_canonical);
}

if (window.location.search.indexOf('_page=') > 0) {
  $('head').append("<link rel="canonical" href="" + window.location.origin + "/blog">");
}
Copy Code

Append tracking parameters to form fills

If a user hits the website after clicking an ad link, we want to store those URL parameters into cookies for the purpose of attaching those values to form fills.

⚠️ YOU MUST ADD THIS ABOVE (OUTSIDE OF) THE DOCUMENT READY FUNCTION
jQuery
// Get the value of the UTM parameters from the URL
const trackingParameters = new URLSearchParams(window.location.search);
const utmSourceValue = trackingParameters.get('utm_source');
const utmMediumValue = trackingParameters.get('utm_medium');
const utmCampaignValue = trackingParameters.get('utm_campaign');
const utmTermValue = trackingParameters.get('utm_term');
const utmContentValue = trackingParameters.get('utm_content');
const gclidValue = trackingParameters.get('gclid');
const _gclidValue = trackingParameters.get('_gclid');
const fbclidValue = trackingParameters.get('fbclid');
const campaignIdValue = trackingParameters.get('campaign_id');
const adGroupIdValue = trackingParameters.get('ad_group_id');
const creativeValue = trackingParameters.get('creative');
const matchTypeValue = trackingParameters.get('match_type');
const networkValue = trackingParameters.get('network');
const deviceValue = trackingParameters.get('device');
const keywordValue = trackingParameters.get('keyword');

// Check if the parameters exist and set cookies accordingly
if (utmSourceValue) {
  document.cookie = `utmSource=${utmSourceValue}; path=/;`;
}
if (utmMediumValue) {
  document.cookie = `utmMedium=${utmMediumValue}; path=/;`;
}
if (utmCampaignValue) {
  document.cookie = `utmCampaign=${utmCampaignValue}; path=/;`;
}
if (utmTermValue) {
  document.cookie = `utmTerm=${utmTermValue}; path=/;`;
}
if (utmContentValue) {
  document.cookie = `utmContent=${utmContentValue}; path=/;`;
}
if (gclidValue) {
  const expiryDate = new Date();
  expiryDate.setDate(expiryDate.getDate() + 90); // 90 days
  document.cookie = `gclid=${gclidValue}; path=/; expires=${expiryDate.toUTCString()};`;
}
if (_gclidValue) {
  const expiryDate = new Date();
  expiryDate.setDate(expiryDate.getDate() + 90); // 90 days
  document.cookie = `_gclid=${_gclidValue}; path=/; expires=${expiryDate.toUTCString()};`;
}
if (fbclidValue) {
  const expiryDate = new Date();
  expiryDate.setDate(expiryDate.getDate() + 7); // 7 days
  document.cookie = `fbclid=${fbclidValue}; path=/; expires=${expiryDate.toUTCString()};`;
}
if (campaignIdValue) {
  document.cookie = `campaignId=${campaignIdValue}; path=/;`;
}
if (adGroupIdValue) {
  document.cookie = `adGroupId=${adGroupIdValue}; path=/;`;
}
if (creativeValue) {
  document.cookie = `creative=${creativeValue}; path=/;`;
}
if (matchTypeValue) {
  document.cookie = `matchType=${matchTypeValue}; path=/;`;
}
if (networkValue) {
  document.cookie = `network=${networkValue}; path=/;`;
}
if (deviceValue) {
  document.cookie = `device=${deviceValue}; path=/;`;
}
if (keywordValue) {
  document.cookie = `keyword=${keywordValue}; path=/;`;
}
Copy Code
⚠️ YOU MUST ADD THIS INSIDE OF THE DOCUMENT READY FUNCTION
jQuery
// Get the value of the cookies
const utmSourceValue = getCookie("utmSource");
const utmMediumValue = getCookie("utmMedium");
const utmCampaignValue = getCookie("utmCampaign");
const utmTermValue = getCookie("utmTerm");
const utmContentValue = getCookie("utmContent");
const gclidValue = getCookie("gclid");
const _gclidValue = getCookie("_gclid");
const fbclidValue = getCookie("fbclid");
const campaignIdValue = getCookie("campaignId");
const adGroupIdValue = getCookie("adGroupId");
const creativeValue = getCookie("creative");
const matchTypeValue = getCookie("matchType");
const networkValue = getCookie("network");
const deviceValue = getCookie("device");
const keywordValue = getCookie("keyword");

// Append UTM Sources as hidden fields to each form
jQuery('form').append(`<input type="hidden" id="utmSource" name="UTM Source" value="${utmSourceValue}" />`);
jQuery('form').append(`<input type="hidden" id="utmMedium" name="UTM Medium" value="${utmMediumValue}" />`);
jQuery('form').append(`<input type="hidden" id="utmCampaign" name="UTM Campaign" value="${utmCampaignValue}" />`);
jQuery('form').append(`<input type="hidden" id="utmTerm" name="UTM Term" value="${utmTermValue}" />`);
jQuery('form').append(`<input type="hidden" id="utmContent" name="UTM Content" value="${utmContentValue}" />`);
jQuery('form').append(`<input type="hidden" id="gclid" name="Gclid" value="${gclidValue}" />`);
jQuery('form').append(`<input type="hidden" id="fbclid" name="Fbclid" value="${fbclidValue}" />`);
jQuery('form').append(`<input type="hidden" id="campaignId" name="Campaign ID" value="${campaignIdValue}" />`);
jQuery('form').append(`<input type="hidden" id="adGroupId" name="Ad Group ID" value="${adGroupIdValue}" />`);
jQuery('form').append(`<input type="hidden" id="creative" name="Creative" value="${creativeValue}" />`);
jQuery('form').append(`<input type="hidden" id="matchType" name="Match Type" value="${matchTypeValue}" />`);
jQuery('form').append(`<input type="hidden" id="network" name="Network" value="${networkValue}" />`);
jQuery('form').append(`<input type="hidden" id="device" name="Device" value="${deviceValue}" />`);
jQuery('form').append(`<input type="hidden" id="keyword" name="Keyword" value="${keywordValue}" />`);
Copy Code

Store form values as first-party cookies for GTM

An event listener is added to form elements with the "gtm" attribute. Whenever a change event occurs, the script captures the attribute value ("gtm") and the corresponding input value. It then sets a cookie with the "gtm" attribute value as the name and the input value as the value.

⚠️ You must add a custom attribute named "gtm" to each input you want stored. The value should exactly match the name of your cookie in GTM (case-sensitive).
jQuery
// Get the base website URL
var baseUrl = document.location.hostname;

// Function to convert phone numbers to E.164 format
function toE164(phoneNumber) {
  // Remove everything except digits
  var digits = phoneNumber.replace(/\D/g, "");
  // If it has 10 digits, assume it's a US number and add +1
  if (digits.length === 10) {
    return "+1" + digits;
  }
  // If it already includes country code (like 11 digits starting with 1)
  else if (digits.length === 11 && digits.startsWith("1")) {
    return "+" + digits;
  }
  // Otherwise, return as-is
  return phoneNumber;
}

// Event listener for changes in form elements with "gtm" attribute
$("form [gtm]").on("change", function() {
  var input = $(this);
  var name = input.attr("gtm"); // Get the "gtm" attribute value for naming the cookie
  var value = input.val();

  // If the input is a tel type, convert the phone number to E.164 format
  if (input.attr("type") === "tel") {
    value = toE164(value);
  }

  if (input.attr("type") === "checkbox") {
    var checkboxes = $("form [gtm='" + name + "']:checked");
    var values = checkboxes.map(function() {
      return this.value;
    }).get().join(",");
    document.cookie = name + "=" + values + "; path=/; domain=" + baseUrl;
  } else if (input.attr("type") === "radio") {
    var radioButtons = $("form [gtm='" + name + "']");
    radioButtons.each(function() {
      if ($(this).prop("checked")) {
        document.cookie = name + "=" + $(this).val() + "; path=/; domain=" + baseUrl;
      }
    });
  } else {
    document.cookie = name + "=" + value + "; path=/; domain=" + baseUrl;
  }
});
Copy Code
Green digital face with a Matrix-style effect.