ActiveCampaign UTM Tracking: How to Pass UTM Parameters to Every Contact

By Haktan Suren, PhD
In Blog
Sep 1st, 2018
23 Comments
36004 Views

If your ActiveCampaign contact record has an email address but no campaign source, the UTM parameters never reached the contact field.

That is usually a handoff problem, not an ActiveCampaign reporting problem.

I first wrote about passing UTMs to ActiveCampaign in 2018. The basic idea still works: create fields, add them to the form, and populate them before submission. But the old three-step version leaves out the parts that now cause most of the trouble: field mapping, persistence across pages, consent, repeat visits, and verification.

This is the version I would use today.

The short version

JobWhere it happensWhat can go wrong
Capture the UTM valuesThe landing page or a site-side tracking scriptThe visitor arrives without UTMs, or consent prevents storage
Keep the values until conversionFirst-party storage, the current URL, or your applicationA refresh, another page, a redirect, or a multi-step form drops them
Send the valuesHidden form fields or a server-side API handoffThe fields exist in ActiveCampaign but are not mapped in the form or integration
Store the valuesActiveCampaign custom contact fieldsA later blank submission or repeat visit overwrites useful data
Verify the resultThe submitted contact recordThe thank-you page works, but the fields are still empty

A hidden field is only the delivery slot. It does not capture or remember anything by itself.

Where UTM fields live in ActiveCampaign now

As of August 2026, I separate three things that are easy to confuse:

  1. The custom contact field is the storage location on the ActiveCampaign contact record.
  2. The hidden form field is the input that accepts a value during an inline-form submission.
  3. The contact record is where I verify that the saved value actually arrived.

The current path for contact fields is Contacts → Fields → Contacts. ActiveCampaign calls this the Manage Fields page. Create fields such as utm_source, utm_medium, utm_campaign, utm_term, and utm_content there.

For an ActiveCampaign inline form, go to Website → Forms, edit the form, then open Fields → My Fields. Add or locate the custom fields and drag them into the form. ActiveCampaign supports a Hidden Field type for inline forms. Its documentation also says hidden fields are text-only and are not available for floating box, floating bar, or modal forms.

ActiveCampaign documents both paths in its current guides for custom contact fields and hidden form fields.

One important detail: creating a custom field does not automatically map it into every form or integration. A field can exist perfectly in ActiveCampaign and still stay blank forever because nothing sends a value to it. If that is your symptom, use my CRM field mapping checklist before changing the tracking code.

Choose the handoff method before touching the form

There are two practical methods, plus one stronger server-side variation.

MethodPage refreshMulti-step flowRedirectIframe embed
Current URL → ActiveCampaign hidden fieldWorks while the tagged URL remainsUsually noOnly if the UTMs are forwardedOnly if the iframe URL receives them and the form accepts them
Site tracking script → stored values → hidden fieldYes, if storage is allowedYes, if every step can read the stored valuesYes, on the same site or with an explicit handoffOnly with a supported parameter, SDK, or messaging handoff
Site tracking script → server → ActiveCampaign APIYes, after the server receives the valuesYes, if the application carries them throughYes, if the application carries them throughYes, if the embedded tool sends the values to your server

The first method is fine for a short, single-page path.

The second method is what I use when the visitor may browse before converting. A site-side script captures the UTMs, stores the approved values, and fills the hidden inputs when the form loads or submits. HandL UTM Grabber is one way to handle that capture and persistence on WordPress, but the underlying requirement is the same with or without a plugin.

The API variation is useful when your WordPress form already submits to your own server or integration. The server can sync the contact and update its custom fields through the ActiveCampaign API. ActiveCampaign describes its API as the route for integrations and functionality outside its main interface.

An API does not recover attribution that was never captured. It only gives you a more controlled way to deliver the data you already have.

Method 1: pass UTM parameters into an ActiveCampaign hidden field

ActiveCampaign supports adding a query string to the hosted form URL. Its own example uses a hidden field whose personalization tag matches the query parameter after the percent signs are removed.

https://example.activehosted.com/f/15?utm_source=google&utm_medium=cpc&utm_campaign=summer_demo

This is useful when you link directly to an ActiveCampaign-hosted form.

An embedded form on a WordPress page is different. The UTMs in the browser address bar do not magically become values inside the generated ActiveCampaign fields. You need to pass them into the form.

For the most control, use the full embed code. ActiveCampaign says its simple embed uses JavaScript and updates automatically when the form changes, while the full embed uses HTML and CSS and must be pasted again after form changes. The full embed gives you actual hidden inputs that your site code can populate.

In the generated code, an input may look like this:

<input type="hidden" name="field[12]" value="" />

The number is the ActiveCampaign field ID in that form. Do not copy field[12] from this article. Use the exact name generated for your own field.

A minimal current-URL handoff looks like this:

<script>
const params = new URLSearchParams(window.location.search);
const sourceField = document.querySelector('input[name="field[12]"]');

if (sourceField && params.has('utm_source')) {
  sourceField.value = params.get('utm_source');
}
</script>

Repeat the mapping for the fields you actually use. Place the script after the full embed markup, or run it after the form exists in the page.

This example deliberately does not pretend to solve persistence. If the visitor moves to an untagged page, the current URL no longer contains the values. That is when you need the second method.

Method 2: capture first, then send by form or API

A tracking script changes the order of operations:

  1. Read the approved attribution values on the landing page.
  2. Store them according to your consent setup.
  3. Retrieve them when the form is ready.
  4. Fill the ActiveCampaign hidden inputs, or send the same values through your server-side integration.
  5. Confirm the values on the contact record.

This handles a normal WordPress journey better because the landing page and conversion page do not have to be the same page.

It also makes the failure boundary clearer. If the stored value is correct but the ActiveCampaign field is blank, the problem is in the form mapping or API handoff. If the stored value is already blank, the problem happened earlier. My longer diagnosis order is in Why UTM Fields Are Blank Even When the Link Looks Right.

For Contact Form 7, the final handoff uses its own hidden-field and mail-tag mechanics before a CRM integration sees the value. I cover that separately in Contact Form 7 UTM Tracking.

First touch and last touch need different fields

If you send every visit into one field called utm_source, the newest value can replace the old one. That may be exactly what you want. It is not first-touch tracking.

I prefer explicit field names:

Field setWrite ruleQuestion it answers
first_utm_source, first_utm_medium, first_utm_campaignWrite once when emptyHow did this contact first arrive?
last_utm_source, last_utm_medium, last_utm_campaignUpdate on the latest attributed visit or conversionWhat brought this contact back before the latest conversion?

Add term and content fields only if your campaigns use them and someone will inspect them. Ten empty CRM columns are not better attribution.

The first-touch rule must be enforced somewhere. Your site code, integration, automation, or server needs to check whether the first-touch field already has a value before replacing it. Update the last-touch fields deliberately.

ActiveCampaign also has a form option named Allow blank fields to overwrite existing field data. Its current form guide says this option is selected by default. For attribution fields, I review that setting under Options → Form Settings. Otherwise, a later submission with empty hidden fields can erase a useful value.

If you are still deciding which model belongs in the CRM, read First-Touch vs Last-Touch Attribution in WordPress.

Why the fields are still blank

The fields exist but the form does not send them

Creating utm_source under Contacts → Fields is not enough. Add the field to the inline form, map it in your WordPress integration, or include it in the API handoff.

The script reads only the current URL

The visitor landed with UTMs, browsed to another page, and submitted there. If nothing stored the original values, the form has nothing to send.

Consent changes when storage begins

Your consent tool may block the tracking script, delay it, or clear storage before the visitor submits. That can be correct behavior for your policy. It also means the attribution field may remain empty. I explain the implementation tradeoff in Cookie Consent Without Losing UTMs on WordPress.

A blank repeat submission overwrites a good value

This is easy to miss because the first test works. Review the blank-field overwrite setting and test the same email address twice.

The form is inside an iframe

The parent WordPress page cannot simply reach into a cross-origin iframe and fill its fields. Pass the values through a supported iframe URL parameter, embed SDK, or controlled message. If the embedded provider does not accept and store those values, WordPress cannot force it.

How I verify UTM parameters in ActiveCampaign

I do not stop at the thank-you message. I check the contact record.

  1. Open a tagged test URL with unmistakable values, such as ?utm_source=qa&utm_medium=manual&utm_campaign=activecampaign_test_202608.
  2. If you expect persistence, navigate to an untagged page before opening the form.
  3. Submit the form with a unique email address.
  4. In ActiveCampaign, open Contacts, find that contact, and inspect the custom contact fields.
  5. Confirm each field separately. Do not accept a populated source field as proof that campaign and medium also mapped correctly.
  6. Repeat the test with the same email address and no UTMs. Confirm that your first-touch values remain and your blank-field behavior matches the rule you chose.
  7. Repeat once more with a second tagged visit. Confirm that last-touch changes only if that is the intended behavior.

If the first submission fails, inspect the form input before submit. If the browser input is blank, fix capture or persistence. If the browser input contains the value but the contact record is blank, fix the mapping or API request.

What I would not over-claim

  • Saving UTMs in ActiveCampaign does not turn ActiveCampaign into a complete attribution model.
  • A UTM value tells you what was attached to the visit. It does not prove that the campaign caused the conversion.
  • An API handoff is not automatically more accurate. It is only more controlled after your server has the data.
  • A tracking script does not override consent choices or browser restrictions.
  • A hidden field does not survive refreshes, redirects, multi-step forms, or iframes unless the rest of the implementation carries the value through.

My final checklist

  • Create named custom contact fields in ActiveCampaign.
  • Add or map those fields in the exact form or integration that submits the contact.
  • Choose current-URL capture or persistent site-side capture deliberately.
  • Use separate first-touch and last-touch fields if you need both.
  • Review whether blank form values can overwrite existing data.
  • Test consented and non-consented paths according to your setup.
  • Verify the actual contact record with a unique tagged submission.
  • Repeat the test with the same email address.

The implementation is working only when the right value reaches the right contact field and stays there under the rules you chose.

About the Author

Haktan Suren, PhD
- Webguru, Programmer, Web developer, and Father :)

23 Responses to “ActiveCampaign UTM Tracking: How to Pass UTM Parameters to Every Contact”

  1. Yoan Yahemdi says:

    Hey,
    Thanks for this great article.

    However, I’ll be careful, never use utm parameters inside the website that is already tracked by the GA.

    It will rewrite the real source in Google Analytics.
    It will trigger a new fake session in Google Analytics as well.

    Your method should be used only for the form which are outside of the website.

    Kind regards,
    Yoan.

    • Haktan Suren, PhD Haktan Suren says:

      Hi Yoan,

      I do not understand why it will rewrite the source? or it will create fake sessions in GA. HandL UTM Grabber does not interfere with GA at all. I appreciate if you can explain more.

      Thanks,

  2. Joao says:

    Hey, Haktan,

    I tried to make the plugin works with Active Campaign, but it’s passing the same parameters (the first that i tried). All the contacts are with the same UTM’s.

    Can you help witi this problem?

  3. Josh says:

    Hi @Haktan

    What if you’re using gravity forms in WordPress to ActiveCampaign? How do you change the code in WP (Step 3)? I have Handl plugin installed. Made the changes in Gravity form AC setting using hidden fields then changes.

    (check box)Allow field to be populated dynamically
    Parameter Name:
    utm_source

    I got it pass through GF to AC with a simple test adding /?utm_source=test&utm_medium=test to the end of my url

    BUT This morning I got two real submissions but no utm data info passed in gravity form entry or AC entry. I can verify in GA that utm info was passed there. Leads or traffic are coming from Bing As an FB ads if that is helpful. Verified i have the UTMs setup correctly on those platforms.

    Any help or directions would be helpful. Thanks!

  4. Zach S. says:

    HI Haktan,

    I followed the process above and for some reason it’s still only passing %s in Active Campaign. Here’s a look at our code. We installed and activated the plugin, created hidden fields, created the form, and then modified the form with your wrapper code. Any thoughts?

    [utm_medium] [/utm_medium]

  5. Zach S says:

    <code class="{html}"
    [utm_medium] [/utm_medium]

  6. Hello,

    Thanks for the tutorial.

    I´ve done and it´s working almost 100% but “gclicd” and handl_original_ref still just showing %s

    Ps: I´ve created a ebook campaign at facebook just for instagram stories.

    Can you help me?

    Cheers.

  7. Terry Lee says:

    I am having trouble getting this to work. Do I need to do step 3 if I have the WP Plug in Installed and Activated? If so, do I need to have the WP plug in at all?

  8. I’m using SmartTheme (came with OptimizePress plugin), and it is integrated with ActiveCampaign.

    I followed the process above.

    But the custom fields justs are filled with %s.

  9. Nick says:

    Hello, I’ve tried this — and it seems to be working. However, the when HANDL populates the UTM fields, it shows on the form. How does it stay hidden?

  10. Gabriele says:

    Hi Haktan, does it work with Clickfunnels if i paste the Html code directly i. their editor into a page to attach the form. I tried and it doesn’t work.

    Thanks!

  11. Fernando says:

    This post saved my day! Thanks a lot.

  12. Mate says:

    This method is work in 2023?

  13. Alex says:

    Can I also extract only the URL Path/Slug

Wrap your code in <code class="{language}"></code> tags to embed!

Leave a Reply

E-mail address is required for commenting. However, it won't be visible to other users.

Loading Facebook Comments ...
Loading Disqus Comments ...