βœ… MVT Tester is pending approval for the GTM Template Gallery
Built with ❀️ by Net Impression

Free Multivariate Testing Tool for Google Tag Manager

Launch A/B and MVT Experiments Instantly β€” No Paid Tools Needed

Drop this simple, powerful JavaScript into a Custom HTML tag in Google Tag Manager and start running A/B and multivariate tests for free.
No third-party platform. No limits. No need for Optimize, VWO, or Optimizely.

βœ… Supports multiple variants
βœ… Random user assignment with cookie persistence
βœ… Full dataLayer push for GA4 analysis
βœ… Supports test versioning and manual override
βœ… Fully compatible with Google Tag Manager

All you need to do is:

  1. Give your test a unique test code (e.g. AAA001)
  2. Choose how many variants you want (e.g. 4 = control + 3 variations)
  3. Add your JavaScript for each variant at the top of the code
  4. Paste the whole block into a Custom HTML Tag in GTM and trigger it on your test page
  5. Watch the results roll into your GA4 reports!

You can even force a variation by adding ?mvt=variation1 to your URL for testing/debugging.

‍

<script>
(function() {
  /* ==== MULTIVARIATE TEST SETUP ==== */
  /* 
     βœ… Update the following values for your test:
     1. testCode        β†’ Unique test identifier (must be unique per test!)
     2. testVersion     β†’ Optional version tag to prevent conflicts when re-running a test
     3. variants        β†’ Total number of variants (e.g. 4 = control + 3 variations)
     4. testInclusionRate β†’ Between 0 and 1 (e.g. 1 = 100%)
     5. Define your control() and variationX() functions below
  */

  var testCode = 'AAA001'; // Unique code for this test
  var testVersion = 'v1';  // Change this if you re-run the same test later
  var variants = 4;
  var testInclusionRate = 1;
  var cookieDays = 7;

  // ==== VARIATION FUNCTIONS ====
  window.control = function () {
    console.log(testCode + ' Control Running');
    // Your control logic here
  };
  
  window.variation1 = function () {
    console.log(testCode + ' Variation 1 Running');
    // Your variation 1 logic here
  };

  window.variation2 = function () {
    console.log(testCode + ' Variation 2 Running');
    // Your variation 2 logic here
  };

  window.variation3 = function () {
    console.log(testCode + ' Variation 3 Running');
    // Your variation 3 logic here
  };

  // ==== DO NOT EDIT BELOW THIS LINE ====

  var cookieKey = testCode + '_' + testVersion;

  function setCookie(name, value, days) {
    var expires = new Date();
    expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000));
    document.cookie = name + '=' + encodeURIComponent(value) + '; expires=' + expires.toUTCString() + '; path=/; SameSite=Lax';
  }

  function getCookie(name) {
    var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
    return match ? decodeURIComponent(match[2]) : null;
  }

  var urlParams = (function () {
    var params = {};
    var query = window.location.search.substring(1);
    var pairs = query.split("&");
    for (var i = 0; i < pairs.length; i++) {
      var parts = pairs[i].split("=");
      if (parts.length === 2) {
        params[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
      }
    }
    return params;
  })();

  var forcedVariant = urlParams['mvt'];

  function runVariant(variantName) {
    console.log(testCode + ': Running ' + variantName);

    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: 'MVT Test',
      eventCategory: 'MVT Test',
      eventAction: testCode,
      eventLabel: testCode + ' ' + variantName
    });

    setCookie(cookieKey, variantName, cookieDays);

    if (typeof window[variantName] === 'function') {
      window[variantName]();
    } else {
      console.warn('No function defined for ' + variantName);
    }

    if (typeof window.dispatchEvent === 'function') {
      window.dispatchEvent(new Event('mvt-loaded'));
    }
  }

  var existing = getCookie(cookieKey);

  if (forcedVariant) {
    runVariant(forcedVariant.toLowerCase());
  } else if (existing) {
    runVariant(existing);
  } else if (Math.random() < testInclusionRate) {
    var index = Math.floor(Math.random() * variants);
    var variantName = index === 0 ? 'control' : 'variation' + index;
    runVariant(variantName);
  } else {
    console.log(testCode + ': User not included in test');
  }

  // === βœ… Console credit ===
  console.log('Code on this page was developed by www.netimpression.co.uk πŸš€');

})();
</script>

‍

✨ This script was developed by Net Impression β€” making analytics simpler, sharper, and free where it counts. Feel free to copy, share, or extend it β€” just leave the credit in the console! You can also view the source on GitHub or contribute improvements.

Contact us

As a specialist analytics and CRO agency, we work closely with clients to make data a driving force behind smarter decisions and stronger performance.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.