Cross Domain Tracking For Marketo with Munchkin Code

Inconsistent user tracking across domains affects data accuracy in Marketo. This guide explains cross-domain tracking via link clicks and form submissions, detailing Munchkin script modifications, cookie encryption, URL parameter passing, and deployment through Google Tag Manager.

Enabling cross-domain tracking with Marketo ensures that tracking information (Marketo cookies) is accurately transferred when users navigate between pages on different domains owned by you. This guide outlines the necessary steps to achieve this. We cover two specific and common use cases of cross-domain user journeys:

  1. Link Clicks from Domain A to Domain B: For example, you have a landing page on my-lp.com with a call to action (e.g., “Check Pricing”) that takes users to my-main-site.com.
  2. Marketo Embed Forms with Thank You Pages on a Different Domain: You use Marketo embed forms on domain A (my-lp.com) and your thank you page URLs are on your main website (my-main-site.com).

Another common scenario is when both your Marketo embed form and thank you page are on the same domain (my-lp.com), and the user is then sent an email containing links to your main website (my-main-site.com). In this case, Marketo should natively track and associate the visits to the same user since links within Marketo-delivered emails already contain tracking parameters. You just need to ensure that the Munchkin code is present on both domains. You can easily verify the presence of the Marketo Munchkin tracking code on your webpages.

If there are any other use cases you can think of, please share them in the comments.

Let’s look at both primary cases one at a time. There will be a lot of scripting involved, but as long as you follow the instructions and comments within our scripts, you don’t need much programming background to implement this.

Before we dive into the scripts, let’s understand what cross-domain tracking really means and the tactics we will use to achieve it.

How Does Tracking in Marketo Work?

Web tracking for any analytics tool, including Marketo, relies on cookies. Typically, this involves first-party cookies, so you don’t need to worry about third-party cookie blocking with standard Marketo tracking configurations.

To enable Marketo to track your user’s end-to-end journey, we use a tracking script called Munchkin, which you can find under the Admin section in Marketo. Once the Munchkin script loads in a user’s browser, Marketo sets a cookie named _mkto_trk. This cookie helps in identifying and tracking users across your website. For detailed information about this cookie and other tracking details, you can refer to Marketo’s documentation.

A crucial aspect relevant to this guide is cross-domain tracking. By default, a cookie is associated with a single domain (first-party). If a user visits another domain, Munchkin will set a new cookie value, even if you are using the same tracking code.

Marketo doesn’t inherently recognize that you own multiple domains. Therefore, we need to inform Marketo about these multiple domains and ensure cookie sharing across them. The challenge is to retain the same cookie value when the domain changes, allowing for consistent user tracking.

How to Retain and Pass Cookie Values Across Multiple Domains

To retain and pass cookie values across multiple domains, we will use a method that involves passing the cookie value as a URL parameter during user navigation from one domain to another. Here’s a brief overview of the approach we’ve followed:

  1. Capture the Cookie Value on Domain A: Extract the value of the _mkto_trk cookie on domain A.
  2. Pass the Cookie Value via URL Parameter: When the user navigates to domain B, append the cookie value as a URL parameter.
  3. Set the Cookie on Domain B: On domain B, retrieve the cookie value from the URL and set the _mkto_trk cookie with this value.

This method is akin to how Marketo passes tracking parameters in the URL when someone clicks on a Marketo-delivered email. It’s also similar to how Google Ads uses the “GCLID” parameter and Facebook uses the “fbclid” parameter to maintain tracking consistency.

However, this method requires careful handling of a couple of important considerations:

  1. Encrypt Cookie Values: To prevent abuse, encrypt cookie values before passing them in the URL.
  2. Respect Cookie Consents: Ensure that this method is only executed when the user has given consent for cookie tracking.

Let’s look at what tools we need to get this to work

Tools Used for Implementation

To implement cross-domain tracking, we use the following tools. However, alternative tools can be used with similar logic:

  • Usercentrics for Consent Management: Alternatives like Cookiebot or other Consent Management Platforms (CMPs) would work similarly.
  • Google Tag Manager (GTM) for Firing Munchkin Tracking Scripts: Alternatives include adding scripts directly to the page or using other Tag Management Systems like Tealium, which would follow the same logic.

Assumption: This implementation assumes a user journey from landing pages to the main website. The flow is generally one-way (landing page > main website) and rarely in reverse.

Implementation

Munchkin Script on Domain A (my-lp.com)

To enable cross-domain tracking, modify your Munchkin script as shown below. Notice the added lines and comments. We also dispatch an event called ‘munchkinScriptLoaded’ to avoid race conditions. Some scripts and functions depend on the Munchkin Script being fully initialized, and this event can be used to ensure proper execution.

   (function() {
     var didInit = false;
     function initMunchkin() {
       if(didInit === false) {
         didInit = true;
         Munchkin.init('123-XXX-456', // change to your Munchkin ID
         {
             domainLevel: 2, // new addition
             customName: 'my_lp_com', // your domain identifier
             wsInfo: 'a0bCdefGHiJK' // change to your Munchkin wsInfo
           });
        
            // Dispatch custom event after Munchkin has been initialized
         var event = new CustomEvent('munchkinScriptLoaded');
         document.dispatchEvent(event);
        
       }
     }
     var s = document.createElement('script');
     s.type = 'text/javascript';
     s.async = true;
     s.src = '//munchkin.marketo.net/munchkin.js';
     s.onreadystatechange = function() {
       if (this.readyState == 'complete' || this.readyState == 'loaded') {
         initMunchkin();
       }
     };
     s.onload = initMunchkin;
     document.getElementsByTagName('head')[0].appendChild(s);
   })();

Munchkin Script on Domain B (my-main-site.com)

Munchkin script on Domain B will look slightly different. We’ll get to that part in a bit. Lets finish implementing our process for Domain A first.

Link Decoration – Domain A

Since we assume users navigate from Domain A to Domain B, we will decorate links on Domain A. However, if users navigate in the opposite direction, you should add these scripts on Domain B as well.

Helper Functions

We start with some helper functions. These functions will:

  1. Capture the Cookie Value: Retrieve the value of the _mkto_trk cookie.
  2. Encrypt the Cookie Value: Secure the cookie value before passing it.
  3. Decorate Direct Links: Append the encrypted cookie value to direct links.
  4. Decorate Form Thank You Pages: Ensure the cookie value is passed to thank you pages after form submissions.

Capture the Cookie Value

  // Function to get cookie

  function getCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
      var c = ca[i];
      while (c.charAt(0) == ' ') c = c.substring(1, c.length);
      if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
    }
    return null;
  }

Encrypt the Cookie Value

  // Function to base64 encode a string
  function base64Encode(str) {
    return btoa(decodeURIComponent(encodeURIComponent(str)));
  }

Decorate Direct Links

Note a change you have to make in the comments – update your main website domain instead of my-main-site.com in the given script

 // Function to decorate links
  function decorateLinks() {
    var mktidValue = getCookie('_mkto_trk');
         // Uncomment below line for debugging if needed
        //    console.log('MKTID Value:', mktidValue);
    if (mktidValue) {
      var encodedMktid = base64Encode(mktidValue);
         // Uncomment below line for debugging if needed
      // console.log('Encoded MKTID:', encodedMktid);

      // Select all anchor tags
      var links = document.querySelectorAll('a');

      // Decorate links that include ‘my-main-site.com' in their href
      links.forEach(function(link) {
        var href = link.getAttribute('href');
        if (href) {
         // Uncomment below line for debugging if needed
         // console.log('Original Href:', href);
          if (href.includes('my-main-site.com')) // change this to your domain
          {
            // Append the mktid parameter to the existing URL
            if (href.includes('?')) {
              href += '&mktid=' + encodedMktid;
            } else {
              href += '?mktid=' + encodedMktid;
            }
            link.setAttribute('href', href);
         // Uncomment below line for debugging if needed
            // console.log('New Href:', href);
          }
        }
      });
    }
  }

Once you have placed these functions in the same order, we can go ahead and fire our decorate links function after the Munchkin Script has loaded. This is where our event 'munchkinScriptLoaded' comes in handy.

 // Event listener for Munchkin Script loaded
  document.addEventListener('munchkinScriptLoaded', function() {
    // Delay the execution of decorateLinks by 2 seconds (2000 milliseconds)
    setTimeout(decorateLinks, 2000);
  });

What we did here though is delay this function by 2 seconds to give Munckin enough time for placing the cookie before we decorate the links. If your users click the link before 2 seconds, the cookie value may not get extracted. Simply adjust this delay if you experience that the time taken is longer or shorter. (Note the delay is in milliseconds, so you use accordingly.)

Before we head on to Domain B, lets add the Marekto form scenario in the same scripts to cover both cases together.

Decorate Form Thank You Pages

This section covers decorating normal Marketo form embeds to ensure the tracking cookie is passed to thank you pages.

A typical Marketo form embed on your page looks something like this (sample code):

There are two approaches to modifying the form embed code:

  1. Modify Each Form Embed Individually: Update the embed code for every form.
  2. Add a Global Function: Implement a global function that modifies all form embeds. This approach is more efficient as it allows for easier future changes by updating a single script rather than modifying each embed code on your landing pages.

We recommend the global function approach for its maintainability and ease of updates.

To decorate the thank you page URLs of your forms, you need two functions:

  1. Function to Construct URL: This function appends the encrypted Marketo cookie value to the URL, similar to the direct link decoration process.
  2. Function to Modify Form Submit Action: This function captures the existing thank you page URL using a Marketo hook and appends the modified URL to the form submit action.

Modify URL

To modify the thank you page URL and append the Marketo cookie value, use the following function:

  // Function to modify the thank you page URL
  function modifyThankYouPageUrl(url) {
    var mktidValue = getCookie('_mkto_trk');
    if (mktidValue) {
      var encodedMktid = base64Encode(mktidValue);
      if (url.includes('?')) {
        url += '&mktid=' + encodedMktid;
      } else {
        url += '?mktid=' + encodedMktid;
      }
    }
    return url;
  }

You’ll notice that the getCookie function was previously defined, so there’s no need to define it again.

Similar to link decoration, we use the parameter mktid to pass the value. You can change this parameter to any name you prefer, but ensure you update all instances of mktid in the script accordingly.

Update Thank You Page URL

No need for any changes here – simply copy paste the following script.

  // Function to attach the event listener to forms
  function attachFormSubmitListener() {
    if (window.MktoForms2) {
      MktoForms2.whenReady(function (form) {
        form.onSuccess(function(values, followUpUrl) {
          followUpUrl = modifyThankYouPageUrl(followUpUrl);
          window.location.href = followUpUrl;
          return false;
        });
      });
    }
  }

Now that we have all the functions, we need to ensure they execute in the correct order. The functions must run only after both the Marketo form and the Munchkin script have loaded. If the functions execute before either of these events, they won’t work due to the dependencies.

To handle this, we use the built-in DOMContentLoaded event to ensure the Marketo form has loaded and our custom munchkinScriptLoaded event to ensure the Munchkin script has loaded. We will create flags (or helper variables) to indicate when both events have occurred.

Start by defining two variables and setting their values to false:

  // Flags to check if events have occurred
  var isDOMLoaded = false;
  var isMunchkinLoaded = false;

We then add a function that checks if these 2 events have occurred and if they did, executes thank you URL modifier function.

   // Function to check if both conditions are met
  function checkAndAttachListeners() {
    if (isDOMLoaded && isMunchkinLoaded) {
      attachFormSubmitListener();
    }
  }

At the same time, we also need to make sure that when these events do occur, we are setting the values of our flags to true when these events fire and when that happens we go back and fire our checkAndAttachListeners function.

Its simple for 'DOMContentLoaded' as this is the first time we are writing this function

    // Event listener for DOMContentLoaded
  document.addEventListener('DOMContentLoaded', function() {
    isDOMLoaded = true;
    checkAndAttachListeners();
  });

But for 'munchkinScriptLoaded' we have already written that function above for direct links decoration. So we’re just going to modify the same function slightly by making sure that when this event takes place, the corresponding flag is set to true and the checkAndAttachListeners();  is executed.

    // Event listener for Munchkin Script loaded
  document.addEventListener('munchkinScriptLoaded', function() {
    isMunchkinLoaded = true;
    checkAndAttachListeners();
    // Delay the execution of decorateLinks by 2 seconds (2000 milliseconds)
    setTimeout(decorateLinks, 2000);
  });

You have now completed the necessary steps for Domain A. To download the entire script, click here. Just a reminder: this is an HTML file, use an HTML editor to open ;). Make sure to read the comments within the script for detailed explanations and additional context.

Adding the scripts via Google Tag Manager

This is quite straightforward. Simply go to your Google Tag Manager account. 

    1. Tag: Add a custom HTML tag and paste the entire script in the tag.
    2. Trigger: Choose a trigger that targets pages of Domain A only (Create the trigger if you don’t already have one).
    3. Consent check: Thoroughly test consent approvals before firing your codes. In GTM its just easier to configure “Additional Consent Options” in your tag settings.

Testing

Once you have added the script, it’s time to test the implementation. Follow these steps:

  1. Click on a Direct Link: Navigate from Domain A to Domain B by clicking on a direct link.
  2. Submit a Form: Fill out and submit a form on Domain A.

In both cases, you should see the mktid parameter in your URL with a long alphanumeric value, indicating that the cookie value has been successfully passed and encrypted.

Summary of What We Accomplished So Far

  1. Captured the Marketo Cookie: We retrieved the cookie placed by Marketo on our landing page (Domain A).
  2. Encrypted the Cookie Value: We encrypted this cookie value to ensure security.
  3. Passed the Encrypted Value: We passed this encrypted value to our second domain (Domain B) via the mktid parameter in the URL, either when a user clicks a direct link or submits a form.

Changes to Domain B

Now that Domain A is ready with the necessary scripts, let’s complete the process by adding a script on Domain B to ensure that the cookie value passed in the URL is utilized.

Changes to Domain B are made within your Munchkin script by adding the following functions:

  1. Cookie Value Decoder Function: This function will decode the cookie value passed in the URL.
  2. Set Marketo Cookie Function: This function sets the received cookie value before the Munchkin code has a chance to set a new cookie.

Cookie Value Decoder Function

       // Function to base64 decode a string
           function base64Decode(str) {
               return decodeURIComponent(atob(str));
           }

Set Marketo Cookie Function

// Set the Marketo cookie
           function setMarketoCookie(value) {
               var date = new Date();
               date.setTime(date.getTime() + (2 * 365 * 24 * 60 * 60 * 1000)); // 2 years expiration
               var expires = "expires=" + date.toUTCString();
               document.cookie = "_mkto_trk=" + value + ";" + expires + ";path=/";
           }

Note: Marketo cookies are set for 2 years by default. This is reflected in our function, but you can modify the duration if necessary.

Initialize Munchkin after cookie value is received and decrypted

Below is the full Munchkin tracking code for Domain B. Pay attention to the comments and update wherever necessary:

    (function() {
           var didInit = false;
      
           // Function to base64 decode a string
           function base64Decode(str) {
               return decodeURIComponent(atob(str));
           }
      
           // Set the Marketo cookie
           function setMarketoCookie(value) {
               var date = new Date();
               date.setTime(date.getTime() + (2 * 365 * 24 * 60 * 60 * 1000)); // 2 years expiration
               var expires = "expires=" + date.toUTCString();
               document.cookie = "_mkto_trk=" + value + ";" + expires + ";path=/";
           }
      
           // Initialize Munchkin
           function initMunchkin() {
               if (didInit === false) {
                   didInit = true;
                   Munchkin.init('123-XXX-456', // change to your Munchkin ID
                   {
                       domainLevel: 2, // new addition
                       customName: 'my_main_site_com', // your domain identifier
                       wsInfo: 'a0bCdefGHiJK' // change to your Munchkin wsInfo
                   });
                  
                   // Dispatch custom event after Munchkin has been initialized
                   var event = new CustomEvent('munchkinScriptLoaded');
                   document.dispatchEvent(event);
               }
           }
      
           // Load Munchkin script and initialize
           function loadAndInitMunchkin() {
               // Check for the mktid parameter in the URL
               var urlParams = new URLSearchParams(window.location.search);
               var encodedCookie = urlParams.get('mktid');
               if (encodedCookie) {
                   var decodedCookie = base64Decode(encodedCookie);
                   setMarketoCookie(decodedCookie);
               }
      
               var s = document.createElement('script');
               s.type = 'text/javascript';
               s.async = true;
               s.src = 'https://munchkin.marketo.net/munchkin.js';
               s.onreadystatechange = function() {
                   if (this.readyState === 'complete' || this.readyState === 'loaded') {
                       initMunchkin();
                   }
               };
               s.onload = initMunchkin;
               document.getElementsByTagName('head')[0].appendChild(s);
           }
      
           loadAndInitMunchkin();
       })();

Adding the script via Google Tag Manager

Again, quite straightforward.

  1. Tag: Create a new custom HTML tag. Paste the entire script.
  2. Trigger: Choose a trigger targeting your pages on my-main-site.com (Domain B)
  3. Consent check: Make sure to fire the tag only on proper Marketo consent
  4. Publish your container.

Testing the Overall Implementation

The most comprehensive test is to examine user web visits data in Marketo. However, you can initially verify the implementation by checking if the same cookie is placed on both domains. Follow these steps:

  1. Verify the Cookie on Domain A:
    • Navigate to Domain A and ensure you consent to Marketo cookies.
    • Open the developer console in your browser. In Chrome, right-click on the page and select “Inspect.”
    • Go to the “Application” tab. In the left navigation under “Storage,” click on “Cookies” and then your domain name.
    • Use the Filter box to search for “_mkto_trk.” There may be more than one entry; this is normal. Click on the one with the same domain name in the domain column.
    • A new section will open at the bottom showing the cookie value. Note this value down.
  2. Verify the Cookie on Domain B:
    • Follow the user journey from Domain A to Domain B (via direct link click or form submission).
    • Once on Domain B, repeat the steps above to look for the _mkto_trk cookie (this time, click the one that belongs to Domain B).
    • Note down the cookie value.
  3. Compare Cookie Values: Compare the cookie values from both domains. If the values are the same, your implementation is successful!

Actions Taken for Cross-Domain Tracking with Munchkin

Here is what we did in this guide to ensure Marketo/Munchkin cross-domain tracking is correctly implemented across all your domains

  1. Munchkin Initialization:
    • We initialized Marketo’s Munchkin tracking on the landing pages.
    • Dispatched a custom event (munchkinScriptLoaded) once the Munchkin script was loaded.
  2. Cookie Retrieval and Link Decoration:
    • Retrieved the Marketo tracking cookie (_mkto_trk) and encoded it.
    • Decorated links on the landing page by appending the encoded cookie as a query parameter (mktid).
  3. Form Submission Handling:
    • Used MktoForms2 API to handle form submissions.
    • Modified the thank you page URL by appending the encoded Marketo tracking cookie before redirecting the user.

The risks of not implementing cross-domain tracking in Marketo 

If the Marketo Munchkin cookie is not synchronized across your domains, the tracking of user activity will be fragmented. This means:

  1. Separate Anonymous Activity: Each domain will create its own anonymous Munchkin cookie for the user, resulting in separate tracking of user activity on each domain.
  2. Loss of Continuity: Actions performed by the user on one domain (e.g., form submissions, page views) will not be linked to their activity on another domain, causing Marketo to treat the user as two distinct anonymous visitors.
  3. Inconsistent Lead Records: Without synchronization, if a user becomes known (e.g., by filling out a form) on one domain, their subsequent activity on another domain will not be associated with their known lead record, leading to incomplete or inaccurate lead data.
  4. Ineffective Campaigns: Marketing automation and personalization campaigns that rely on comprehensive tracking data will be less effective, resulting in missed valuable insights and opportunities to engage with the user.

If you encounter any issues with implementing this, feel free to leave a comment and we’ll do our best to assist you. If you found this guide useful, please consider sharing it with your professional network or following us on LinkedIn. We regularly post updates about new guides and articles for our followers. Additionally, you can subscribe to our “useletter” for the latest insights and updates.

0 Comments

    Leave a Reply