Forms June 20, 2026 5 min read Updated July 29, 2026

Passing UTM parameters through Webflow forms into your CRM

Attribution breaks when someone lands on an ad, browses three pages, then converts. Here's how to carry the source through a Webflow form without losing it on the second click.

On this page

Why attribution breaks

Someone clicks a LinkedIn ad and lands on /pricing?utm_source=linkedin&utm_campaign=q3-launch. They read it, click through to a case study, then to the contact page, and submit the form.

By that point the URL is /contact with no parameters. The form records no source. In your CRM the lead is "direct", and your ad spend looks like it produced nothing.

Analytics tools handle this with their own session tracking, but that data lives in the analytics tool — not on the lead record your sales team looks at. To attribute a specific person to a specific campaign, the parameters have to travel with them and land in the submission.

Three problems to solve: capture on entry, persist across pages, and attach at submit.

Capture and persist

Store the parameters on first landing and keep them for the session:

(function () {
  const KEY = 'attribution';
  const FIELDS = [
    'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',
    'gclid', 'fbclid', 'msclkid',
  ];

  const params = new URLSearchParams(window.location.search);
  const found = {};

  FIELDS.forEach(field => {
    const value = params.get(field);
    if (value) found[field] = value;
  });

  const existing = JSON.parse(sessionStorage.getItem(KEY) || '{}');

  // First touch wins: don't let an internal link or a later visit
  // overwrite the campaign that actually brought them in.
  if (Object.keys(found).length && !existing.utm_source && !existing.gclid) {
    found.landing_page = window.location.pathname;
    found.referrer = document.referrer || 'direct';
    found.captured_at = new Date().toISOString();
    sessionStorage.setItem(KEY, JSON.stringify(found));
  }
})();

Put it in Site Settings → Custom Code → Before </body> so it runs on every page.

The click IDs matter as much as the UTMs. gclid (Google), fbclid (Meta) and msclkid (Microsoft) are what those platforms use for conversion import — if you ever want to send conversions back to the ad platform, the click ID is the join key and the UTMs are not.

First touch versus last touch is a real decision, not a detail. The code above keeps the first campaign that brought someone in. If your sales cycle involves several visits and you care about what triggered the final conversion, drop the guard and let later values overwrite. Most B2B teams want first touch; most e-commerce teams want last. Pick deliberately, because switching later makes historical data incomparable.

Attach to the form

Add hidden fields to your Webflow form — in the Designer, drag in a Text Field, set it to hidden in Settings, and give each a name matching your keys. Then populate on load:

(function () {
  const data = JSON.parse(sessionStorage.getItem('attribution') || '{}');

  document.querySelectorAll('form').forEach(form => {
    Object.entries(data).forEach(([key, value]) => {
      const field = form.elements[key];
      if (field) field.value = value;
    });
  });
})();

If you'd rather not maintain hidden fields by hand, create them:

Object.entries(data).forEach(([key, value]) => {
  if (form.elements[key]) return;
  const input = document.createElement('input');
  input.type = 'hidden';
  input.name = key;
  input.value = value;
  form.appendChild(input);
});

Webflow submissions include any named input in the form, so injected fields arrive alongside the visitor's answers.

Getting it into the CRM

Three routes, in ascending order of control.

Native integration. Webflow's built-in integrations and tools like Zapier or Make read submission fields, so mapping utm_source to a CRM property is configuration, not code. Simplest, and adequate for most teams.

Webhook. Point the form at your own endpoint, transform the payload, and write to the CRM API. More work, complete control over deduplication and field mapping.

Direct API from the browser. Don't. It requires a CRM key in client-side JavaScript, where anyone can read it.

Whichever route, create the CRM properties before you send data. Most CRMs silently drop unrecognised fields, which produces the worst outcome: everything appears to work and no attribution arrives.

The bits people miss

Cross-domain journeys. If your site is example.com and your app is app.example.com, sessionStorage doesn't cross subdomains. Pass the values in the link, or use a cookie scoped to .example.com.

Consent. Storing campaign identifiers is processing personal data in several jurisdictions. If your consent banner blocks analytics until acceptance, attribution capture belongs in the same gate. Running it before consent while blocking analytics after is inconsistent in a way that's hard to defend.

Internal links carrying UTMs. Someone builds a nav link with ?utm_source=newsletter on it and every internal click rewrites attribution. The first-touch guard above prevents the damage; also, don't UTM-tag your own internal links.

Storage disabled. Private browsing and some privacy settings make sessionStorage throw. Wrap reads and writes in try/catch, or a privacy-conscious visitor gets a form that silently fails to populate — or worse, a JavaScript error that breaks the page.

function safeGet(key) {
  try { return sessionStorage.getItem(key); }
  catch (e) { return null; }
}

Verify it end to end

Attribution is easy to believe in and hard to notice failing. Test the whole path once, properly:

  1. Open a private window. Land on yoursite.com/?utm_source=test&utm_campaign=verify.
  2. Click through two internal pages.
  3. Open DevTools → Application → Session Storage. Confirm the values survived.
  4. Submit the form. Check Webflow's submission record contains the hidden fields.
  5. Check the CRM record. Confirm the properties populated — this is where it usually fails.

Then repeat it quarterly. Attribution breaks silently when someone rebuilds a form and forgets the hidden fields, and the symptom — a gradual rise in "direct" leads — looks exactly like a marketing problem rather than a technical one. Teams have cut ad budgets over this.

Share

Our Products

We don’t just build apps; we create solutions that transform how you use Webflow. Whether you’re looking to streamline workflows, add advanced functionality, or scale your business, we’ve got you covered.

All apps