Gravity Forms is the most widely used premium form plugin for WordPress. If you’re running paid campaigns and collecting leads through Gravity Forms, you’ve almost certainly hit this wall: form entries arrive with a name, email, and phone number — but nothing about where the lead actually came from.
You’re spending money on Google Ads, Facebook campaigns, LinkedIn promotions, and Microsoft Advertising. But when a lead submits your Gravity Form, the entry tells you nothing about which ad, campaign, or channel drove them to your site. Every lead looks identical: no source, no campaign, no attribution trail.
This guide fixes that. You’ll learn how to capture UTM parameters, click IDs (gclid, fbclid, msclkid, li_fat_id, ttclid), and the referrer URL in Gravity Forms — so every form entry carries complete attribution data. We’ll cover the native dynamic population method, explain exactly why it breaks in real-world conditions, show the JavaScript and cookie approach that actually works, and introduce an automated solution that handles everything with zero configuration.
What Attribution Data Should Gravity Forms Capture?
Before configuring anything, understand the four types of data that a form entry should include to give you a complete picture of where each lead came from:
| Data Type | What It Tells You | Example |
|---|---|---|
| UTM parameters | Which campaign, source, medium, keyword, and ad creative sent the visitor | utm_source=google, utm_medium=cpc, utm_campaign=spring-promo |
| Click IDs | A unique identifier linking the click to a specific ad platform for offline conversion tracking | gclid=Cjw…, fbclid=IwAR3…, msclkid=abc123 |
| Referrer URL | The website or search engine the visitor came from before landing on your site | https://www.google.com/ |
| Landing page | The first page on your site the visitor saw — confirms which campaign URL they arrived on | /services/?utm_source=google&utm_medium=cpc |
Together, these four data points give you a complete attribution trail for every lead. UTM parameters reveal the campaign context. Click IDs let you send conversions back to the ad platform. The referrer identifies organic and social traffic. And the landing page confirms the visitor’s entry point.
Gravity Forms captures none of this by default. But it does offer a built-in feature — dynamic population — that can pull query string values into hidden fields. Let’s start there.
Method 1: Hidden Fields with Dynamic Population (the Native Approach)
Gravity Forms supports dynamic population — a feature that pulls values from URL query strings into form fields. Here’s how to set it up for UTM tracking:
Step 1: Add Hidden Fields
Open your form in the Gravity Forms editor. Under “Standard Fields,” drag a Hidden field onto your form. Add one hidden field for each data point you want to capture. At minimum, create fields for:
- utm_source
- utm_medium
- utm_campaign
- utm_term
- utm_content
Label each field to match the parameter it tracks (e.g., label the first one “UTM Source”).
Step 2: Enable Dynamic Population
Click on each hidden field, go to the Advanced tab, and check “Allow field to be populated dynamically.” A text input labelled “Parameter Name” will appear. Enter the exact query string parameter name — for example, utm_source for the UTM Source field.
Repeat for each hidden field:
| Field Label | Parameter Name |
|---|---|
| UTM Source | utm_source |
| UTM Medium | utm_medium |
| UTM Campaign | utm_campaign |
| UTM Term | utm_term |
| UTM Content | utm_content |
Step 3: Include Fields in Notification Emails
By default, Gravity Forms notification emails include the {all_fields} merge tag, which will output the values of your hidden fields. If you’ve customised your notification template, make sure you either include {all_fields} or add individual merge tags for each hidden field (e.g., {UTM Source:15} — the number is the field ID shown in the form editor).
Step 4: Test It
Add UTM parameters to your form page URL and submit a test entry:
https://yoursite.com/contact/?utm_source=google&utm_medium=cpc&utm_campaign=spring-sale
Check the form entry in Forms > Entries. Your hidden fields should show the UTM values from the URL.
This native method works — but only under ideal conditions. In practice, it breaks in several common scenarios.
Why Dynamic Population Breaks (and How to Fix Each Issue)
The native dynamic population method is fragile. Here are the five most common reasons it fails for UTM tracking — and the fix for each one.
1. Page Caching Serves Stale Values
This is the most common cause of failure. Dynamic population uses server-side PHP to read query string values and inject them into the form HTML. If your page is cached — by a caching plugin (WP Super Cache, W3 Total Cache, WP Rocket) or by your hosting provider (WP Engine, Kinsta, Cloudflare) — the cached version of the page is served instead of a fresh PHP render. The hidden fields get the values from the first visitor’s URL, and every subsequent visitor sees those same stale values.
This isn’t just an inconvenience — it’s a data integrity problem. One user’s UTM data gets assigned to another user’s form submission.
Fix: Exclude the form page from your cache. In most caching plugins, you can add the page URL to an exclusion list. On managed hosts like WP Engine, check the “Cache Exclusions” settings. However, this sacrifices the performance benefits of caching for that page.
2. UTM Parameters Disappear on Page Navigation
This is the most fundamental limitation. UTM parameters only exist in the URL of the landing page. The moment a visitor clicks to any other page on your site, those parameters vanish from the URL. If your form is on a different page than the landing page — which is the case for most websites — the hidden fields have nothing to read.
Example: A visitor clicks your Google Ad and lands on /services/?utm_source=google&utm_medium=cpc. They browse around, then navigate to /contact/ to fill out your form. The /contact/ URL has no query string parameters. Dynamic population finds nothing. Your form entry shows blank UTM fields.
Fix: Store UTM values in cookies on the landing page, then read from cookies (not the URL) when the form loads. We’ll cover the full implementation below.
3. Reserved WordPress Parameter Names Cause 404 Errors
WordPress reserves certain parameter names for internal use. If you use one as a dynamic population parameter — name, page, type, year, month, day — you’ll get unexpected behaviour or outright 404 errors. The standard UTM parameter names (utm_source, utm_medium, etc.) are safe, but if you’re adding custom parameters, check the WordPress reserved terms list first.
Fix: Use prefixed parameter names (e.g., lsp_source instead of source) for any custom parameters. The standard utm_ parameters are not reserved and work fine.
4. Administrative Visibility Instead of Hidden
Gravity Forms offers two ways to hide a field from the user: setting the field type to “Hidden” or setting a regular field’s visibility to “Administrative.” These are not the same thing. Administrative fields are excluded from form submissions — they can’t be dynamically populated via query strings. If you accidentally set visibility to Administrative instead of using a proper Hidden field, your UTM values won’t come through.
Fix: Use the dedicated “Hidden” field type from the Standard Fields panel, not the visibility toggle on other field types.
5. Dynamic Population Only Works When Logged In
If dynamic population works when you’re logged into WordPress but fails for anonymous visitors, caching is almost certainly the culprit. Most caching plugins exclude logged-in users from the cache (because the admin bar and other user-specific elements need to render dynamically). This means you see correct values during testing but your actual leads get stale or empty values.
Fix: Test in an incognito/private browsing window, or log out of WordPress before testing. If values appear when logged in but not when logged out, confirm your caching plugin settings and exclude the form page.
Method 2: JavaScript and Cookies (the Reliable Approach)
The native method’s core weakness is that it reads from the URL at page-load time. A more reliable approach stores UTM values in the visitor’s browser cookies on the first page load, then populates the form fields from those cookies — regardless of which page the form is on.
This approach involves two parts: a JavaScript snippet that captures and stores the data, and a PHP filter that reads cookies and populates the hidden fields.
Part 1: Capture and Store UTM Parameters in Cookies
Add this JavaScript to your site (via your theme’s header, a custom plugin, or a code snippets plugin). It runs on every page load and stores any UTM parameters found in the URL as first-party cookies that persist for 90 days:
<script>
(function() {
var params = ['utm_source', 'utm_medium', 'utm_campaign',
'utm_term', 'utm_content', 'gclid', 'fbclid',
'msclkid', 'li_fat_id', 'ttclid'];
var search = new URLSearchParams(window.location.search);
var dominated = false;
// Only overwrite cookies if this page has UTM/click ID params
params.forEach(function(p) {
if (search.has(p)) dominated = true;
});
if (dominated) {
params.forEach(function(p) {
var val = search.get(p) || '';
document.cookie = p + '=' + encodeURIComponent(val) +
';path=/;max-age=7776000;SameSite=Lax';
});
}
// Always capture referrer and landing page on first visit
if (!getCookie('landing_page')) {
document.cookie = 'landing_page=' +
encodeURIComponent(window.location.href) +
';path=/;max-age=7776000;SameSite=Lax';
document.cookie = 'referrer_url=' +
encodeURIComponent(document.referrer || '(direct)') +
';path=/;max-age=7776000;SameSite=Lax';
}
function getCookie(name) {
var match = document.cookie.match(
new RegExp('(^| )' + name + '=([^;]+)')
);
return match ? decodeURIComponent(match[2]) : '';
}
})();
</script>
This script captures all five UTM parameters plus the five major click IDs (gclid, fbclid, msclkid, li_fat_id, ttclid) and stores them as cookies. It also captures the original landing page URL and referrer on first visit only.
Part 2: Populate Gravity Forms Hidden Fields from Cookies
Add this PHP code to your theme’s functions.php file or a site-specific plugin. It uses the gform_field_value filter to read cookie values and inject them into hidden fields:
// Populate Gravity Forms hidden fields from cookies
$lsp_params = array(
'utm_source', 'utm_medium', 'utm_campaign',
'utm_term', 'utm_content', 'gclid', 'fbclid',
'msclkid', 'li_fat_id', 'ttclid',
'landing_page', 'referrer_url'
);
foreach ( $lsp_params as $param ) {
add_filter( 'gform_field_value_' . $param, function( $value ) use ( $param ) {
return isset( $_COOKIE[ $param ] ) ? sanitize_text_field( $_COOKIE[ $param ] ) : '';
});
}
Part 3: Configure the Hidden Fields in Your Form
In the Gravity Forms editor, add a Hidden field for each parameter. Enable “Allow field to be populated dynamically” on each one and set the Parameter Name to match:
| Field Label | Parameter Name | Data Captured |
|---|---|---|
| UTM Source | utm_source | Traffic source (google, facebook, linkedin) |
| UTM Medium | utm_medium | Marketing medium (cpc, email, social) |
| UTM Campaign | utm_campaign | Campaign name |
| UTM Term | utm_term | Paid search keyword |
| UTM Content | utm_content | Ad variation identifier |
| GCLID | gclid | Google Ads click ID |
| FBCLID | fbclid | Meta/Facebook click ID |
| MSCLKID | msclkid | Microsoft Ads click ID |
| LinkedIn Click ID | li_fat_id | LinkedIn Ads click ID |
| TikTok Click ID | ttclid | TikTok Ads click ID |
| Landing Page | landing_page | First page URL the visitor saw |
| Referrer URL | referrer_url | External site that sent the visitor |
Part 4: Test the Full Flow
Open an incognito window (to ensure no cached session). Navigate to your site with UTM parameters in the URL:
https://yoursite.com/services/?utm_source=google&utm_medium=cpc&utm_campaign=spring-sale&gclid=test123
Then navigate to a different page — your contact page, for example — and submit the form. Check the entry in Forms > Entries. The UTM values and gclid from the original landing page should appear in the hidden fields, even though the form page URL had no query string.
Tracking Which Ad Brought Each Submission
Capturing UTM parameters is only half the story. To know exactly which ad generated a lead, you also need to capture click IDs — the unique identifiers that ad platforms append to your URL when someone clicks an ad.
Here are the click IDs used by the major ad platforms:
| Ad Platform | Click ID Parameter | How It’s Added |
|---|---|---|
| Google Ads | gclid | Auto-tagging (enabled by default) |
| Meta (Facebook/Instagram) | fbclid | Automatic on all ad clicks |
| Microsoft Advertising | msclkid | Auto-tagging (enabled by default) |
| LinkedIn Ads | li_fat_id | Requires enabling click ID tracking in campaign settings |
| TikTok Ads | ttclid | Automatic when TikTok Pixel is installed |
The JavaScript snippet above already captures all five click IDs. The important thing to understand is why click IDs matter separately from UTM parameters.
UTM parameters tell you the campaign context — the source, medium, and campaign name. Click IDs go further: they link a specific form submission to a specific ad click in the ad platform. This is what enables offline conversion tracking — the ability to feed conversion data back to Google Ads, Meta, or Microsoft Advertising so their algorithms can optimise for leads that actually convert to sales.
For a deeper dive into how each click ID works, see our guides on gclid tracking, fbclid tracking, and Microsoft, LinkedIn, and TikTok click IDs.
Capturing the Referrer URL in Gravity Forms
Not all traffic arrives with UTM parameters. Organic search visitors, social media referrals, and links from other websites don’t carry UTM tags — but the referrer URL tells you where they came from.
Gravity Forms offers two native approaches to capture the referrer, but both have significant limitations:
Native Option 1: The {referer} Merge Tag
Add a Hidden field to your form. In the Advanced tab, set the Default Value to {referer} (note the single ‘r’ — this is the Gravity Forms merge tag spelling). This will populate the field with the HTTP referer header.
Limitation: The {referer} merge tag captures the last page URL, not the original external referrer. If a visitor arrives from Google, browses three pages, then submits your form, the referer will show your own site’s internal page — not Google. This makes it useless for attribution.
Native Option 2: The PHP Filter Method
The official Gravity Forms documentation suggests using the gform_field_value_refurl filter to read $_SERVER['HTTP_REFERER'] and inject it into a hidden field. This has the same limitation — it captures the last page’s URL, not the original external source.
Additionally, the HTTP referer header is unreliable. Some browsers strip it entirely, HTTPS-to-HTTP transitions may not send it, and privacy extensions can block it.
The Cookie Approach (Reliable)
The JavaScript snippet in Method 2 above already handles this correctly. It captures document.referrer on the visitor’s first page load and stores it in a cookie. Since it only writes the referrer cookie when no existing landing_page cookie exists, it preserves the original external referrer even after the visitor navigates to other pages on your site.
This gives you the actual source — https://www.google.com/, https://www.facebook.com/, or (direct) — rather than an internal page URL.
What Your Form Entries Should Look Like
Once you’ve set up either Method 1 (for simple single-page setups) or Method 2 (for reliable cross-page tracking), here’s an example of what a Gravity Forms entry looks like with full attribution data:
| Field | Value |
|---|---|
| Name | Sarah Chen |
| sarah@example.com | |
| Phone | 021 555 1234 |
| Message | Interested in your services — can you send pricing? |
| UTM Source | |
| UTM Medium | cpc |
| UTM Campaign | brand-search-nz |
| UTM Term | marketing agency wellington |
| GCLID | CjwKCAjw7NKxBhA…xRtGhQ |
| Referrer URL | https://www.google.com/ |
| Landing Page | /services/?utm_source=google&utm_medium=cpc |
Now you know that Sarah found you through a Google Ads brand search campaign, searched for “marketing agency wellington,” and landed on your services page. You have the gclid to feed back to Google Ads as an offline conversion once she becomes a customer. That’s attribution at the individual lead level — something Google Analytics cannot provide.
Setting Up Your Ads with UTM Parameters
For any of this to work, your ad URLs need to include UTM parameters. Here’s how to tag your campaigns on each major platform:
Google Ads
Google Ads auto-tags clicks with the gclid parameter by default. For UTM parameters, add a tracking template at the campaign or account level:
{lpurl}?utm_source=google&utm_medium=cpc&utm_campaign={campaignname}&utm_term={keyword}&utm_content={creative}
Meta (Facebook/Instagram) Ads
In Ads Manager, edit the URL Parameters field at the ad level:
utm_source=facebook&utm_medium=paid-social&utm_campaign={{campaign.name}}&utm_content={{ad.name}}
Microsoft Advertising
Microsoft auto-tags with msclkid. Add UTM parameters via the tracking template:
{lpurl}?utm_source=bing&utm_medium=cpc&utm_campaign={CampaignName}&utm_term={QueryString}
LinkedIn Ads
Add UTM parameters in the Destination URL field of each ad:
https://yoursite.com/landing-page/?utm_source=linkedin&utm_medium=paid-social&utm_campaign=your-campaign-name
Enable the LinkedIn Insight Tag and click ID tracking in your campaign settings to capture li_fat_id.
TikTok Ads
In TikTok Ads Manager, add UTM parameters to your destination URL:
https://yoursite.com/landing-page/?utm_source=tiktok&utm_medium=paid-social&utm_campaign=__CAMPAIGN_NAME__
TikTok automatically appends the ttclid parameter when the TikTok Pixel is installed on your site.
Method 3: Automatic Tracking with LeadSourcePro
The manual methods above work, but they require maintaining JavaScript code, PHP snippets, and hidden field configuration across every form. If any piece breaks — a theme update overwrites your functions.php, a caching plugin reconfigures, or a new form is created without the hidden fields — your attribution data silently stops flowing.
LeadSourcePro eliminates all of that. It’s a WordPress plugin that captures UTM parameters, click IDs (gclid, fbclid, msclkid, li_fat_id, ttclid), the referrer URL, and the landing page automatically — with zero configuration. There are no hidden fields to add, no JavaScript to maintain, and no PHP filters to write.
Here’s how it works:
- Install and activate the plugin. That’s the entire setup process.
- LeadSourcePro captures attribution data automatically on every page load — UTM parameters, click IDs, referrer, and landing page — and stores it in the visitor’s session using first-party cookies.
- When a visitor submits any Gravity Form, LeadSourcePro attaches the attribution data to the form entry. No hidden fields needed.
- View the data in your Gravity Forms entries, in notification emails, or export it to your CRM.
LeadSourcePro works with Gravity Forms and eight other form plugins (including Contact Form 7, WPForms, Ninja Forms, Elementor Forms, Formidable Forms, Fluent Forms, WS Form, and HubSpot Forms). It handles caching automatically, persists data across page navigation, and captures both first-touch and last-touch attribution.
Comparing the Three Methods
Here’s a side-by-side comparison to help you decide which approach fits your situation:
| Feature | Native Dynamic Population | JavaScript + Cookies | LeadSourcePro |
|---|---|---|---|
| UTM parameters | Yes (same page only) | Yes (all pages) | Yes (all pages) |
| Click IDs (gclid, fbclid, etc.) | Manual per-ID setup | Yes (with code) | Yes (automatic) |
| Referrer URL | Last page only | Original referrer (with cookies) | Original referrer (automatic) |
| Landing page URL | No | Yes (with cookies) | Yes (automatic) |
| Works with page caching | No | Yes | Yes |
| Persists across page navigation | No | Yes | Yes |
| Hidden fields required | Yes (manual setup) | Yes (manual setup) | No |
| Code required | No | Yes (JS + PHP) | No |
| Works with multi-page forms | First page only | Yes | Yes |
| Works with AJAX-loaded forms | Depends on cache | Yes | Yes |
| Maintenance required | Low (but fragile) | Medium (code updates) | None |
Setup Checklist
Whichever method you choose, make sure you’ve covered these steps:
- Add UTM parameters to all your ad campaign URLs (Google Ads, Meta, Microsoft, LinkedIn, TikTok)
- Enable auto-tagging for click IDs on each ad platform (gclid, msclkid are on by default; li_fat_id and ttclid require configuration)
- Configure hidden fields in Gravity Forms with the correct parameter names (if using Method 1 or 2)
- Install cookie-capture JavaScript (if using Method 2) or LeadSourcePro (Method 3)
- Add PHP cookie-reading filters (if using Method 2)
- Update notification email templates to include attribution merge tags
- Test the full flow in an incognito window — navigate from a UTM-tagged URL to your form page and confirm the data appears in the form entry
- If using hidden fields with UTM parameters, check that your caching plugin excludes the form page (Method 1) or that you’re reading from cookies (Method 2)
Frequently Asked Questions
Why are my Gravity Forms hidden fields empty even though the URL has UTM parameters?
The most common cause is page caching. Gravity Forms’ dynamic population uses PHP, which doesn’t execute on cached pages. Either exclude the form page from your cache or switch to the cookie-based approach (Method 2 or 3), which uses client-side JavaScript and is unaffected by caching.
Do I need to add hidden fields to every Gravity Form on my site?
With Methods 1 and 2, yes — every form that should capture attribution data needs its own set of hidden fields. With LeadSourcePro (Method 3), no — the plugin attaches attribution data to all form entries automatically, with no hidden fields required.
How do I capture UTM data in Gravity Forms multi-page forms?
Multi-page Gravity Forms use JavaScript to navigate between pages without changing the URL, so hidden fields populated on page 1 carry through to submission. However, the underlying issue is the same: if the visitor navigated to the form page from a different landing page, the UTM parameters are already gone from the URL. The cookie-based approach (Method 2 or 3) handles this reliably.
Can I track organic search leads (no UTM parameters) in Gravity Forms?
Yes — that’s what the referrer URL captures. When someone arrives from an organic Google search, the referrer will show https://www.google.com/. Combined with the landing page URL, you can identify organic traffic even without UTM tags. For a complete explanation of tracking lead sources beyond UTM parameters, see our guide on tracking lead sources in WordPress forms.
What happens if a visitor returns to my site days later and submits a form?
If you’re using the cookie approach, the attribution data persists for 90 days (the cookie expiry set in the JavaScript snippet). If the visitor returns within that window and submits a form, the original UTM parameters and click IDs will still be captured. If they return via a new campaign URL, the script overwrites the cookies with the new campaign data.
Stop losing lead source data from Gravity Forms
LeadSourcePro captures UTM parameters, click IDs, referrer URL, and landing page automatically on every Gravity Forms submission — no hidden fields, no code, no configuration. Install LeadSourcePro and see where your leads are really coming from.

Leave a Reply