Datos Blog

Learn about business automation and operations

How to set up UTM tracking and site tracking across all forms with AC

By the end of this post, you’ll know how to set up UTM tracking and site tracking across an entire site at once (without having to edit every form manually).

In layman’s terms, this will enable you to see in ActiveCampaign:

What you’ll need:

If you need help with any step of this process, I’m available for hire to set up custom solutions for you.

Capturing UTM and email on form submission

The first thing you want to do is capture the UTM parameters and email when a form is submitted.

You’ll need to set up a few things for this in Google Tag Manager.


  1. Go to Variables, and click the “New” button.
  2. Name it UTM Source
  3. Click choose variable type to begin setup…
  4. Click URL on the right sidebar
  5. Switch Component Type to Query
  6. For Query Key, type utm_source
  7. Repeat this process 3 more times, with UTM Medium, UTM Content, and UTM Campaign. (You can also do UTM Term if you use that).

What this is doing is grabbing the values from the URL when it says ?utm_source=example&utm_medium=example2. UTM Source will be example, and UTM Medium will be example2.

You have one last variable to setup which will grab the hostname of the page that referred your visitor. (For example, facebook.com).

  1. Add a new variable and call it Referrer hostname
  2. Choose Custom Javascript as the type
  3. Copy/paste this code in and save:
function() { 
  var referrerDomain = new URL(document.referrer).hostname; 
  return referrerDomain; 

Form submission trigger

The next thing you need to do is set up a solid trigger for when your form is successfully submitted. You want Google Tag Manager to know exactly when to grab the visitor’s email and UTM parameters.

Now, a lot of people will immediately think of the form submission trigger type that comes with Google Tag Manager. But it comes with some potential issues which I won’t get into now.

The easiest and fastest way to determine when a form was successfully submitted is to watch for a change in page styles or elements. See, most forms will display a confirmation message when they’re submitted successfully (or grey out the submit button). If your forms don’t do this, no worries. You can likely use the regular form submission trigger without too much of a problem.

Without further ado, here’s how you set up the trigger for Elementor forms specifically. (If you’re not using Elementor, skip these steps and read below).

  1. Go to triggers
  2. Create a new one, and name it Elementor form submission
  3. For trigger type, choose Element Visibility
  4. Switch Selection Method to CSS Selector
  5. Under Element Selector, type “.elementor-form-spinner” without the quotes. This is the class for an element that only shows up when the form is successfully submitted.
  6. For when to fire this trigger, choose “Every time an element appears on screen”.
  7. IMPORTANT: Check “Observe DOM changes”. Without this, the trigger won’t work. This option tells Google Tag Manager to watch the page in real time instead of just checking once when the page loads.
  8. Save!

You’ll test the trigger soon, once you have a tag set up.

If you’re using any form other than Elementor forms, this trigger won’t work. You need to find a “CSS Selector” that will tell Google Tag Manager when that form is submitted.

To do that, follow these steps:

  1. Go to a page with a form.
  2. Test submitting the form and see what changes (if anything) when it is successful. Is there a confirmation message? Does the button grey out? Any changes here are key. Make sure to find a difference that doesn’t occur when you submit with bad info (such as an email address that isn’t formatted correctly).
  3. Now, go back to the form and right-click in the area where the change occurred (such as the button). Click inspect element if you’re on chrome, or the equivalent in any other browser.
  4. Submit the form again, and watch what changes in the code. Does the class on the button change? Is there a new element that appears? Whatever changes will be the target for your trigger.
  5. Write down a unique identifier that will help you target this element. Need help with this step? Contact me and I’ll help you out.
  6. Use this unique identifier and follow the Elementor steps above. Substitute “.elementor-form-spinner” with your identifier.

Capture email address and UTM parameters on form submit

This is where the magic happens!

  1. Create a new tag
  2. Title it something like “Capture email address and UTM on form submit”.
  3. Under Triggering, choose the trigger you just finished above.
  4. Under Tag Configuration, choose Custom HTML.
  5. Copy the following code and make the changes noted below to make it work for you.
  6. Save your tag.
<script type="text/javascript">
var useremail = document.querySelectorAll("[type='email']")[0].value;
localStorage.setItem('useremail', useremail);

    (function(e,t,o,n,p,r,i){e.visitorGlobalObjectAlias=n;e[e.visitorGlobalObjectAlias]=e[e.visitorGlobalObjectAlias]||function(){(e[e.visitorGlobalObjectAlias].q=e[e.visitorGlobalObjectAlias].q||[]).push(arguments)};e[e.visitorGlobalObjectAlias].l=(new Date).getTime();r=t.createElement("script");r.src=o;r.async=true;i=t.getElementsByTagName("script")[0];i.parentNode.insertBefore(r,i)})(window,document,"https://diffuser-cdn.app-us1.com/diffuser/diffuser.js","vgo");
    vgo('setAccount', 'YOUR ACCOUNT ID HERE');
    vgo('setTrackByDefault', true);
    vgo('setEmail', useremail);

if ({{UTM Source}} !== undefined) {
localStorage.setItem('utm_source', {{UTM Source}});
else {
localStorage.setItem('utm_source', {{Referrer hostname}});
console.log({{Referrer hostname}});

localStorage.setItem('utm_medium', {{UTM Medium}});
localStorage.setItem('utm_content', {{UTM Content}});
localStorage.setItem('utm_campaign', {{UTM Campaign}});

You’ll need to put in your account ID from ActiveCampaign. Go to Settings > Tracking and copy the site tracking script there. Grab the ID from the ‘setAccount’ part, and copy it into this script.

While you’re in that part of AC, make sure that you’ve enable site tracking for this particular domain.

Brief overview of how the script works:

  • At the very top it sets the variable “useremail” to the value of the email form field. This is based on a CSS selector that might fail with some forms. I think any form should use type=”email” for the email field, but if it doesn’t you’ll need to figure out a different selector.
  • If you have multiple forms on a page, this selector might fail because it chooses the first type=”email” field every time. If you have multiple forms, you’ll need to iterate through every “email” field and check if it’s empty before setting the variable.
  • Next, the email address is stored inside “Local storage” so that it can be used for site tracking on other pages. Local storage is like a cookie but it’s stored on the user’s machine. It can be cleared when they clear browsing data.
  • The next part submits the site tracking event to AC directly.
  • Lastly, we check if UTM Source is defined or not. If not, we use the Referrer hostname variable we set up earlier as UTM source. Then we set all UTM parameters into local storage.

Note that we have not yet sent the UTM parameters to AC. That’ll come later. The risk is that this script doesn’t finish before the page refreshes, so we’re keeping it lean.

Are you lost? I know I’ve run into challenges while reading guides like this one. Contact me if you need a helping hand.

Submitting UTM parameters to AC and site tracking across the site

Phew! You did it. Now you have captured the user’s email address and UTM parameters and put them in local storage, so you can use them however you like throughout their time on your site.

For this next piece, you’ll make an API call to ActiveCampaign to say “Hey! That email we just submitted? Here’s where they came from”.

I’m just going to note real quick that the way I set this up has a potential issue. This will fire on every page, multiple times if a user keeps browsing. It shouldn’t really affect page speed, but it’s not ideal. An ideal scenario would only fire this script once for every form submit.

If you want that ideal scenario, I can help you set it up. But it’s outside the scope of this post.

Create your UTM parameter fields in AC

1. In ActiveCampaign, go to Lists > Manage Fields.

2. Create a new group called “UTM Parameters” for organization.

3. Create several new fields: Latest UTM Source, Latest UTM Medium, Latest UTM Content, Latest UTM Campaign, and optionally Latest UTM Term.

4. (Optional) If you want to capture their very first UTM parameters and save that in addition to keeping track of their latest submissions (Trust me, you do), create another set of fields but call these “Original” instead of “Latest”. Heads up: you’ll need Zapier to make this work properly.

5. Set up an automation with this trigger:

6. Create an action to post to a webhook.

7. Go to Zapier and start a new Zap. Make the trigger “Catch Webhook”. Copy the hook URL and paste it into ActiveCampaign.

8. Set up an action in your Zap for ActiveCampaign, use the “Create/Update Contact” action.

9. Set it up to take the “Latest” UTM parameter fields and copy them into the corresponding “Original” UTM parameter fields.

10. Make sure this action doesn’t subscribe them to some list or do anything other than update the fields.

Now, the first time valid UTM info comes through, it’ll be stored in the original UTM parameter fields.

Set up your UTM parameter submission tag

  1. Create a new tag
  2. Name it something like “Submit UTM parameters to AC and site tracking on every page”
  3. Select Custom HTML as your tag type.
  4. For the trigger, choose “All Pages”
  5. Use this code and make the required changes noted below.
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">
if (localStorage.getItem('useremail')) {
var useremailstorage = localStorage.getItem('useremail');

    (function(e,t,o,n,p,r,i){e.visitorGlobalObjectAlias=n;e[e.visitorGlobalObjectAlias]=e[e.visitorGlobalObjectAlias]||function(){(e[e.visitorGlobalObjectAlias].q=e[e.visitorGlobalObjectAlias].q||[]).push(arguments)};e[e.visitorGlobalObjectAlias].l=(new Date).getTime();r=t.createElement("script");r.src=o;r.async=true;i=t.getElementsByTagName("script")[0];i.parentNode.insertBefore(r,i)})(window,document,"https://diffuser-cdn.app-us1.com/diffuser/diffuser.js","vgo");
    vgo('setAccount', 'YOUR ACCOUNT ID HERE');
    vgo('setTrackByDefault', true);
    vgo('setEmail', useremailstorage);

if (localStorage.getItem('utm_source')) {
params = new URLSearchParams();
params.append('email', useremailstorage);
params.append('field[%LATEST_UTM_SOURCE%,0]', localStorage.getItem('utm_source'));
params.append('field[%LATEST_UTM_MEDIUM%,0]', localStorage.getItem('utm_medium'));
params.append('field[%LATEST_UTM_CONTENT%,0]', localStorage.getItem('utm_content'));
params.append('field[%LATEST_UTM_CAMPAIGN%,0]', localStorage.getItem('utm_campaign'));

    'https://YOUR AC URL.api-us1.com/admin/api.php/?api_action=contact_sync&api_key=API KEY HERE&api_output=json', params, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}}

Changes needed:

  • Make sure the field[%LATEST… etc. part matches the names you used in AC for your Latest UTM parameter fields.
  • Replace your account ID in the site tracking script.
  • Replace your AC URL in the API url
  • Add your API key after &api_key=. You can find this under Settings > Developer.

In a nutshell, this script:

  • Calls Axios so that you can use it for the API action. You have many options, I chose Axios because it’s easy.
  • Grab the user email from storage (if it’s there) and use it to submit site tracking.
  • If there’s a UTM source stored, grab all UTM parameters and add them to a JSON payload.
  • Sync the contact to AC using the email address as the identifier. All you’re doing is telling AC to fill the UTM parameter fields with the values from local storage.

Need help customizing this for your specific needs? Get in touch with me.

Wow, you’re done!

The next step is, of course, to test this whole setup. Even following this tutorial step by step, you’re likely to run into an issue somewhere along the line unless you’re using the exact same setup I was using when I built this.

I want to note that technically, using Javascript for all of this is not a best practice because anyone could snoop around and find your ActiveCampaign API key. You should use something server-sided if you have the knowledge. But if you know how to do that, why are you reading this post? 😉

Skip forward

Never miss a post from Datos