Protecting your Thank You/Download pages from direct visits… by newbies

This one comes up periodically in the Community, so thought I'd set out the answers for next time.

Thank You (a.k.a. Follow Up/Download) pages shown after a lead converts are public webpages, just like the Landing Pages that host your forms. So occasionally the concern flares up that people will post or forward the Thank You URL, encouraging other leads to bypass the form and go straight to the Download button.

True: out of the box, Marketo pages don't offer any protection against this form of hotlinking (let alone actual username/password protection).

Of course, if people are sharing your gated (but free) content willy-nilly, that's kind of A Good Thing. Some leads who circumvented your form will come back and convert on their own, and if interest is high enough to encourage sharing, you're probably already seeing more form fillouts despite the unwanted leaks.

A little lightweight protection is still worth it. Either way, you should frame the situation optimistically, since — and this is the important takeway — you can't stop an actual hacker, or even a preteen prankster who knows how to use view-source, since the page is still public.

On the other hand, you can stop a casually unethical person who doesn't have any skillz, and you can send innocent recipients of a forwarded link back to the form first.

In sum, this isn't about a secure asset distribution (for that, you'd use signed links or per-lead usernames/passwords, neither of which are possible with Marketo alone). It's about showing good faith to management, which is why I called the function below goodFaithAntiHotlink.

What you really want

The goal is typically phrased as “make sure they came from the form,” but that's overly specific. Truth is, you only care if they came from your site(s) or not. After all, if they can fake the hostname part of their referrer, they can fake the path, page, and/or query string just as easily.

That is, you don't care if the previous page was exactly http://www.example.com/mylandingpage.html?querystring=2345. Just knowing they came from www.example.com shows they followed (or forged) the correct navigation from LP to TY. This keeps the required JavaScript more concise.

The simplest take

Here's a <script> to put in your document <head> to do the job:

(function goodFaithAntiHotlink(referrer) {
  
  /* configurable section: put your site-specific settings here */
  var options = {
    allowedHostnames: ['pages.example.com', 'pages.someotherexample.com'],
    fallbackURL: 'http://www.example.com/myform.html'
  };

  /* ---- no need to edit below this line! ---- */
  var refLoc = document.createElement('A');
  !referrer || (refLoc.href = referrer);

  if (options.allowedHostnames.indexOf(refLoc.hostname) == -1) {
    document.location.href = options.fallbackURL;
  }  
})(document.referrer);

At the top, customize the allowedHostnames array to contain your site(s), and set the fallbackURL to the form page. No need to touch anything else.

If they didn't come from one of the known sites, they're taken to the form page.

The next level

To get the code to dynamically adapt to each Form/Thank You combo (instead of having to change the fallbackURL each time) you can use {{my.tokens}} and some nice use of semantic (self-describing) HTML elements.

Set up your form page as a token:

ss

Then, in the <head> of your Thank You page (you can do this in the template level, of course, I'm just showing the page level here) use the standard link rel="prev" tag (“prev” means “previous”) to indicate what was supposed to be the previous navigated page:

ss

Now, you have a predictable source for the form page, so you can set the same fallbackURL on every page:

  /* configurable section: put your site-specific settings here */
  var options = {
    allowedHostnames: ['pages.example.com', 'pages.someotherexample.com'],
    fallbackURL: document.querySelector('LINK[rel="prev"]').href
  };

The next-next level

And if you don't use any domain aliases, you can also just check for the current domain, so the whole options block is the same on every page:

  /* configurable section: put your site-specific settings here */
  var options = {
    allowedHostnames: [document.location.hostname],
    fallbackURL: document.querySelector('LINK[rel="prev"]').href
  };

What about robots?

Use noindex, nofollow (see screenshot above). This will prevent the page from being indexed by search engines, another source of unexpected direct traffic.

What about same-page Thank You text?

It's great! I even wrote another post about a way to store different Thank You text options on the form itself in Form Editor.

With the same-page apporach, the lead stays on the LP URL even as the displayed content changes. So if they forward that URL, the above code is unnecessary.

Yet in the wild, most Marketo LPs still have companion Thank You LPs. Sometimes that's because the team doesn't know about the same-page approach, to be sure. But often that next page doesn't just display the short “Thank You” response, it also displays related content, loads conversion pixels, etc.. And while large-scale content replacement is possible with the same-page method, the necessary tech skills elude most marketing teams.

What if we send the asset via email?

Sending a download link via email helps you confirm that the lead is emailable, which is a win.

(Note: you shouldn't be sending links directly to downloadables like PDFs, but rather links to dedicated redirector pages, as I dove into here.)

But you can't stop people from forwarding that link (as in clicking the literal button in their email client). You can encourage them to use the Marketo-supplied Forward to Friend feature instead, but some leakage must be expected.

Again, if links don't expire and aren't protected by a lead-specific username/password (as opposed to a single password for everyone, lead-specific credentials are less likely to be shared since they feel more personal) then it's open season, provided a person is interested-slash-devious enough.