Marketing attribution · Updated September 2026 · 11 min read

How to capture UTM parameters in forms and keep them

Analytics can tell you which campaign brought a visit. It usually cannot tell you which campaign brought the person who later became your best customer, because that person lives in your form responses and your CRM, not in your analytics. Capturing UTM parameters in the form itself closes that gap, if you handle the two places where UTMs quietly go missing.

By Raj Kumar, Founder, Zunoform

A paper plane with a hidden terracotta tag, a thread tracing its path back to a brass pin

The short answer

Add one hidden field per parameter, named exactly utm_source, utm_medium, utm_campaign (plus utm_term and utm_content if you use them). When someone opens a form link carrying those parameters, the form reads them from the URL and saves them with the response, invisibly. If visitors land on another page first or the form is embedded, store the UTMs on arrival and pass them to the form yourself.

  • Hidden field names must match the URL parameter names exactly, and values are case sensitive.
  • UTMs only exist on the landing URL; they vanish when the visitor clicks to another page.
  • Decide whether you want first-touch, last-touch or both, and name the fields accordingly.
  • Never put email addresses or other personal data in UTM values.

How do UTM parameters work?

UTM parameters are tags you add to the end of a link: ?utm_source=newsletter&utm_medium=email&utm_campaign=october-launch. The page they point to ignores them. Analytics tools such as Google Analytics read them when the page loads and attribute that session to the campaign you described.

Google's documentation lists nine parameters and says you should always use utm_source, utm_medium and utm_campaign. Values are case sensitive, so utm_source=Google and utm_source=google are two different sources in your reports. Our UTM builder at /tools/utm-builder assembles tagged links and handles URLs that already have a query string.

Which UTM parameters should your form capture?

Parameters from Google Analytics' URL builder documentation, checked 28 September 2026.

ParameterIdentifiesExampleCapture in the form?
utm_sourceThe referrernewsletter, linkedin, googleAlways
utm_mediumThe channel typeemail, social, cpcAlways
utm_campaignThe campaign or promotionoctober-launchAlways
utm_contentWhich link or creativeheader-button, video-ad-bIf you compare creatives
utm_termPaid search keywordform-builderPaid search only
utm_idCampaign IDabc.123If you import cost data
utm_source_platformThe buying platformSearch Ads 360Rarely
utm_creative_format / utm_marketing_tacticCreative type / targetingvideo / remarketingNo: Google says GA4 does not currently report them

Sources: Google Analytics Help: Collect campaign data with custom URLs

What is a hidden field, and why use it for UTMs?

A hidden field is a form field the respondent never sees. Instead of being typed, its value is filled in from the page URL (or a default value) and stored alongside the visible answers. Named utm_source, it picks up whatever utm_source the link carried.

That puts the source on the lead record itself. To take a made-up example, analytics can report that the October email drove 40 submissions; only the form response can tell you that the one lead who became a large account came from that email. It also keeps working for visitors whose browsers block analytics scripts, because the tagged URL still reaches the form. It does record where someone came from, so mention it in your privacy notice.

How do you capture UTM parameters in a form? (step by step)

The general method works in most builders; the notes in brackets describe Zunoform.

01

Decide what you need

Usually utm_source, utm_medium and utm_campaign. Add utm_content if you compare buttons or creatives, and first-touch fields if the sales cycle is long (see below).

02

Add the hidden fields

Create one hidden field per parameter with the exact lowercase name. (In Zunoform: Settings, turn on Hidden fields, add each name, optionally with a default value such as "direct" for visits with no tag.)

03

Build tagged links

Tag the form link itself for emails, ads and social posts, using consistent lowercase values. Keep a shared list of allowed sources and mediums so two people don't invent "LinkedIn" and "linkedin-ads".

04

Test with a real submission

Open the tagged link in a private window, submit, and check the response. (In Zunoform the values appear in the response detail, as extra columns in the form's CSV export and in a connected Google Sheet, and in webhook or Zapier payloads.)

05

Handle landing pages and embeds

If the tagged link points to a landing page rather than the form, the parameters must be carried over. The next two sections cover this, and it is where most setups break.

06

Report by source

Group responses by utm_source and utm_campaign in your export or CRM, and compare lead quality, not just counts.

Why do UTM parameters go missing before the form?

UTMs live in the URL of the first page someone lands on. Three common situations drop them before the form ever sees them.

The visitor browses first

An ad lands on your pricing page with ?utm_campaign=spring. The visitor clicks to Features, then to Contact. The Contact page URL has no parameters, so a hidden field on that form reads nothing. This is the most common reason UTM hidden fields come back empty.

The form is embedded in an iframe

An embedded form runs at its own URL inside a frame. Unless the embed code copies the host page's query string onto the frame's address, the form sees none of it. Check what your builder's embed code does. Zunoform's embed script copies the host page's query string onto the frame, so a visitor who lands on the page that holds the form with ?utm_source=google is captured without extra work (add data-forward-params="false" to switch that off, or data-params to set values of your own). A plain iframe snippet copies nothing, so there you add the parameters to the iframe's src yourself, as in the snippet below.

Redirects and link shorteners

Most shorteners and redirects keep the query string, but some site redirects (http to https, trailing slashes, a language switch) rebuild the URL without it. Click your tagged link and look at the address bar where you end up.

First-touch vs last-touch: which should you store?

The fix for browsing visitors is to save the UTMs on arrival. First you have to decide which arrival counts.

ModelWhat it recordsBest for
First touchThe campaign that brought the person the very first time, kept even if they return later via another linkMeasuring which channels find new people; long B2B cycles
Last touchThe most recent tagged visit before they convertedMeasuring which campaign closed the deal; short cycles
BothTwo sets of fields, e.g. ft_source and utm_sourceMost teams: costs two extra hidden fields and settles arguments

How do you keep UTM parameters across pages?

A small script on your site saves the parameters when a visitor lands and adds them to the form link or iframe later. Where you save them changes how long they last.

StorageHow long it lastsScopeWatch out for
sessionStorageUntil the tab or window closesOne origin, one tabLost if they come back tomorrow; fine for same-visit attribution
localStorageNo expiry by designOne origin (protocol + domain)Safari deletes script-writable storage after 7 days of browser use without interaction on your site
First-party cookieWhatever expiry you setCan span subdomainsSame Safari 7-day cap for script-set cookies; count it in your cookie consent
Server-side (CRM or tag manager)As long as you keep itYour systemsMore setup; usually needs a developer

None of these works across different devices. A visitor who clicks an ad on a phone and converts on a laptop arrives untagged.

Sources: MDN: Window.localStorage · WebKit: Full Third-Party Cookie Blocking and More (7-day storage cap)

A copyable snippet: store first- and last-touch UTMs and pass them to your form

<script>
(function () {
  var KEYS = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
  var params = new URLSearchParams(window.location.search);
  var now = {};
  KEYS.forEach(function (k) { var v = params.get(k); if (v) now[k] = v.toLowerCase(); });
  var first = {}, last = now;
  try {
    if (Object.keys(now).length) {
      if (!localStorage.getItem("ft_utms")) localStorage.setItem("ft_utms", JSON.stringify(now));
      localStorage.setItem("lt_utms", JSON.stringify(now));
    }
    first = JSON.parse(localStorage.getItem("ft_utms") || "{}");
    last = JSON.parse(localStorage.getItem("lt_utms") || "{}");
  } catch (e) { /* storage blocked: fall back to this page's URL */ }
  // Adds last-touch as utm_* and first-touch as ft_* to form links and iframes.
  document.querySelectorAll('a[href*="/form/"], iframe[src*="/form/"]').forEach(function (el) {
    var attr = el.tagName === "IFRAME" ? "src" : "href";
    var url = new URL(el.getAttribute(attr), window.location.href);
    Object.keys(last).forEach(function (k) { if (!url.searchParams.has(k)) url.searchParams.set(k, last[k]); });
    Object.keys(first).forEach(function (k) { url.searchParams.set("ft_" + k.slice(4), first[k]); });
    el.setAttribute(attr, url.toString());
  });
})();
</script>

An example to adapt, not an official Zunoform script. Place it before the closing body tag, after your form links or a plain iframe whose src is your form URL (a script-injected embed may not exist yet when it runs; with Zunoform's embed script, write the stored values into the element's data-params attribute before embed.js loads instead). Add hidden fields named utm_source, utm_medium, utm_campaign, utm_term, utm_content, ft_source, ft_medium, ft_campaign, ft_term and ft_content, and keep only the ones you use.

How do you send UTM data to your CRM or Google Sheets?

Once the UTMs are on the response, they should travel with it. In most builders hidden fields are included wherever answers go: the spreadsheet row, the webhook payload, the CRM contact. Map utm_source to your CRM's lead source property and utm_campaign to a campaign property, rather than dumping them into a notes field nobody filters on.

Be precise about what your tool actually sends. In Zunoform, hidden fields appear in the response view, the per-form CSV export and the Business plan's REST API, and they travel with each delivery: Google Sheets and Excel rows get one extra column per hidden field (after the answer, location and user-agent columns), webhook, Zapier and workflow payloads carry them in a hidden object (hidden.utm_source), and Airtable fills columns with the same name. HubSpot and Mailchimp do not receive them yet, so to get UTMs into those, route the lead through Zapier or a webhook.

However you move the data, clean the values on the way in: lowercase them and map known variants ("fb", "facebook.com") to one name, or your source report will have six rows for Facebook.

How do you track form conversions by source in GA4?

GA4 already attributes each session to its UTM source, so what it needs from you is a reliable conversion event. Its enhanced measurement can send form_start and form_submit automatically for forms on your own pages, though Google notes the parameters need custom dimensions before they show in reports. The recommended event for a lead is generate_lead, which Google describes as firing when a user submits a form; mark it as a key event.

Embedded forms are the catch. GA's tag on your page cannot see clicks inside an iframe served from another domain, so form_submit will not fire for it. The dependable pattern is to redirect respondents after submitting to a thank-you page on your own site and fire generate_lead there. Zunoform can redirect after submit, and the redirect URL can carry answers, such as the plan someone picked, so the thank-you page can send them as event parameters. Test this on an embedded form: its redirect loads inside the frame, where browsers may limit analytics cookies, so it is most reliable when the form is opened as a direct link.

Keep personal data out of that URL. Google's guidance is that URL paths and parameters sent to Analytics must be free of PII, so pass a plan name or budget band, never an email or phone number.

Source: Google Analytics Help: Enhanced measurement events

Source: Google Analytics Help: Recommended events (generate_lead)

Source: Google Analytics Help: Best practices to avoid sending PII

UTM hidden field mistakes to check for

Forms where source tracking pays off

Where Zunoform fits (and where it doesn't)

Hidden fields are on every Zunoform plan, including Free: you name the parameters, set optional defaults, and the values are saved with each response, shown in the response detail and exported as CSV columns. Redirect after submit is on every plan too, and redirect URLs can carry answers to a thank-you page. If you switch a form to anonymous mode with hidden fields on, the builder warns you that URL values can still identify people.

Hidden field values go out with every Google Sheets, Excel, Zapier and webhook delivery, and the embed script forwards your page's query string to the form. The limits are real, though. The native HubSpot and Mailchimp integrations do not map hidden fields to contact properties, and there is no built-in first-touch storage, so the snippet above is your job. If you need UTMs written straight onto CRM contact properties without a Zapier or webhook step, a tool whose native CRM integration maps hidden fields, or a dedicated attribution plugin, is a better fit today.

Questions people ask

How do I capture UTM parameters in a form?

Add hidden fields named exactly like the parameters (utm_source, utm_medium, utm_campaign) and send people to the form with a tagged link. The form reads the values from its URL and saves them with each response. If visitors land on another page first, or the form is embedded, store the UTMs on arrival and append them to the form URL.

What is a hidden field in a form?

A hidden field is a field the respondent never sees. Its value comes from the page URL, a default, or a script, and it is saved alongside the visible answers. Common uses are UTM parameters, a customer or order ID from a personalized link, or the page the form was embedded on.

Why are my UTM hidden fields empty?

Usually because the form's own URL never had the parameters. Visitors browsed from the tagged landing page to another page, the form is in an iframe that does not receive the host page's query string, or a redirect stripped it. Test by opening a tagged link in a private window and submitting.

Should I store first-touch or last-touch UTMs?

Store both if you can. First touch shows which channels introduce new people, last touch shows which campaign preceded the conversion, and the difference is often the most useful part of the report. It costs a second set of hidden fields and a few lines of script that saves the first set without overwriting it.

Are UTM parameters case sensitive?

Yes. Google Analytics treats utm_source=Google and utm_source=google as different sources, and most CRMs do the same with text values. Agree on lowercase values, keep a shared list of allowed sources and mediums, and lowercase values when you capture them.

Do UTM parameters survive an embedded form?

Only if the embed passes them on. An embedded form loads at its own address inside a frame, so it sees the frame's URL, not your page's. Some embed codes copy the page's query string automatically, as Zunoform's embed script does; others, and any plain iframe, do not, so you add the parameters to the iframe URL yourself.

Can I send UTM data to Google Sheets or a CRM?

In most builders, yes: hidden fields travel with the answers to integrations. Check yours with a test submission. In Zunoform, hidden fields are added as columns in Google Sheets and Excel and sent in Zapier and webhook payloads, as well as appearing in the response view, the CSV export and the Business REST API. The native HubSpot and Mailchimp integrations do not carry them.

About the author

Raj Kumar · Founder, Zunoform

Raj Kumar is the founder of Zunoform, the form builder made by Symphonic Grow. He builds the product and writes these guides, checking every competitor price and feature claim against the vendor's own pages before publishing.

Raj Kumar on LinkedIn

Keep reading

Ready when you are

Better forms.
Better data.

Start with a conversation, a document or a single page.
Unlimited forms and 500 responses per month on Free.
No card required.

  • No credit card
  • Unlimited forms
  • 500 responses / month