Key takeaways
- UTM parameters in a URL (utm_source, utm_medium, utm_campaign) can be read with JavaScript’s URLSearchParams and saved to hidden form fields.
- This lets you know which ad, email, or campaign generated each contact form submission.
- Hidden fields submit with the form and appear in the submission data alongside the customer’s message.
- Describe this requirement to Fudge — it can build the complete implementation including hidden fields and JavaScript.
When someone fills out your contact form after clicking a Facebook ad, you want to know that. When a wholesale inquiry comes in after a specific email campaign, you want to attribute it correctly. UTM parameter capture in forms closes the attribution gap between “this person contacted us” and “this campaign drove that contact.”
How to use UTM on Shopify
UTM parameters are appended to URLs in your marketing links:
https://yourstore.com/pages/contact?utm_source=facebook&utm_medium=paid&utm_campaign=summer_sale
When someone lands on this URL, the UTM values exist in the browser’s URL bar. JavaScript can read them and store them so they travel with the form submission.
How to get UTM parameters from a URL with JavaScript
The modern, clean way to read URL parameters is URLSearchParams:
var params = new URLSearchParams(window.location.search);
var utmSource = params.get('utm_source'); // "facebook"
var utmMedium = params.get('utm_medium'); // "paid"
var utmCampaign = params.get('utm_campaign'); // "summer_sale"
var utmContent = params.get('utm_content'); // optional
var utmTerm = params.get('utm_term'); // optional (for paid search)
If there’s no UTM parameter in the URL, params.get() returns null. Handle this gracefully by using empty string fallbacks.
Adding hidden UTM fields to a Shopify form
Step 1 - Add hidden fields to your form HTML.
In your theme’s contact form (typically in sections/contact-form.liquid or the contact page template), add hidden input fields inside the form:
<input type="hidden" id="utm-source" name="contact[utm_source]" value="" />
<input type="hidden" id="utm-medium" name="contact[utm_medium]" value="" />
<input type="hidden" id="utm-campaign" name="contact[utm_campaign]" value="" />
<input type="hidden" id="utm-content" name="contact[utm_content]" value="" />
For custom forms or apps: use name="properties[UTM Source]" format for line item properties, or whatever naming convention your form system expects.
Step 2 - Read UTM values and populate the fields with JavaScript.
Add this script after your form (or in theme.liquid before </body>):
<script>
(function() {
var params = new URLSearchParams(window.location.search);
var utmFields = {
'utm_source': 'utm-source',
'utm_medium': 'utm-medium',
'utm_campaign': 'utm-campaign',
'utm_content': 'utm-content'
};
Object.keys(utmFields).forEach(function(param) {
var value = params.get(param);
var field = document.getElementById(utmFields[param]);
if (value && field) {
field.value = value;
}
});
})();
</script>
Step 3 - Test. Open your contact page with UTM parameters in the URL:
https://yourstore.com/pages/contact?utm_source=test&utm_campaign=test_campaign
Submit the form and check the email notification — the UTM values should appear in the submission.
Persisting UTMs across multiple pages
A common problem: a visitor clicks your ad (UTMs are on the landing page URL), browses a few product pages, then visits the contact page directly — which has no UTMs in the URL. By the time they reach the form, the UTM values are gone.
Solution: store UTMs in sessionStorage (or localStorage) on first visit.
(function() {
var params = new URLSearchParams(window.location.search);
var utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
// Store UTMs on first page load if present
utmParams.forEach(function(param) {
var value = params.get(param);
if (value) {
sessionStorage.setItem(param, value);
}
});
// Populate form fields from storage (fallback from URL)
function populateField(paramName, fieldId) {
var value = params.get(paramName) || sessionStorage.getItem(paramName) || '';
var field = document.getElementById(fieldId);
if (field) field.value = value;
}
populateField('utm_source', 'utm-source');
populateField('utm_medium', 'utm-medium');
populateField('utm_campaign', 'utm-campaign');
populateField('utm_content', 'utm-content');
})();
sessionStorage persists values within a browser session (until the tab is closed). localStorage persists across sessions — more powerful, but also picks up UTMs from weeks-old visits, which may not be what you want.
UTM capture with form apps
Most dedicated form tools (Typeform, JotForm, Hulk Form Builder) have built-in UTM tracking:
Typeform: In the form settings, go to Hidden Fields → add UTM parameters. Typeform automatically reads these from the URL and attaches them to submissions.
Jotform: Prefill fields from URL parameters — add a field, go to Properties → Prefill → From URL Parameter.
These built-in options are simpler than custom JavaScript and worth using if you’re already using these tools.
What to do with UTM data in form submissions
Email routing. Send paid media leads to your sales team, organic leads to your content team.
CRM attribution. When the form submission enters your CRM (via Zapier, HubSpot integration, etc.), the UTM values travel with it. You can filter deals by source and see which campaigns generate the highest-value customers.
ROI reporting. If you know a wholesale customer came from a specific LinkedIn campaign, you can attribute their lifetime value back to that campaign — far more accurate than last-click analytics.