Google Tag Manager code for capturing GCLID and MSCLKID parameters in HubSpot

I managed to get GCLID tracking working with the script below in Google Tag Manager to update my HubSpot contacts. But I’m stuck on adding MSCLKID (Microsoft Click ID from Bing Ads) to the same setup.

Can someone help me modify this to capture both click IDs in one script? I’d prefer to keep everything in a single tag if that’s possible.

function extractParameter(paramName) {
  var regex = RegExp('[?&]' + paramName + '=([^&]*)');
  var result = regex.exec(window.location.search);
  return result && decodeURIComponent(result[1].replace(/\+/g, ' '));
}

function createStorageRecord(paramValue) {
  var expirationTime = 90 * 24 * 60 * 60 * 1000; // 90 days in milliseconds
  var futureDate = new Date().getTime() + expirationTime;
  
  return {
    paramValue: paramValue,
    expiration: futureDate
  };
}

function handleGoogleClickId() {
  var googleClickId = extractParameter('gclid');
  var formFieldIds = ['google_click_id', 'gc_tracking']; // form field IDs for gclid
  var storedRecord = null;
  var targetFormField;

  var gclSource = extractParameter('gclsrc');
  var validSource = !gclSource || gclSource.indexOf('aw') !== -1;

  formFieldIds.forEach(function (fieldId) {
    if (document.getElementById(fieldId)) {
      targetFormField = document.getElementById(fieldId);
    }
  });

  if (googleClickId && validSource) {
    storedRecord = createStorageRecord(googleClickId);
    localStorage.setItem('google_click_tracking', JSON.stringify(storedRecord));
  }

  var clickData = storedRecord || JSON.parse(localStorage.getItem('google_click_tracking'));
  var isDataValid = clickData && new Date().getTime() < clickData.expiration;

  if (targetFormField && isDataValid) {
    targetFormField.value = clickData.paramValue;
  }
}

window.addEventListener('load', handleGoogleClickId);

I already set up the custom property in HubSpot and added it as a hidden field to my forms. The Google tracking works fine but I really need the Microsoft Ads tracking too.

I’m not much of a developer so I mostly work by copying existing solutions, but there doesn’t seem to be much documentation for Microsoft Ads compared to Google Ads tracking.

I ran into this exact issue a few months ago when we added Bing campaigns to our Google Ads setup. Your current structure will work perfectly for MSCLKID - Microsoft uses the same URL parameter approach. Just extend your existing function to handle MSCLKID too. The main difference? Microsoft doesn’t use a source parameter like Google’s gclsrc, so validation’s actually simpler. I’d build a generic function that takes parameter names and field IDs as arguments, then call it for both gclid and msclkid. One big lesson I learned - create separate hidden fields in HubSpot for each click ID. I tried combining them into one field at first and it caused data conflicts when users came from different sources. Also, MSCLKID has the same 90-day attribution window as Google, so your current expiration logic works for both.