-
-
Save keithws/c3a93663da38630be0cf00924fdbbbe4 to your computer and use it in GitHub Desktop.
<script> | |
/** | |
* push events to Google Tag Manager when the Marketo Forms 2 Javascript is | |
* loaded and executed and when Marketo form events occur | |
* uses the Marketo Forms 2.0 API | |
* http://developers.marketo.com/documentation/websites/forms-2-0/ | |
* | |
* @author Keith W. Shaw <[email protected]> | |
* @license MIT | |
*/ | |
(function marketoFormListener () { | |
"use strict"; | |
/** | |
* poll for global MktoForms2 variable to be defined | |
* @returns {undefined} | |
*/ | |
function pollForMktoForms2 (delay) { | |
if (isNaN(delay)) { | |
throw new Error("Expected delay (" + delay + ") to be a number."); | |
} | |
if (window.MktoForms2) { | |
// mark the start of the script loading | |
window.dataLayer = window.dataLayer || []; | |
window.dataLayer.push({ | |
"event": "mkto.form.js", | |
"mkto.form.start": (new Date()).getTime() | |
}); | |
// bind liseners for all Marketo Form events | |
addMktoForms2Listeners(window.MktoForms2); | |
} else { | |
// keep polling, but progressively increase the delay | |
setTimeout(pollForMktoForms2.bind(null, 2 * delay), delay); | |
} | |
} | |
/** | |
* helper function to push invalid Marketo field errors to GTM | |
* @returns {undefined} | |
*/ | |
function waitForError () { | |
var element, input, mktoErrorMsg; | |
// check for error message | |
element = document.querySelector(".mktoErrorMsg"); | |
if (element) { | |
mktoErrorMsg = element.textContent || element.innerText; | |
// look for invalid input | |
input = document.querySelector("input.mktoInvalid, .mktoInvalid input"); | |
window.dataLayer.push({ | |
"event": "mkto.form.error", | |
"mkto.form.error.message": mktoErrorMsg, | |
"gtm.element": input, | |
"gtm.elementClasses": input && input.className || "", | |
"gtm.elementId": input && input.id || "", | |
"gtm.elementName": input && input.name || "", | |
"gtm.elementTarget": input && input.target || "" | |
}); | |
} | |
} | |
/** | |
* setup Marketo Form listeners to push events to GTM | |
* @returns {undefined} | |
*/ | |
function addMktoForms2Listeners (MktoForms2) { | |
MktoForms2.whenReady(function handleReady (form) { | |
window.dataLayer.push({ | |
"event": "mkto.form.ready", | |
"mkto.form.id": form.getId(), | |
"mkto.form.submittable": form.submittable(), | |
"mkto.form.allFieldsFilled": form.allFieldsFilled(), | |
"mkto.form.values": form.getValues() | |
}); | |
form.onValidate(function handleValidate (valid) { | |
window.dataLayer.push({ | |
"event": "mkto.form.validate", | |
"mkto.form.valid": valid | |
}); | |
// wait for the error message to appear | |
setTimeout(waitForError, 0); | |
}); | |
form.onSubmit(function handleSubmit (thisForm) { | |
var button; | |
button = thisForm.getFormElem().find("button[type=\"submit\"]"); | |
window.dataLayer.push({ | |
"event": "mkto.form.submit", | |
"mkto.form.id": thisForm.getId(), | |
"mkto.form.submittable": thisForm.submittable(), | |
"mkto.form.allFieldsFilled": thisForm.allFieldsFilled(), | |
"mkto.form.values": thisForm.getValues(), | |
"mkto.form.button": { | |
"classes": button.attr("class"), | |
"text": button.text(), | |
"type": "submit" | |
} | |
}); | |
}); | |
form.onSuccess(function handleSuccess (values, followUpUrl) { | |
window.dataLayer.push({ | |
"event": "mkto.form.success", | |
"mkto.form.values": values, | |
"mkto.form.followUpUrl": followUpUrl | |
}); | |
}); | |
}); | |
MktoForms2.whenRendered(function handleRendered (form) { | |
window.dataLayer.push({ | |
"event": "mkto.form.rendered", | |
"mkto.form.id": form.getId(), | |
"mkto.form.submittable": form.submittable(), | |
"mkto.form.allFieldsFilled": form.allFieldsFilled(), | |
"mkto.form.values": form.getValues() | |
}); | |
}); | |
} | |
// start polling with an initial delay of 125ms | |
pollForMktoForms2(125); | |
}()); | |
</script> |
I updated this code to work even when the Marketo Forms 2 JavaScript is loaded after GTM. It works by polling for the existence of the MktoForm2 global variable. Don't worry, the polling has an exponential decay, so it won't slow down pages that do not load Marketo. Also, a new custom event, mkto.form.js
, is pushed into the GTM data layer when the MktoForm2 global variable is detected.
Thank you so much for this!! I'm new to Marketo but comfortable enough with GTM and GA that this makes sense to me. Really looking forward to trying it out.
Ideal, Keith. Cheers for the work here
Thanks Keith I think this is exactly what I've been looking for!!
However I'm not a developer, more a technical marketer, so forgive me but I have a couple of questions...
- I'm assuming this is implemented as a Custom HTML Tag via GTM, and fired on Pageview?
- It looks like your code automatically adds the callback parameter described in the marketo API documentation here? https://developers.marketo.com/javascript-api/forms/ - meaning I don't need to do anything to the marketo form code, right?
- You've already mentioned that code won't slow down pages that do not load Marketo - but what impact does it have on the speed of the pages that do load Marketo?
In my experience, Marketo does not support multiple forms on one page. ¯\(ツ)/¯
This gist gets the Market Form ID by calling the Marketo Forms 2 API method
getId()
on theform
object passed as the first argument to the callback function for each event listener provided by the Marketo Forms 2 API.