Contact Form 7 is the most popular WordPress form plugin — over five million active installs. If you’re using it for lead generation, you’ve probably noticed the same problem everyone else has: form submissions arrive with a name, email, and message, but zero information about where the lead came from.
You’re running Google Ads, Facebook campaigns, LinkedIn promotions — spending real money to drive traffic. But when a lead fills out your CF7 form, the submission email tells you nothing about which ad, campaign, or channel sent them to your site. Every lead looks the same: “Direct / None.”
This guide fixes that. You’ll learn how to capture UTM parameters, click IDs (gclid, fbclid, msclkid), and the referrer URL in Contact Form 7 — so every form submission carries complete attribution data. We’ll cover the native CF7 method, explain exactly why it breaks, and show you the approaches that actually work.
What Data Should Contact Form 7 Capture?
Before configuring anything, it helps to understand the four types of attribution data that a form submission should include:
| 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-sale |
| 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 tell you 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.
The challenge with Contact Form 7 is that it captures none of this by default. You have to set it up yourself.
Method 1: CF7 Hidden Fields with default:get (the Native Approach)
Contact Form 7 supports hidden fields natively. You can add them directly in the form editor and use the default:get option to pull values from the URL’s query string.
Here’s the basic setup. In your CF7 form editor, add hidden fields below your visible fields and above the submit button:
[hidden utm_source default:get]
[hidden utm_medium default:get]
[hidden utm_campaign default:get]
[hidden utm_term default:get]
[hidden utm_content default:get]
[hidden gclid default:get]
[hidden fbclid default:get]
Then in the Mail tab, add the corresponding mail tags to your email template so the values are included in notification emails:
--- Attribution Data ---
Source: [utm_source]
Medium: [utm_medium]
Campaign: [utm_campaign]
Term: [utm_term]
Content: [utm_content]
GCLID: [gclid]
FBCLID: [fbclid]
This works when the form is on the same page the visitor landed on — and the URL still contains the UTM parameters and click IDs. For example, if someone clicks your Google Ad and lands directly on /contact/?utm_source=google&utm_medium=cpc&gclid=abc123, the hidden fields will capture those values.
Why CF7 Hidden Fields Stop Working (And Why Your UTM Data Shows Up Blank)
The default:get method is simple, but it breaks in almost every real-world scenario. If your CF7 hidden fields are passing blank UTM values, one of these five problems is the cause.
1. The Visitor Navigates Away from the Landing Page
This is the most common reason — and it’s a fundamental limitation, not a bug. UTM parameters disappear from the URL the moment a visitor clicks any link on your site. If they land on your homepage from a Google Ad and then navigate to your contact page, the URL changes to /contact/ — no UTM parameters, no gclid, nothing. The default:get fields have nothing to read.
This single issue makes the native method unreliable for any site where the form isn’t on the landing page. And for most lead generation sites, the form is on a dedicated contact or quote request page — not the ad landing page.
2. Caching Plugins Serve a Stale Page
Page caching plugins (WP Rocket, LiteSpeed Cache, W3 Total Cache) can serve a cached version of the page where the hidden field values were set during the cache build — not from the current visitor’s URL. This means the hidden fields may contain empty values or values from a previous request. Clear your cache after installing any UTM tracking setup and test with caching enabled.
3. The Field Name Doesn’t Match the URL Parameter
The default:get option requires the hidden field name to exactly match the URL parameter name. If your URL has utm_source=google, your field must be named utm_source. A mismatch like utmsource or source will fail silently — the field just stays empty.
4. Mail Tags Are Missing from the Email Template
Even when hidden fields capture data correctly, you won’t see it unless you add the corresponding mail tags to your email template. Adding [hidden utm_source default:get] to the form without adding [utm_source] to the Mail tab means the data is captured but never sent in the notification email. This is a common oversight that makes it look like tracking isn’t working.
5. The Form Is in a Popup or Modal
If your CF7 form is loaded inside a popup or modal plugin, the form markup may be injected via JavaScript after the page renders. In some configurations, default:get fields aren’t populated because the form wasn’t part of the initial page load. This is a known issue reported in WordPress.org support threads — dynamic hidden fields in CF7 popups frequently return blank values.
Method 2: JavaScript and Cookies (The Manual Fix)
The fix for the page-navigation problem is to store UTM parameters and click IDs in browser cookies when the visitor first arrives, then read those cookies when the form is submitted — regardless of which page the form is on.
This is the approach we’ve detailed across the article series on populating hidden form fields with UTM parameters. Here’s how it applies specifically to Contact Form 7.
Step 1: Capture and Store Parameters on Page Load
Add a JavaScript snippet that runs on every page load. It checks the URL for UTM parameters and click IDs, and if found, stores them in first-party cookies with a defined expiry (typically 30-90 days).
(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);
params.forEach(function(param) {
var value = search.get(param);
if (value) {
document.cookie = param + '=' + encodeURIComponent(value)
+ ';max-age=2592000;path=/;SameSite=Lax';
}
});
// Store referrer on first visit only
if (!getCookie('original_referrer') && document.referrer
&& !document.referrer.includes(window.location.hostname)) {
document.cookie = 'original_referrer='
+ encodeURIComponent(document.referrer)
+ ';max-age=2592000;path=/;SameSite=Lax';
}
// Store landing page on first visit only
if (!getCookie('landing_page')) {
document.cookie = 'landing_page='
+ encodeURIComponent(window.location.href)
+ ';max-age=2592000;path=/;SameSite=Lax';
}
function getCookie(name) {
var match = document.cookie.match(
new RegExp('(^| )' + name + '=([^;]+)')
);
return match ? decodeURIComponent(match[2]) : '';
}
})();
Step 2: Add Hidden Fields to Your CF7 Form
In your CF7 form editor, add hidden fields with unique IDs. Don’t use default:get this time — we’ll populate them from cookies via JavaScript:
[hidden utm_source id:cf7-utm-source]
[hidden utm_medium id:cf7-utm-medium]
[hidden utm_campaign id:cf7-utm-campaign]
[hidden utm_term id:cf7-utm-term]
[hidden utm_content id:cf7-utm-content]
[hidden gclid id:cf7-gclid]
[hidden fbclid id:cf7-fbclid]
[hidden referrer_url id:cf7-referrer]
[hidden landing_page id:cf7-landing-page]
Step 3: Populate Hidden Fields from Cookies
Add a second script that reads the cookie values and writes them into the hidden fields before form submission:
document.addEventListener('DOMContentLoaded', function() {
function getCookie(name) {
var match = document.cookie.match(
new RegExp('(^| )' + name + '=([^;]+)')
);
return match ? decodeURIComponent(match[2]) : '';
}
var fields = {
'cf7-utm-source': 'utm_source',
'cf7-utm-medium': 'utm_medium',
'cf7-utm-campaign': 'utm_campaign',
'cf7-utm-term': 'utm_term',
'cf7-utm-content': 'utm_content',
'cf7-gclid': 'gclid',
'cf7-fbclid': 'fbclid',
'cf7-referrer': 'original_referrer',
'cf7-landing-page': 'landing_page'
};
for (var fieldId in fields) {
var el = document.getElementById(fieldId);
if (el) {
el.value = getCookie(fields[fieldId]);
}
}
});
Step 4: Update the CF7 Mail Template
In the Mail tab, add the mail tags for every hidden field:
--- Lead Attribution ---
UTM Source: [utm_source]
UTM Medium: [utm_medium]
UTM Campaign: [utm_campaign]
UTM Term: [utm_term]
UTM Content: [utm_content]
Google Click ID: [gclid]
Facebook Click ID: [fbclid]
Referrer: [referrer_url]
Landing Page: [landing_page]
This approach works. It persists attribution data across page navigation and captures it when the form is submitted on any page. But it comes with real costs:
- You maintain two JavaScript snippets that need to run on every page. Any conflict with a caching plugin, minification tool, or theme update can silently break tracking.
- You must add 7-9 hidden fields to every CF7 form on your site — and remember to update the mail template for each one.
- No automatic source detection. If a visitor arrives from organic Google search (no UTM parameters, no click IDs), all your hidden fields will be empty. The JavaScript captures what’s in the URL, but organic search traffic doesn’t carry UTM parameters — so the lead appears as “unknown.”
- No dashboard or reporting. The data exists only in notification emails. To analyse lead sources across campaigns, you’d need to build your own spreadsheet or pipe data to a CRM manually.
Tracking Click IDs: gclid, fbclid, msclkid, and More
UTM parameters tell you which campaign sent a visitor. Click IDs go further — they identify the specific click, which lets you send conversion data back to the ad platform for offline conversion tracking and audience optimisation.
Each major ad platform has its own click identifier:
| Ad Platform | Click ID Parameter | How It’s Added |
|---|---|---|
| Google Ads | gclid | Auto-tagging (enabled by default) |
| Meta (Facebook/Instagram) | fbclid | Automatic on all clicks from Meta |
| Microsoft Ads (Bing) | msclkid | Auto-tagging (enable in account settings) |
| LinkedIn Ads | li_fat_id | LinkedIn Insight Tag |
| TikTok Ads | ttclid | Auto-tagging (enabled by default) |
In Contact Form 7, the process for capturing any click ID is identical: add a hidden field, store the value in a cookie on arrival, and populate the field before submission. We’ve covered each click ID in depth — see the dedicated guides for gclid tracking, fbclid tracking, and Microsoft, LinkedIn, and TikTok click IDs.
The key challenge is the same across all click IDs: they disappear from the URL on internal navigation. A visitor clicks your Google Ad, lands on your homepage with gclid=abc123 in the URL, clicks through to your services page, then fills out your CF7 contact form. By the time they submit, the gclid is long gone from the URL. Without cookie-based persistence, the hidden field will be empty.
Capturing the Referrer URL in Contact Form 7
Not all traffic arrives with UTM parameters or click IDs. Someone who finds your site through an organic Google search, clicks a link from a blog post, or visits from a social media profile won’t have any UTM tags in their URL. For these visitors, the HTTP referrer is your only attribution signal.
The referrer is the URL of the page the visitor was on before they arrived at your site. If someone searches “web designer Wellington” on Google and clicks your organic listing, the referrer will be https://www.google.com/. If they click a link on another blog that mentions your business, the referrer will be that blog’s URL.
Contact Form 7 has a built-in special mail tag [_url] that captures the URL of the page where the form was submitted — but that’s not the referrer. CF7 doesn’t capture the referrer natively.
To capture the referrer, you have three options:
- A dedicated plugin like “Referrer Input for Contact Form 7” adds a new field type that captures the HTTP referer via JavaScript (cache-compatible).
- The Dynamic Text Extension plugin adds a
dynamic_hiddentag that can use a shortcode to pull the referrer URL. - Custom JavaScript (shown in Method 2 above) stores
document.referrerin a cookie on first visit and populates a hidden field at submission time.
There’s an important limitation to understand: the referrer only tells you the last page before your site, not the original source. If a visitor arrives from Google, browses three pages on your site, and then submits a form, document.referrer on the form page will show your own site’s URL — not Google. That’s why the cookie approach (storing the referrer on first arrival only) is essential for accurate attribution.
Even with cookies, the referrer has limitations. Some browsers and privacy extensions strip the referrer entirely. HTTPS-to-HTTP transitions may not send it. And direct traffic (typing a URL, bookmarks, some email clients) has no referrer at all.
The referrer is most useful as a fallback — it fills in the picture when UTM parameters and click IDs aren’t available, such as organic search traffic and referral visits from other websites.
Which Ad Brought This Lead? Connecting Campaign Data to CF7 Submissions
With UTM parameters, click IDs, and the referrer all captured, you can now trace every CF7 submission back to its source. Here’s what the data tells you for each traffic type:
Google Ads lead: utm_source=google, utm_medium=cpc, utm_campaign=[your campaign name], gclid=[unique click ID]. You know the exact campaign and can send the gclid back to Google for offline conversion tracking.
Facebook Ads lead: utm_source=facebook, utm_medium=paid-social, utm_campaign=[your campaign name], fbclid=[unique click ID]. You know the campaign and can feed the conversion back to Meta via the Conversions API.
Organic Google search lead: No UTM parameters, no click IDs. The referrer shows https://www.google.com/. The landing page shows which page they found in search results. You can’t see the exact search query (Google hides it), but you know the channel and entry point.
LinkedIn Ads lead: utm_source=linkedin, utm_medium=cpc, utm_campaign=[your campaign name], li_fat_id=[click ID]. Full campaign attribution plus a click ID for conversion tracking.
Direct traffic lead: No UTM parameters, no click IDs, no referrer. The landing page is the only data point. This visitor typed your URL directly, used a bookmark, or came from a source that strips referrer data.
The manual JavaScript/cookie method captures all of this — but it requires you to maintain custom code, configure every form individually, and piece together the attribution data from notification emails. For a site with one form, that’s manageable. For a site with multiple forms across multiple pages, it becomes a maintenance burden.
Method 3: Automatic Tracking with LeadSourcePro
LeadSourcePro is a WordPress plugin built specifically to solve the attribution problem for Contact Form 7 and eight other form plugins. It replaces all the custom JavaScript, cookie management, and hidden field configuration with a single plugin that works automatically.
Here’s how it works with Contact Form 7:
- Install and activate. LeadSourcePro adds a lightweight script to your site that captures UTM parameters, click IDs (gclid, fbclid, msclkid, li_fat_id, ttclid), the referrer URL, and the landing page on every visit. The data is stored in a first-party cookie with a configurable conversion window.
- No form changes required. LeadSourcePro hooks directly into Contact Form 7’s submission process. You don’t need to add hidden fields, modify your form editor, or update mail templates. When a visitor submits any CF7 form on your site, the attribution data is automatically attached to the submission.
- Automatic source detection. Unlike the manual method where organic and referral traffic produce empty fields, LeadSourcePro identifies the traffic source automatically. It reads the referrer, recognises it as Google, Bing, or another search engine, and labels the lead as “Organic Search.” Social media referrers are labelled “Organic Social.” Sites without a referrer are labelled “Direct.” Paid traffic with UTM parameters is labelled with the ad platform name — Google Ads, Meta Ads, Microsoft Ads, LinkedIn Ads, or TikTok Ads.
- A searchable dashboard. Every submission appears in a WordPress dashboard with the full attribution trail — traffic source, UTM parameters, click IDs, landing page, referrer, and form data. You can search, sort, filter by source, and export to CSV.
The key difference from the manual method: LeadSourcePro identifies traffic sources that don’t have UTM parameters or click IDs. When a visitor arrives from organic Google search, the plugin reads the referrer, recognises it as a search engine, and labels the lead “Organic Search” — even though there are no UTM parameters in the URL. The manual approach can’t do this without additional source-detection logic.
Side-by-Side: Which Approach Is Right for Your Site?
| Feature | default:get (Native) | JavaScript + Cookies | LeadSourcePro |
|---|---|---|---|
| Captures UTM parameters | Only on the landing page | Across all pages (via cookies) | Across all pages (automatic) |
| Captures click IDs (gclid, fbclid, etc.) | Only on the landing page | Yes, with manual configuration | Yes, automatically |
| Captures referrer URL | No | Yes, with custom code | Yes, automatically |
| Detects organic / direct / social traffic | No | No | Yes — automatic source labelling |
| Persists across page navigation | No | Yes | Yes |
| Works with cached pages | Unreliable | Yes (client-side) | Yes |
| Works in popups / modals | Unreliable | Depends on implementation | Yes |
| Requires form editor changes | Yes — add hidden fields + mail tags | Yes — add hidden fields + mail tags | No changes needed |
| Requires custom JavaScript | No | Yes — two scripts to maintain | No |
| Dashboard / reporting | No — email only | No — email only | Yes — searchable WordPress dashboard |
| Supported form plugins | CF7 only | CF7 only (per implementation) | CF7 + 8 others (Gravity Forms, WPForms, Ninja Forms, Formidable, Fluent Forms, Elementor Pro, Forminator, Jetpack) |
Quick Setup Checklist
Whichever method you choose, make sure these fundamentals are in place:
- Tag all your campaign URLs with UTM parameters. Google Ads, Facebook Ads, LinkedIn Ads, email campaigns, social posts — any link you control should carry utm_source, utm_medium, and utm_campaign at minimum. Without UTM tags on the inbound link, there’s nothing for any tracking method to capture.
- Enable auto-tagging on your ad platforms. Google Ads appends gclid automatically (it’s on by default). Microsoft Ads requires you to enable the msclkid setting manually. Meta appends fbclid automatically on all clicks.
- Test with a real campaign URL. Append UTM parameters to your site URL (e.g.,
yoursite.com/contact/?utm_source=test&utm_medium=test&utm_campaign=test&gclid=test123), navigate to a different page, come back to the form, and submit it. Check whether the attribution data appears in the notification email or the dashboard. - Check your caching setup. If you use a page caching plugin, clear the cache after any tracking changes and test again. Client-side JavaScript (Methods 2 and 3) is generally cache-safe, but server-rendered hidden fields (Method 1) can be affected.
- Verify the mail template. For Methods 1 and 2, open the CF7 Mail tab and confirm every hidden field has a corresponding mail tag. A missing tag means the data is captured but never sent.
Common Questions
Does this work with Contact Form 7’s Flamingo addon?
Yes. Flamingo stores all submitted data including hidden fields. If your hidden fields capture UTM data (Method 1 or 2), Flamingo will record those values alongside the visible fields. LeadSourcePro has its own storage, so Flamingo is not required but remains compatible.
What if I use multiple forms on one page?
The cookie-based approaches (Methods 2 and 3) work regardless of how many forms are on a page. Each form reads from the same cookies when it’s submitted. For the native default:get method, each form needs its own set of hidden fields — but the URL parameters are shared, so they’ll all capture the same values.
Will this affect page speed or Core Web Vitals?
The JavaScript in Method 2 is lightweight — a few hundred bytes of vanilla JavaScript that runs after page load. LeadSourcePro’s script is similarly small and non-blocking. Neither approach adds render-blocking resources or measurably affects Largest Contentful Paint, First Input Delay, or Cumulative Layout Shift.
Is storing UTM data in cookies GDPR-compliant?
UTM parameters and click IDs are campaign identifiers, not personal data. First-party cookies that store marketing attribution data are generally categorised as “analytics” or “marketing” cookies under GDPR frameworks. That said, you should declare them in your cookie policy and — depending on your consent approach — ensure they are covered by your cookie consent banner. LeadSourcePro uses first-party cookies only and stores no personal data in the cookie itself.
Next Steps
If you’re using Contact Form 7 for lead generation and spending money on ads, you need attribution data attached to every submission. The native default:get method is a starting point, but it breaks the moment a visitor navigates away from the landing page — which is most of the time.
The JavaScript/cookie approach fixes the persistence problem but requires manual setup, ongoing maintenance, and can’t identify organic or direct traffic sources.
LeadSourcePro handles everything automatically — UTM parameters, click IDs, referrer, landing page, and automatic source detection — with no form changes, no custom code, and a built-in dashboard for every form plugin on your site.
For deeper dives into specific topics covered in this guide, see the related articles in this series:
- Why UTM Parameters Disappear in WordPress (and How to Fix It)
- How to Populate Hidden Form Fields with UTM Parameters
- GCLID Tracking in WordPress: Capture Google Ads Click IDs
- fbclid Tracking in WordPress: Capture Facebook Click IDs
- Track Microsoft, LinkedIn & TikTok Click IDs in WordPress
- How to Track Lead Sources in WordPress Forms (Complete Guide)
Stop losing lead source data from your Contact Form 7 submissions.
LeadSourcePro captures UTM parameters, click IDs, referrer, and landing page automatically for every CF7 submission — no hidden fields, no custom code. See where every lead comes from in a searchable WordPress dashboard.

Leave a Reply