Example: Per-Content Conversions

By default, firing a conversion means a developer hardcodes the call and redeploys. Every new goal, every renamed conversion, every "can we also track this one?" goes back into the development queue.

This example moves that decision to the people making it. A developer adds two fields to a Content Type and drops a script into the container once. From then on editors decide, per content instance, whether it counts as a conversion and what that conversion is called — no code changes, no redeploy.

The worked example is a CTA button inside a Hero, a reusable Content Type placed on many pages through a container. The same technique applies to any reusable Content Type.

Avoiding False Positives#


Everything here exists to fire conversion(name) at exactly the right moment and never at the wrong one. A false positive is worse than a missing conversion: it inflates your numbers.

GuardPrevents
Success gate — fire only after the goal succeedsCounting intent instead of completion. For a bare CTA the click is completion — the exception, not the rule.
Editor / preview guardif (window.dotAnalytics)Recording conversions while an author edits or previews inside UVE.
Double-fire guardThe same goal counted twice from a double-click or re-submit.
Enabled + named guardFiring on instances the editor never opted in, or with an empty name.

Step 1: Add Two Fields#


FieldTypeVariablePurpose
Enable ConversionCheckboxenableConversionTurns tracking on for this instance.
Conversion nameSelect (preferred) or TextconversionNameThe name reported to analytics.

Step 2: Detect and Fire#


#set($doConversion = false)
#if($UtilMethods.isSet($conversionName) && "$!{enableConversion}" == "true")
    #set($doConversion = true)
#end

<a class="primary-cta" href="$cta1Url"#if($doConversion) data-dot-conversion="$esc.html($!{conversionName})"#end>$cta1Text</a>

#if($doConversion)
<script>
  (function () {
    if (window.__dotConversionListenerAdded) return;
    window.__dotConversionListenerAdded = true;

    document.addEventListener('click', function (event) {
      var link = event.target.closest('a[data-dot-conversion]');
      if (!link) return;
      var name = link.getAttribute('data-dot-conversion');
      if (!name) return;
      if (!window.dotAnalytics) return;   // editor / analytics off
      window.dotAnalytics.conversion(name);
    });
  })();
</script>
#end

Adapting to Other Goals#


Goal typeSuccess momentWhere to fire
CTA / link clickThe click itselfOn click, then let it navigate
Form submissionAfter the submit succeedsIn the submit success handler
Purchase / checkoutAfter payment is confirmedAfter the payment API returns success
Gated downloadAfter the download startsIn the download success callback