Hello,
How do I set up cookie-based UTM tracking in Marketo? I want to be able to track source even if a person navigates away from the URL with the UTM parameters.
Is it possible to track, if UTM URL parameters not in URL, set cookie values, and if UTM URL parameters is present, set those.
Solved! Go to Solution.
There are a number of JS libraries for this purpose, from the rudimentary to the robust to the ridiculously buggy. ConversionPath and the Digital Pi tracker are two you can trust.
But I’d suggest something even simpler: a UTM Forwarder (or more generally, a Query Param Forwarder) which simply picks up the UTM params and forwards them from page to page — unless the pageview originally had its own UTMs, of course. Then you continue to Auto-Fill from the query string.
You can place this code on every page, making sure it comes before the Forms 2.0 library on those pages that have forms:
/**
* Simple Same-Origin Query Param Forwarder
* @author Sanford Whiteman, TEKNKL (blog.teknkl.com / sandy@teknkl.com)
* @version v2.0.1
* @copyright Copyright 2024 FigureOne, Inc.
* @license MIT License: You must include this license and the above credits in all uses & reproductions of this software.
*/
function forwardParams(userOpts){
let defaultOpts = {
storageArea: "local",
storageKey: "last_utmified_query",
interestingParams: ["utm_campaign", "utm_medium", "utm_source", "utm_content", "utm_term"],
expireMins: 30,
restore: true,
restoreTS: false
};
let opts = Object.assign({}, defaultOpts, userOpts);
let current = {
state: new URL(document.location.href),
time: new Date().getTime()
};
let storage = {
area: window[opts.storageArea + "Storage"],
key: opts.storageKey
};
for( [paramName] of [...current.state.searchParams] ) {
if( !opts.interestingParams.includes(paramName) ) {
current.state.searchParams.delete(paramName);
}
}
if( current.state.searchParams.size ) {
storage.area[storage.key] = JSON.stringify({
time: current.time,
query: current.state.searchParams.toString()
});
} else {
let restorable = JSON.parse(storage.area[storage.key] || '""');
if ( !restorable || !opts.restore ) return;
if ( current.time - restorable.time <= opts.expireMins * 6E4 ) {
let updated = {
state: new URL(document.location.href)
};
for( [paramName,paramValue] of new URLSearchParams(restorable.query) ) {
updated.state.searchParams.append(paramName, paramValue);
}
if(opts.restoreTS) {
updated.state.searchParams.set("utmified_ts", restorable.time);
}
history.replaceState("", {}, updated.state.href);
}
}
}
forwardParams();
The last line runs the forwarder function with default options:
To change the options, pass an object to forwardParams()
. For example, if you want set a shorter expiry for testing, do this instead:
forwardParams({
expireMins: 1
});
There are a number of JS libraries for this purpose, from the rudimentary to the robust to the ridiculously buggy. ConversionPath and the Digital Pi tracker are two you can trust.
But I’d suggest something even simpler: a UTM Forwarder (or more generally, a Query Param Forwarder) which simply picks up the UTM params and forwards them from page to page — unless the pageview originally had its own UTMs, of course. Then you continue to Auto-Fill from the query string.
You can place this code on every page, making sure it comes before the Forms 2.0 library on those pages that have forms:
/**
* Simple Same-Origin Query Param Forwarder
* @author Sanford Whiteman, TEKNKL (blog.teknkl.com / sandy@teknkl.com)
* @version v2.0.1
* @copyright Copyright 2024 FigureOne, Inc.
* @license MIT License: You must include this license and the above credits in all uses & reproductions of this software.
*/
function forwardParams(userOpts){
let defaultOpts = {
storageArea: "local",
storageKey: "last_utmified_query",
interestingParams: ["utm_campaign", "utm_medium", "utm_source", "utm_content", "utm_term"],
expireMins: 30,
restore: true,
restoreTS: false
};
let opts = Object.assign({}, defaultOpts, userOpts);
let current = {
state: new URL(document.location.href),
time: new Date().getTime()
};
let storage = {
area: window[opts.storageArea + "Storage"],
key: opts.storageKey
};
for( [paramName] of [...current.state.searchParams] ) {
if( !opts.interestingParams.includes(paramName) ) {
current.state.searchParams.delete(paramName);
}
}
if( current.state.searchParams.size ) {
storage.area[storage.key] = JSON.stringify({
time: current.time,
query: current.state.searchParams.toString()
});
} else {
let restorable = JSON.parse(storage.area[storage.key] || '""');
if ( !restorable || !opts.restore ) return;
if ( current.time - restorable.time <= opts.expireMins * 6E4 ) {
let updated = {
state: new URL(document.location.href)
};
for( [paramName,paramValue] of new URLSearchParams(restorable.query) ) {
updated.state.searchParams.append(paramName, paramValue);
}
if(opts.restoreTS) {
updated.state.searchParams.set("utmified_ts", restorable.time);
}
history.replaceState("", {}, updated.state.href);
}
}
}
forwardParams();
The last line runs the forwarder function with default options:
To change the options, pass an object to forwardParams()
. For example, if you want set a shorter expiry for testing, do this instead:
forwardParams({
expireMins: 1
});
Awesome!!!! Thank you.
So I need to copy to every page on the website.
Would it work putting it in site wide script in the header?
Sure, you can put it in an external .js file which is easier to manage. Just make sure it's on every page, since naturally you need to pick up UTMs wherever they may be.
I've added the code to one of our subdomain websites, sitewide header code, used a UTM link to land on the website, went to an internal page, and submitted a form, but none of the UTM parameters got added to the person record.
Is there any changes needed on the form to accept the different UTMs?
This is no an marketo landing page, its external.
For marketo landing pages
how do I link an external JS file in Marketo with landing page templates? Should I copy the code and put it into the template?
You'll have to link to your pages(s), nothing to look at without that.
You can save the code to a .js file and upload it to Design Studio. Then link to that <script>
in the <head>
.
The code has been applied site wide.
I went from home page, with UTM URL, click on case study page, and submitted a market form. But nothing
Without having a link to your page I can't do anything else.
{domain remove}
Working as expected for me.
(1) Navigated to:
https://gimessentials.acquire.com.au/gim-essentials-transforms-geological-data-management-processes/?utm_medium=my-medium&utm_source=my-source
(2) Observed query string persisted to localStorage:
(3) Within the next few seconds, navigated to:
https://gimessentials.acquire.com.au/
(4) Observed the persisted query params immediately restored to current URL:
(5) Observed the corresponding hidden fields populated on both forms from query params, per Form Editor config:
Ahh, I change the hidden fields in the form to capture Cookie parameters, before I had it just on URL parameters so it didn't write. Tested, and working.
Thank you so much for that help! Amazing
Not sure I understand your response. The form must fill from query params. Cookies are not used by this code.
Yeah ignore that post. I was thinking about cookies again.
I have managed to set up the Javascript across a couple of domains and it looks like its working, fantastic. Is it possible to also carry forward UTM's across domains.
For example, a user goes from our primary domain acquire.com.au to market landing page URLs page.acquire.com.au?
Do you also have code written for this scenario?
Do you also have code written for this scenario?
When falling back on cookies I have a whole other JS library with more features. But this simple forwarder could be enhanced with cookie support. Will add that at some point.
@KyleacQuire please return to your thread and check responses.