UTM tracking works the same way in theory across every form platform: hidden fields capture URL parameters and submit them with the form. The implementation details are different for every platform.
Here's the exact setup for the three form tools that account for the majority of WordPress and no-code sites.
Contact Form 7
Contact Form 7 is the most widely-used WordPress form plugin, and one of the more annoying to set up UTM tracking on, because it doesn't natively support reading URL parameters into hidden fields.
Option 1: Use a plugin (fastest)
The simplest path: install "Contact Form 7 UTM Tracker" or "CF7 Populate Fields" from the WordPress plugin directory. These plugins add a shortcode that reads URL parameters automatically.
With CF7 Populate Fields installed, add this to your form's template:
[hidden utm_source default:query_post_meta]
[hidden utm_medium default:query_post_meta]
[hidden utm_campaign default:query_post_meta]
[hidden utm_content default:query_post_meta]
[hidden utm_term default:query_post_meta]
The plugin reads each field name as a query parameter from the URL and pre-fills the hidden field on page load. No additional JavaScript required.
Option 2: JavaScript (no additional plugin)
Add this to your theme's footer (or use a plugin like Code Snippets to add it without editing theme files):
document.addEventListener("DOMContentLoaded", function () {
const params = new URLSearchParams(window.location.search);
const utmFields = ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"];
utmFields.forEach(function(key) {
const input = document.querySelector('input[name="' + key + '"]');
if (input && params.get(key)) {
input.value = params.get(key);
}
});
});
In your CF7 form template, add the hidden fields first:
[hidden utm_source]
[hidden utm_medium]
[hidden utm_campaign]
[hidden utm_content]
[hidden utm_term]
The JavaScript will find these fields and populate them from the URL on page load.
Connecting CF7 to your CRM
CF7 doesn't have native CRM integrations. You'll use either the CF7 to Zapier plugin or Flamingo (CF7's companion plugin for storing submissions) plus a Zapier workflow.
In Zapier, when building the "Create Contact in [CRM]" action, you'll see the CF7 field names in the trigger data. Map each UTM field explicitly to the corresponding CRM property.
Test it
Visit yoursite.com/contact-page?utm_source=test&utm_medium=test&utm_campaign=test, submit the form, then check Zapier's task history or your CRM for the test lead. Verify UTM values populated.
Gravity Forms
Gravity Forms has better native support for UTM capture than CF7, but there are still configuration steps.
Using Gravity Forms' Parameter Field
Gravity Forms has a built-in "Hidden" field that can read from URL parameters:
- Add a new field to your form, choose "Advanced Fields" → "Hidden"
- Give it a field label (e.g., "UTM Source"), this is internal only
- Under "Default Value," enter
\{query:utm_source\}
The \{query:parameter_name\} syntax is Gravity Forms' built-in shortcode for reading URL parameters. Do this for each of the five UTM parameters.
CRM integration with Gravity Forms
Gravity Forms has official add-ons for HubSpot, Salesforce, and Mailchimp. In each add-on, you'll see a field mapping section where you specify which form field maps to which CRM field.
Map each hidden UTM field to the corresponding CRM property (custom contact properties in HubSpot, custom Lead fields in Salesforce).
For GoHighLevel users: there's no official GF add-on for GHL. Use Gravity Forms → Zapier → GoHighLevel, mapping UTM fields in the Zap action.
The multi-step Gravity Forms issue
If you're using Gravity Forms' multi-page feature (the form spans multiple pages), hidden fields only read URL parameters on the page they're placed on. Add your hidden UTM fields to the first page of the form, they'll be stored in form state and submitted when the final page is submitted.
Typeform
Typeform handles hidden fields differently from most form tools. They're configured at the form URL level, not inside the form builder.
Setting up UTM hidden fields in Typeform
- Open your Typeform and go to Connect → Hidden fields
- Click "Add hidden field"
- Enter the field identifier:
utm_source - Repeat for utm_medium, utm_campaign, utm_content, utm_term
Save the form. Now, when you share your Typeform link with UTM parameters appended (https://yourform.typeform.com/to/abc123?utm_source=linkedin), Typeform reads those parameters and attaches them to the response.
Viewing UTM data in Typeform
In your Typeform results, each response will show the hidden field values alongside the answers. You can export results to CSV and the UTM columns will be included.
Connecting Typeform to your CRM
Typeform has native integrations with HubSpot and Salesforce. In the integration settings, you'll see a field mapper. Map each UTM hidden field to the corresponding CRM property.
For Zapier: in the Zap trigger, Typeform passes hidden fields as part of the response payload. They appear as separate fields in the Zap action mapper.
The Typeform UTM gotcha
Typeform requires UTM parameters to be appended to the Typeform URL itself, not a landing page URL that embeds the Typeform. If you're embedding a Typeform on your website, the visitor's URL (with UTMs) isn't the same as the Typeform URL. You'll need a custom embed script that reads UTMs from the page URL and appends them to the Typeform URL on the fly.
Here's how:
document.addEventListener("DOMContentLoaded", function () {
const params = new URLSearchParams(window.location.search);
const tfIframe = document.querySelector('iframe[src*="typeform.com"]');
if (tfIframe) {
const url = new URL(tfIframe.src);
["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"].forEach(function(key) {
if (params.get(key)) url.searchParams.set(key, params.get(key));
});
tfIframe.src = url.toString();
}
});
Platform comparison at a glance
| CF7 | Gravity Forms | Typeform | |
|---|---|---|---|
| Native UTM support | No (needs plugin or JS) | Yes (query shortcode) | Yes (hidden fields setting) |
| Best CRM integration path | Zapier | Native add-ons or Zapier | Native integrations or Zapier |
| Embedded form UTM issue | No | No | Yes, needs extra script |
| Multi-step form note | N/A | Add hidden fields on page 1 | N/A |
| Maintenance overhead | Medium | Low | Low |
The alternative: skip per-form setup entirely
Every method above requires you to configure forms individually and maintain that configuration as forms change. Add a new landing page, forget the hidden fields, and those leads come in untracked.
Trakt solves this by scanning your site automatically and injecting UTM hidden fields into every form it detects, CF7, Gravity Forms, Typeform embeds, and most other form tools. When a form changes or a new one is added, Trakt's injection updates.
See how Trakt handles this automatically →

