I got asked by a subscriber how they could track UTM parameters on the first touch to their website from all mediums, campaigns, etc because contacts where coming to their website, navigating around and then submitting forms. After I helped them they no longer had a massive black hole in their campaign analytics. Here is exactly how to do it.
Greg Staunton
Solution
Eloqua Conversion Tags using Google Tag Manager
We are going to use Google Tag Manager (GTM) to:
- Capture first touch UTM parameters from the landing page URL
- Store them in first party cookies that persist across pages and subdomains
- Read user submitted values from forms
- Send everything into Eloqua as a conversion using a lightweight JavaScript tag
Introduction
Let us break this down. In this article I am going to prove 3 things:
- Add UTM marketing source parameters to a cookie to retrieve them later at the point of conversion.
- Take user submitted values from forms.
- Create a Javascript that will successfully send the above data to Eloqua.
I am glad to say that I was able to achieve all of these things technically, and this article outlines how that is achieved in GTM, and how it could be replicated across your entire website.
To make this practical, I have also included a full working code example that you or your developer can paste into a website and adapt to your own Eloqua form and UTM strategy.
Step 1 - Get the UTM marketing source parameters into a cookie
This is achievable by creating a variable that takes values from query string, and then setting a cookie when these variables are detected.
Your original GTM approach looks like this:
- Create new User-defined variables of type URL and select component type query. Enter the key of the query string variable you want to use, e.g.
utm_medium. - Create a new trigger to fire on page load when
utm_mediumdoes not equalundefined. - Create a tag to set the cookie referencing the query string parameters, e.g.
// Simple GTM example for concatenated UTM cookie
document.cookie = "utmParams={{utm_medium}}_{{utm_source}}_{{utm_campaign}}_{{utm_content}}; path=/; domain=.acme.com;";
In this example, the cookie will persist across all acme.com subdomains. You can then create a 1st party cookie variable in GTM which simply references the name of the required cookie.
Below is a more complete, production ready version that stores each UTM in its own cookie and preserves only first touch.
First touch UTM capture script
// 1. FIRST TOUCH UTM CAPTURE
var utmKeys = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
function getQueryParam(param) {
var urlParams = new URLSearchParams(window.location.search);
return urlParams.get(param);
}
function setFirstTouchUTMs() {
// Only set once - preserves original acquisition source
if (document.cookie.indexOf("ft_utm_source=") !== -1) return;
var baseDomain = window.location.hostname.replace(/^www\./, "");
utmKeys.forEach(function(key) {
var value = getQueryParam(key);
if (value) {
document.cookie = "ft_" + key + "=" + encodeURIComponent(value) +
"; path=/; domain=" + baseDomain + ";";
}
});
// Store first landing page and timestamp
document.cookie = "ft_landing_page=" + encodeURIComponent(window.location.href) +
"; path=/; domain=" + baseDomain + ";";
document.cookie = "ft_timestamp=" + Date.now() +
"; path=/; domain=" + baseDomain + ";";
}
setFirstTouchUTMs();
You can use this directly in a custom HTML tag in GTM, or inline on your site template if you are not using GTM for some properties.
Step 2 - User submitted values in the forms
Your original solution on the login page used jQuery and a specific field id:
// Original jQuery based example
function(){
var loginEmail = $('#Email').val();
return loginEmail;
}
This is achievable where form fields have specific IDs. Where not, we can also get these using GTM data layer variables, in this example:
gtm.element.2.value
To make this more robust and easier to lift across sites, here is a simple vanilla JavaScript helper that looks for common field names and ids.
Reusable form extraction helper
// 2. FORM FIELD EXTRACTION
function getFieldValue(selector) {
var el = document.querySelector(selector);
return el ? el.value : "";
}
function extractFormData(formElement) {
return {
email: getFieldValue("#Email") ||
getFieldValue("input[name='EmailAddress']") ||
getFieldValue("input[name='email']"),
firstName: getFieldValue("#FirstName") ||
getFieldValue("input[name='FirstName']"),
lastName: getFieldValue("#LastName") ||
getFieldValue("input[name='LastName']")
};
}
You can easily extend this to capture phone, company, product interest and anything else you want to post into Eloqua or a CDO.
Step 3 - Creating the conversion tag for Eloqua
Your original Eloqua conversion example looked like this:
// Original example using a GTM variable
var emailStr = '{{Login Email}}';
var htmlStr = 'https://s25071713.t.en25.com/e/f2.aspx?elqFormName=GS_GTM_TEST&elqSiteID=25071713&EmailAddress='
+ encodeURIComponent(emailStr);
var req = new XMLHttpRequest();
req.open('GET', htmlStr, true);
req.send();
The below code references the GTM variable {{Login Email}} and successfully sends it to Eloqua as a conversion. We can add more fields and add them to the string.
Using this example as a template, we could create tracking events for the various conversions on ACME and send the required data to Eloqua on each form submit.
Extended Eloqua conversion with UTM parameters
// 3. READ COOKIES AND SEND TO ELOQUA
function getCookie(name) {
var match = document.cookie.match(new RegExp("(^| )" + name + "=([^;]+)"));
return match ? decodeURIComponent(match[2]) : "";
}
function getFirstTouchUTMs() {
var result = {};
["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"].forEach(function(key) {
result[key] = getCookie("ft_" + key) || "";
});
result.landingPage = getCookie("ft_landing_page") || "";
result.timestamp = getCookie("ft_timestamp") || "";
return result;
}
function sendToEloqua(formData, utmData) {
// Replace with your Eloqua form and site id
var elqFormName = "GS_GTM_TEST";
var elqSiteID = "25071713";
var qs = "?elqFormName=" + elqFormName +
"&elqSiteID=" + elqSiteID +
"&EmailAddress=" + encodeURIComponent(formData.email) +
"&FirstName=" + encodeURIComponent(formData.firstName) +
"&LastName=" + encodeURIComponent(formData.lastName) +
"&FT_Source=" + encodeURIComponent(utmData.utm_source) +
"&FT_Medium=" + encodeURIComponent(utmData.utm_medium) +
"&FT_Campaign=" + encodeURIComponent(utmData.utm_campaign) +
"&FT_Content=" + encodeURIComponent(utmData.utm_content) +
"&FT_Term=" + encodeURIComponent(utmData.utm_term) +
"&FT_Landing_Page=" + encodeURIComponent(utmData.landingPage) +
"&FT_Timestamp=" + encodeURIComponent(utmData.timestamp);
var url = "https://s25071713.t.en25.com/e/f2.aspx" + qs;
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.send();
}
Tie it all together on form submit
// 4. AUTO BIND ON FORM SUBMIT
document.addEventListener("submit", function(e) {
var form = e.target;
// Add a simple opt out option on forms if needed
if (form && form.getAttribute("data-eloqua-track") === "false") return;
var formData = extractFormData(form);
var utmData = getFirstTouchUTMs();
// Only send to Eloqua if we have an email address
if (formData.email) {
sendToEloqua(formData, utmData);
}
});
You can add data-eloqua-track="false" to any form that should not trigger the Eloqua conversion event. For example internal search, newsletter popups you do not want tied to this process, or very specific workflows.
Conclusion
This approach has been a great success for the client. They have razer sharp reporting no matter what the user does. We implemented some other things so we could record first and last touch for greater reporting capabilities though that is a story for another day.
The pattern is simple:
- Capture UTM parameters once at first touch.
- Persist them in first party cookies across all pages and subdomains.
- Read those values and the user submitted form fields at the moment of conversion.
- Post everything into Eloqua so you can use it for segmentation, reporting and CDO based attribution.
Once you have this in place, you can start layering on additional richness such as last touch tracking, GA4 client id capture, page category fields and multi touch CDO structures.
Original minimal example code
Here is all the code you need to get this holy grail of tracking set up in its simplest original form, exactly as I first wrote it:
document.cookie = "utmParams={{utm_medium}}_{{utm_source}}_{{utm_campaign}}_{{utm_content}}; path=/; domain=.acme.com;";
// this code references the ID of the email address field on the login form.
// We can replicate this for all form fields with an ID
function(){
var loginEmail = $('#Email').val();
return loginEmail;
}
// This code sends the required URL to Eloqua,
// it is just var htmlStr that needs to change for each different form
var emailStr = '{{Login Email}}';
The extended examples above show how to harden and generalise this pattern for more complex production environments, but the original pattern remains the same.
Want clean, trustworthy UTM attribution flowing into Eloqua?
I help teams implement bulletproof first-touch and last-touch attribution using GTM, GA4 and Eloqua. Whether your data is unreliable, incomplete or your agency over-engineered it, I can rebuild your tracking so every lead is correctly sourced and every report finally makes sense.