Really, finally winning the Marketo Forms vs. Tracking Protection battle

Update 2020-11-01: You no longer need the method outlined here. As of October 2020, Marketo has modified the Forms 2.0 library to load its hidden IFRAME from the same domain as the form.

💡
This post is only a historical document.

While you should be loading embedded forms from your Marketo LP domain, it turns out just changing the URL is not enough.

Using a non-Marketo-owned domain to load forms2.min.js and call loadForm() seems to avoid collateral damage from Tracking Protection (Firefox’s built-in feature or the equivalent plugin for another browser). The form will at least show up on the page if you do that.

But – I’m sure you will be dismayed to learn – the form still won’t post under TP! You also need to upload a file to Design Studio and add a tiny bit of JavaScript. Then and only then are you good to go.

First, download (Right-click, Save link as) this file:

marketo-xdframe-relative.html

Next, upload the file to Design Studio. To be clear, you’re not creating an LP, you’re uploading the file as static HTML. This may not be something you’ve done before (you probably upload images, CSS, and PDFs) but Marketo actually supports any kind of file.

Screenshot after it’s been uploaded to Design Studio:

ss

Then replace your embed code with this ever-so-slightly different version:

<script src="//pages.example.com/js/forms2/js/forms2.min.js"></script>
<form id="mktoForm_9999"></form>
<script>
   MktoForms2.setOptions({
     formXDPath : "/rs/123-ABC-456/images/marketo-xdframe-relative.html"
   });
   MktoForms2.loadForm("//pages.example.com", "123-ABC-456", 9999);
</script>

Where:

  • 123-ABC-456 represents your Munchkin ID
  • pages.example.com represents your Marketo LP domain
  • 9999 is o’course your form ID

A live demo (though all the code is above):

The why

Using your LP domain enables forms to show up. But there’s a special asset, only used upon submission, that will still be blocked by default. Naturally, this only reveals itself when you run end-to-end tests.

See, embedded forms use an IFRAME message relay (XDFrame) for cross-domain posts (there are other ways to do it, but they’re not as backward-compatible and the IFRAME method works fine + fast in all browsers, even back to IE8).

But the IFRAMEd document loads forms2.min.js from an absolute URL with your instance hostname, i.e. app-xxnn.marketo.com:

ss

Oops! Tracking Protection ain’t gonna let that load, for the same reason it doesn’t like a Marketo domain in the main document. (You can’t avoid TP by using an IFRAME, that would be silly.) As you can see, the replacement XDFrame file uses a relative URL (/js/forms2/js/forms2.min.js), so it loads from your Marketo LP domain like the rest of the assets. Presto! No marketo.com for TP to get all paranoid about.


Notes

The forms2.min.js inside the IFRAME is only loaded because of its bundled (ugh, I hate jQuery so much) jQuery library. One could replace the code screenshotted above with native window.addEventListener("message" ... and a homebrewed Ajax routine. Not that using $.ajax doesn’t save you time over building the latter, it’s just… well, I hate loading a big framework just for this (though forms2.min.js is cached, as long as outer and inner URLs match).