Why do UTM parameters vanish before a visitor fills out your form?
Because UTM parameters live in the landing page URL, and they disappear the moment the visitor clicks to another page. A buyer lands on your blog from a LinkedIn ad, reads, clicks to pricing, then books a demo. By then the URL is clean, and the form submits with no idea where the visit began.
In my view, this is the most common attribution leak on B2B sites. The UTM links are built correctly. Analytics shows the campaign sessions. But the CRM records every lead as direct or unknown, because the form only ever sees the page it sits on, not the page where the visit started.
This tutorial is for one specific situation: a Webflow site where people often land on one page and convert on another. The fix is to store the UTM values when the visitor first arrives, keep them for the session, and drop them into hidden form fields at the moment of submission.
What do you need before you start?
You need four things: a Webflow site with a native form, access to add custom code to the site or page, an agreed UTM naming convention, and a place in your CRM to receive the values. Check that your Webflow plan supports custom code, and set up the CRM properties before writing any code.
The naming convention matters more than people expect. If one campaign uses linkedin and another uses LinkedIn, your reports split one source into two. If you have not agreed on a convention yet, do that first. My UTM naming convention tutorial walks through a simple spreadsheet that keeps everyone consistent.
On the CRM side, create one property per value you plan to keep. In HubSpot, Salesforce, or any CRM, the usual set is first touch source, medium, campaign, content, and term, plus the landing page URL and the referrer. Use clear names that say first touch, so nobody confuses them with last-touch fields later.
Step 1: How do you add hidden fields to a Webflow form?
Add one hidden input per value inside the form element, placed above the submit button. A common approach in Webflow is to place a Code Embed element inside the form that holds plain HTML hidden inputs, each with a clear name like utm_source or landing_page.
Name the inputs exactly as you want them to appear in form submissions and in your integrations. Use lowercase and underscores. The name is what your CRM mapping, Zapier step, or Make scenario will read, so changing it later means fixing every downstream connection.
Give each hidden input an empty value for now. The script in the next steps fills them in. Keep all of them inside the same form wrapper as the visible fields. An input that sits outside the form element will not be submitted with the form, which is the first thing to check if a value goes missing.
Step 2: How do you store UTMs when the visitor first lands?
Add a short script that runs on every page. When a page loads, it reads the URL query string. If any UTM parameter is present and nothing is stored yet, it saves the values, the full landing page URL, and the referrer to browser storage. If values are already stored, it leaves them alone.
That one rule, save only if empty, is what makes this first touch. A visitor who arrives from a paid ad and later clicks an internal link keeps the paid ad as their source. Without the rule, any later visit carrying different UTMs would quietly overwrite the original source.
Use the browser's built-in URLSearchParams to read the query string, rather than splitting the URL by hand. It handles encoding and edge cases cleanly. Place the script in the site-wide footer custom code so it runs on every page, including blog posts and CMS template pages where many visits begin.
Step 3: Should you use session storage or local storage?
Use session storage if you only care about the current visit, and local storage if you want to remember the first touch across visits. Session storage clears when the browser tab closes. Local storage persists until it is cleared. For B2B buying cycles that span weeks, local storage usually tells a truer story.
Local storage comes with a responsibility. You are keeping marketing data in the visitor's browser over time, so make sure your cookie and privacy notice covers it and that your consent tool treats it correctly. If your site needs consent before storing marketing data, run the script only after consent is given.
A practical middle ground is to store a timestamp with the values and treat anything older than ninety days as expired. That keeps the data meaningful without holding on to it forever. Whatever you pick, write the rule down so the next person understands why a lead shows a source from last month.
Step 4: How do you fill the hidden fields before submission?
On pages with a form, extend the script to copy the stored values into the hidden inputs when the page loads. Match each stored value to the input with the same name. If nothing is stored, fill the landing page field with the current URL, so every lead carries at least one clue about its origin.
Fill the fields on page load rather than on submit. Some form tools and integrations read values at submission time in ways that can race a last-second script. Filling early means the values are already in place by the time anyone clicks the button.
If you have several forms on one page, such as a newsletter signup in the footer and a demo form in the body, give the hidden inputs the same names in each form. The script can then fill every matching input on the page in one pass.
Step 5: How do you test that it actually works?
Test on the published site, not just in the Designer. Open a private browser window, visit a page with test UTMs in the URL, click to a different page, and submit the form. Then check the form submission in Webflow and the new record in your CRM. Every hidden value should match the first URL.
Run three more tests. Land with UTMs, then revisit with different UTMs, and confirm the first values survive. Land with no UTMs and confirm the landing page field still fills. Then submit from a mobile browser, because storage and script behavior can differ there and mobile visitors are often the ones who browse before converting.
Also test any redirects in your campaign links. If a redirect strips the query string before the page loads, the script never sees the UTMs. I covered that failure in what happens to UTM parameters through a redirect, and it is worth ruling out before you blame the code.
Step 6: How do you get the values into your CRM correctly?
Map each hidden field to its first-touch property in whatever moves data from Webflow to your CRM. That might be a native integration, a Zapier zap, a Make scenario, or n8n. Then set those properties to write only when empty, so a returning lead's original source is never overwritten by a later form.
This is where many setups break quietly. The form captures the right values, but the integration overwrites the CRM property on every new submission. A lead who first came from a webinar and later from a retargeting ad ends up credited to the ad. Check the update behavior for each mapped property in your tool.
Once the data flows, build one simple report: leads and opportunities by first-touch source and campaign. If you also capture last-touch values, show them side by side. The gap between the two is often the most useful thing in your marketing reporting, and the UTM tracking setup for Webflow campaigns covers the tagging that feeds it. To carry that value through to revenue, see how to tag every deal with its first campaign in HubSpot.
What should you do next?
Create the first-touch properties in your CRM, add the hidden inputs to your main demo form, and install the storage script site-wide. Then run the four tests above on the published site. Within a week of real traffic, your CRM should show where leads actually started instead of a wall of direct and unknown.
Once this works on one form, roll it out to every form on the site, including newsletter and content download forms. Attribution only becomes trustworthy when every entry point records the same fields the same way.
If you want help wiring first-touch attribution from Webflow into HubSpot or another CRM, reach out. I build websites and the automations behind them for lead generation, and clean source data is where that work starts. Let's chat.
Get found, cited and the back office automated
Let's make your site the source AI engines quote and wire up the systems behind it.
Read more blogs
Let's get your website found and cited by AI
Tell me what you're working on, whether AI search is skipping your product, your back office is buried in manual work, or you need a build that does both.