Fixing Marketo pURLs

It's well-known that Marketo's pURL feature, out-of-the-box, has a fatal (and kinda fascinating) shortcoming.[1] If someone has visited your site before — meaning either an anonymous or associated Munchkin session — then pURL-enabled pages aren't functional.

When there's an existing anonymous session, the server ignores the personalized part of the URL (the Marketo Unique Name /JillSmith02 or Unique Code /XYZPDQ) and serves up default/empty content.[2]

On the other hand, if the person has never been to your site on their current device, pURLs work fine.

Unfortunately, then, pURLs work only for people who who either [a] just got a new PC or phone or [b] have been living under a relative rock. Not exactly the widest audience!

Luckily, it's always been possible to fix the strange session behavior with a little JavaScript. I've packaged the fix in my slowly-growing FormsPlus library instead of just pasting it into this post.

Get fixed

First, make sure you have the FormsPlus base library followed by the FormsPlus-pURL lib loaded in your <head>:

<script id="teknklFormsPlus-base-1.0.3" 
<script id="teknklFormsPlus-purl-1.0.0" 

Then, also in your <head>, run the one-liner:


In the vast majority of cases, that's all you need; no need to pass any options to fixSession().

Again, it's critical that you load the remote <script>s and then run fixSession() as high up in the <head> as possible. The main reason is you need to make sure that Munchkin.init() runs after this special pURL stuff. When Munchkin's enabled on Marketo-hosted LPs, init() is automatically injected at the base of the page (just inside </body>) which is great, but in rare cases you might've formally disabled Munchkin and then re-added it yourself (?).

Advanced fixSession() options

If you deliberately are not setting your Munchkin cookie at the highest possible level, you have to tell fixSession() that.

You should recall that Munchkin doesn't set cookies correctly for 2-letter domains. So by default, Munchkin on will its the cookie only for so it can't be shared with FormsPlus.pURL.fixSession includes a fix for this behavior, so the cookie will be (re)set at as is usually desired.

If for some reason you currently rely on the buggy behavior and don't want it fixed, then you'll want to override cookieDomain:


Similarly, if you set Munchkin cookies to expire in less (or more) than the default 730 days, pass expireDays:


And if you want to use the same code even when the lead isn't on a pURLs (it's also relevant to problems like this, by the way) then set alwaysEnable:

How the fix works

Might insert a cool-looking flow diagram later, but let me put it in words for now:

  • The pURL flaw is triggered when Marketo servers receive a request for a pURL-enabled LP that includes a Munchkin _mkto_trk cookie in the HTTP Cookie header.

  • That situation can also be detected in JavaScript before Munchkin.init() runs (after Munchkin initializes you always have a cookie no matter what, so you can't draw conclusions).

  • So, if JS running in the <head> already sees a _mkto_trk, and the current URL is a pURL (it ends with /<page name>/<unique code>) we immediately know the pURL isn't functional.

  • So we copy the cookie value to the browser's temporary sessionStorage and remove the cookie. Then reload the page.

  • This time, the page has been requested from Marketo without the cookie, so pURLs work.

  • Then we restore the cookie in the <head>, so it'll be used by Munchkin and usual tracking will continue.


[1] IMO, the problems start with the name itself. When I started using Marketo, I thought the “personalized” part meant “tagged with the lead's identifying info” which of course is also true of tracked (mkt_tok-enized) links in Marketo emails. So I thought you needed to enable pURLs on an LP for tracked links to work! Then when people say “tokenized URLs” to mean “URLs with {{lead.tokens}} or {{my.tokens}} in them”… it becomes really messy.

[2] When there's an existing associated session, the server also ignores the pURL-linked lead and shows the associated lead instead. But that isn't nearly as bad as the anonymous case, as the associated lead is usually the same as the pURL lead.