Your UTMs are in the URL. You can see them in the browser. The lead submits the form. And then the lead shows up in your CRM with no source data.

The UTMs didn't go anywhere, they were never captured. Here's exactly why, and how to fix it.


Why form submissions don't capture UTMs by default

When someone fills out a form on your website, the form submits whatever fields it contains. Fields have names. Whatever's in those fields gets sent to your form tool, then to your CRM.

UTM parameters live in the URL. They are not form fields. They don't get submitted with the form unless you explicitly add hidden fields designed to capture them.

That's the entire problem. No hidden fields = no UTM data.

The reason this confuses people: nothing breaks. No error. No warning. The form submits fine. The lead arrives in your CRM. It just arrives without source data, because there was never a mechanism to collect it.


The 4 most common causes, in order of likelihood

Cause 1: No hidden fields on the form (most common)

Your form doesn't have hidden fields for utm_source, utm_medium, utm_campaign, utm_content, or utm_term.

How to diagnose: Inspect your form HTML. Look for <input type="hidden"> elements with UTM-related names. If you don't see any, this is your problem.

How to fix it:

In most form builders, you can add hidden fields manually. The field should:

  • Be type: hidden
  • Have a name that matches what you want in your CRM (e.g., utm_source)
  • Have its default value set to read from the URL parameter with the same name

The "read from URL parameter" part is where this gets slightly technical. Different form builders handle it differently:

  • HubSpot forms: Add a hidden field, set it to pre-populate from the URL parameter utm_source
  • Gravity Forms: Use the "Parameter" field type, set the parameter name to utm_source
  • Typeform: Use hidden fields in the Form Settings, add utm_source as a hidden field
  • Contact Form 7: Add a hidden field with [hidden utm_source default:query_post_meta], or use a plugin like CF7 UTM Tracker

Do this for all five UTM parameters. Then test by filling out the form after clicking a link with UTMs in it.

If you'd rather skip this entirely: Trakt automatically injects hidden UTM fields into every form it detects on your site. See how it works →


Cause 2: Hidden fields exist but aren't set to read from the URL

You added the hidden fields. They still show blank in the CRM. The fields are there, but they're not configured to pull from the URL parameters on page load.

How to diagnose: Submit a test form after landing on the page with UTMs in the URL. Check the CRM lead record. If the field is blank (not missing, blank), the field exists but isn't reading the URL.

How to fix it: This depends on your form tool. In most builders, hidden fields have a "default value" or "prefill" option. Set it to "query parameter" and enter the parameter name (e.g., utm_source). Some builders do this with JavaScript instead, a small script on page load that reads URLSearchParams and sets the field values.

Here's the JavaScript approach if your form builder supports custom code:

document.addEventListener("DOMContentLoaded", function () {
 const params = new URLSearchParams(window.location.search);
 ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"].forEach(function (key) {
 const field = document.querySelector('input[name="' + key + '"]');
 if (field && params.get(key)) {
 field.value = params.get(key);
 }
 });
});

Cause 3: UTMs exist on the landing page but not the page with the form

Your ad sends traffic to /landing-page. The form is on /contact. The visitor navigates from one to the other. The UTMs were in the URL on the landing page, but by the time they hit the form page, the URL has changed and the parameters are gone.

How to diagnose: Check your ad destination URLs. Do they point directly to the page with the form? Or is there a navigate-to-another-page step involved?

How to fix it: Two options:

  1. Point your ads directly to the page containing the form (simplest)
  2. Store UTMs in a first-party cookie when the visitor first lands, then read from the cookie on subsequent pages

The cookie approach requires a small script or a tool like Trakt that handles cookie persistence automatically. This also solves the case where someone clicks an ad, browses around your site for a few minutes, and then fills out a form on a completely different page.


Cause 4: CRM field mapping is missing or wrong

The hidden fields exist, are reading correctly, and the data is being submitted. But the CRM lead record still shows blank source fields.

How to diagnose: Check the raw form submission data (most form tools have a submissions log). If you can see UTM values in the submission but not in the CRM, the problem is in the mapping.

How to fix it:

  • In HubSpot native forms: make sure each hidden field maps to a custom HubSpot contact property. HubSpot doesn't automatically map hidden fields, you have to set the mapping in the form field settings.
  • In Zapier/Make workflows: open the Zap, find the step that creates the CRM contact, and check whether the UTM fields are included. If you added the hidden fields after building the Zap, they won't appear automatically, you'll need to edit the trigger step and re-select your form fields.
  • In Salesforce: UTM values typically map to custom Lead fields. Make sure the field API names match what your form tool is sending.

How to test that everything is working

Once you've made your fixes, run this test before going live:

  1. Build a test URL with UTMs using the Trakt UTM Builder →, something like yoursite.com/contact?utm_source=test&utm_medium=email&utm_campaign=attribution-test
  2. Open that URL in a browser (or incognito window)
  3. Fill out the form with your own contact info or a test email
  4. Check the form submission log: do you see the UTM values?
  5. Check the CRM record: do the custom source fields show the UTM values?

If step 4 works but step 5 doesn't, the problem is CRM mapping. If step 4 shows blanks, the problem is hidden fields or the URL-reading configuration.


The preventive fix: automatic hidden field injection

The manual approach works, but it has a maintenance problem. Every time you add a new form, you have to add the hidden fields again. Every time a developer builds a new landing page, you have to check whether the form was set up correctly. Forms get added, forms change, and the UTM setup drifts.

Trakt solves this by scanning your site and automatically injecting hidden UTM fields into every form it finds, including forms added after you set it up. No maintenance, no checklist, no per-form configuration.

See how Trakt handles hidden field injection →


Common gotchas

  • URL-encoded UTMs: Some ad platforms encode UTM values (spaces become %20, etc.). Make sure your CRM field accepts URL-encoded strings, or decode them before storing.
  • GA4 "direct" vs UTM "direct": Google Analytics and your CRM use different definitions of "direct." A lead showing as "direct" in HubSpot doesn't mean they typed your URL, it means no UTM was captured.
  • Form caching: Some WordPress caching plugins serve a cached version of the form page that doesn't execute the JavaScript reading UTMs from the URL. Test with caching disabled if your setup looks correct but isn't working.