Documentation
How do I enable the plugin?
After purchasing Referral Source Tracking for Gravity Forms, install it on your WordPress website.
Step 1: Installation
Log in to your WordPress website and navigate to Plugins → Add Plugin → Upload Plugin → Install the zip file and activate it.
Step 2: Register the Plugin
On the left hand navigation, go to Forms → Settings → Referral Tracking.
Enter your license key and activate it.
Step 3: Enable the Feature
After activating your license, a General tab appears. Click it, tick Enable by Default (“Enable referral source tracking on all forms by default”), then click Save Changes.
Leaving that box unchecked keeps tracking off everywhere. You can instead enable it form by form under Form Settings → Form Options.
That’s it! With Enable by Default on, referral source tracking is active on any existing forms and any new ones you create.
Feature details
Sources it detects
We capture the referrer URL when one is available and store it on the entry. For common platforms we add a friendly label as well, so the source is easy to read.
A source is labeled Ads only when the visit carries the platform’s own ad click ID (gclid, msclkid, li_fat_id, ttclid, oppref and so on). A known platform arriving without one is labeled Organic. Facebook and Instagram are the exception: Meta adds fbclid to every click, so those read Ads when fbclid arrives with any UTM parameter.
Here’s the list of sources that are labeled when detected:
- Google: Google Ads, Google Organic. Gemini traffic tagged
utm_source=geminiis labeled Google Organic; there is no separate Gemini label. - Microsoft/Bing: Bing Ads, Bing Organic
- Facebook: Facebook Ads, Facebook Organic
- Instagram: Instagram Ads, Instagram Organic
- LinkedIn: LinkedIn Ads, LinkedIn Organic
- X (Twitter): X Organic
- Reddit: Reddit Ads, Reddit Organic
- TikTok: TikTok Ads, TikTok Organic
- Pinterest: Pinterest Ads, Pinterest Organic
- Snapchat: Snapchat Ads, Snapchat Organic
- YouTube: YouTube Organic. A YouTube ad click that carries
gclidis recorded as Google Ads unless the URL is also taggedutm_source=youtube, which records YouTube Ads. - Other Search Engines: Yahoo, DuckDuckGo, Yandex
- AI Assistants/LLMs: ChatGPT Ads, ChatGPT Organic, Perplexity, Copilot, Claude, Grok, DeepSeek
- Email Platforms (campaign tracking): Mailchimp, Constant Contact, Pardot (labeled
Salesforce), HubSpot - Direct and Unknown are used when appropriate.
- Custom sources can be defined under Custom Sources for partner, affiliate, and campaign traffic.
UTM parameters it captures
utm_sourceutm_mediumutm_campaignutm_termutm_contentutm_id
Click IDs captured
We capture every click ID below into the Click ID field, and each one attributes the visit to its platform unless the row says otherwise.
| Platform | Click IDs Captured |
|---|---|
| Google Ads | gclid, gbraid, wbraid |
| Google (other) | campaignid, gad_campaignid, gad_sourceCaptured and attributed to Google, but they don’t mark the visit as Ads on their own. On a real Google Ads click they arrive alongside gclid, which does. |
| Microsoft Ads (Bing) | msclkid |
| Meta (Facebook / Instagram) | fbclid |
| LinkedIn Ads | li_fat_id |
| Reddit Ads | rdt_cid, rd_ad |
| TikTok Ads | ttclid |
| Pinterest Ads | pin_cid |
| Snapchat Ads | snap_cid |
| ChatGPT Ads | oppref |
| Mailchimp | mc_cid, mc_eid |
| Constant Contact | cc_cid, cc_eid, cc_campaignid |
| Salesforce Pardot | pi_cid, pi_eid, pi_uid, pi_oid, pi_opt_in |
| HubSpot | _hsenc, _hssc, _hsmi, _hstc, _hsml |
| DoubleClick / DV360 | dclidCaptured into the Click ID field, but it doesn’t map to a DoubleClick source label. The visit reads as Unknown Ads unless something else identifies it. |
Custom sources
Built-in source detection already covers the major search engines, social platforms, AI assistants, and email marketing tools. Custom Sources let you add your own labeled rules on top. Use them for partner sites, affiliate referrals, named campaigns, branded shorteners, employee links, and anything else where the default “Referral” label or a raw utm_source value isn’t specific enough.

Find them under Forms → Settings → Referral Tracking in the Custom Sources section. Each row is one rule.
How a rule is evaluated
For every visit, the plugin checks your Custom Sources before built-in detection. The first rule that matches wins: the plugin sets the visitor’s source to that rule’s Label and skips built-in detection for that visit. If nothing matches, built-in detection runs as usual (Google, Facebook, Direct, etc.).
The fields, one by one
- Label – The text saved as the visit’s Source (e.g.
Partner: Acme,Email: Newsletter,Campaign: Spring Sale). This is exactly what shows up in the entry, in the{pb_ref_source}merge tag, in the Reports tab, and in any CRM mapping. Pick something you’ll recognize on a busy entries screen. - Match Field – Where to look:
- Referrer Host – the domain in the browser’s referrer (e.g. matches
acme.comwhen someone arrives fromhttps://www.acme.com/blog/post). - UTM Source / Medium / Campaign / Term / Content – the corresponding
?utm_*=parameter on the landing URL.
- Referrer Host – the domain in the browser’s referrer (e.g. matches
- Match Type – What to look for:
- Contains – the field value includes your Match Value anywhere inside it. Case-insensitive. Good for catching variations like
acme.com,blog.acme.com,partner.acme.comwith one rule. - Equals – the field value is exactly your Match Value (case-insensitive). Stricter, so use it when you need a precise match like
utm_sourceexactly equalsnewsletter.
- Contains – the field value includes your Match Value anywhere inside it. Case-insensitive. Good for catching variations like
- Match Value – The text to look for. No quotes, no asterisks, just the literal string.
- Priority – A number controlling order. Higher runs first, so where rules overlap the higher-priority one wins. Default is
10; bump to20or50for rules that must beat your defaults, drop to5for catch-alls.
Worked examples
Label a partner site by referrer
| Label | Match Field | Match Type | Match Value | Priority |
|---|---|---|---|---|
Partner: Acme | Referrer Host | Contains | acme.com | 20 |
Anyone arriving from any subdomain of acme.com is labeled Partner: Acme instead of the generic Referral.
Label a tagged newsletter campaign
| Label | Match Field | Match Type | Match Value | Priority |
|---|---|---|---|---|
Email: Newsletter | UTM Source | Equals | newsletter | 20 |
Use this when you control the URL on your end (e.g. links inside your weekly email send ?utm_source=newsletter).
Label a paid campaign by its UTM campaign name
| Label | Match Field | Match Type | Match Value | Priority |
|---|---|---|---|---|
Campaign: Spring Sale | UTM Campaign | Contains | spring-sale | 15 |
Catches ?utm_campaign=spring-sale-2026, ?utm_campaign=spring-sale-google-ads, and similar variants in one rule.
Override built-in Google detection for a specific affiliate
| Label | Match Field | Match Type | Match Value | Priority |
|---|---|---|---|---|
Affiliate: Acme via Google Ads | UTM Source | Equals | acme-gads | 50 |
A high priority makes sure this rule wins over the built-in utm_source=google → Google Ads labeling whenever the tagged source comes through.
“Append Organic/Ads Labels” with custom sources
Built-in sources always show as Google Ads, Facebook Organic, etc. The Append Organic/Ads Labels (Custom Sources) checkbox (also under Forms → Settings → Referral Tracking) controls whether your custom labels get that same suffix.
- Checked (default) – a custom rule labeled
Partner: AcmebecomesPartner: Acme Organicon referral traffic andPartner: Acme Adsif the visit carries a paid click ID such as gclid. - Unchecked – your custom labels render exactly as you typed them, and the plugin adds no suffix.
Pick whichever fits your reporting. Most teams want the suffix so they can compare paid vs organic partner traffic, but if you’re using the Label itself to carry the full identity, turn it off.
Adding rules programmatically
If you’re building an add-on or want rules under version control, the pb_gforms_referral_tracking_custom_sources filter accepts the same shape as the admin UI and merges with it. The plugin sorts rules from both places together by priority before the front-end evaluates them.
Mirror fields
Our tracking fields are added to your form dynamically at render time. They aren’t part of the form’s saved field list. That keeps your forms clean, but some CRM, email marketing, and webhook add-ons build their field-mapping dropdowns only from saved fields, so they can’t “see” our dynamic fields.
Mirror fields fix that. Under Forms → [your form] → Settings → Form Options, click Add mirror fields and the plugin adds a parallel set of editor-visible Hidden fields to your form. The original tracking fields stay the source of truth; the plugin copies their captured values into the mirror fields when the entry is created, so your add-on can map them from its normal field dropdown. The Mirror fields block only appears once that form’s own referral tracking toggle is on.
If your add-on supports a “Custom Value” mapping option, you don’t need mirror fields at all. Just map our merge tags directly (for example {pb_ref_source}, {pb_ref_utm_source}, {pb_ref_clid}).
Managing mirror fields:
- Add mirror fields – creates the editor-visible set.
- Add N missing mirror fields – appears whenever a form has some but not all of the current mirror fields, and names the count. That happens if someone deletes fields by hand, and also after you enable last-touch attribution, which adds a new set of definitions. The plugin leaves surviving field IDs untouched, so saved mappings keep working.
- Remove 2 duplicate mirror fields – appears only when duplicates exist, and names the count. Keeps the first occurrence of each.
- Remove mirror fields – deletes the set (with a confirmation). Values already saved to past entries stay in the database, but add-ons will no longer see them via field-ID lookups.
When last-touch attribution is enabled, mirror fields can include the last-touch set too. Forms that already had the first-touch set won’t pick them up on their own: use Add N missing mirror fields on each one to top it up.
Reports
Find Reports under Forms → Settings → Referral Tracking → Reports. The tab visualizes every tracked entry that landed during the date range you pick, broken down by source, UTM dimension, and referrer. Entries submitted before the plugin was active, entries on forms with tracking off, and trashed or spam entries aren’t counted, so these totals can sit below your Gravity Forms entry count. Ranges cover whole days and end at the last complete UTC midnight, so period comparisons stay like for like. Depending on how far your site’s timezone sits from UTC, that cutoff can fall part-way through your local day.

Charts at a glance
- Source Breakdown – donut chart showing the share of submissions per labeled source (Google Organic, Facebook Ads, your Custom Sources, Direct, etc.).
- Entries Over Time – line chart of total entries per bucket. Hover a point and the tooltip splits that total by source. Longer windows (90 and 365 days) bucket by month so the axis stays readable; on the 30-day window the chart draws every 7th date label to keep it from crowding.
- Top UTM Source / Medium / Campaign – horizontal bar charts of the values with the most entries in each UTM dimension.
- Top Referrers – horizontal bar chart of the referring domains driving the most submissions. The plugin stores direct traffic with the referrer
Direct, so it appears here as its own bar rather than a domain.
Filters
- Form – scope to a single form, or leave on “All forms” for a site-wide view.
- Date range – preset windows (Last 7, 30, 90, and 365 days).
- Compare to previous period – shows the period total with its percent change vs. the equivalent prior window (last-7 vs. the prior 7, last-30 vs. the prior 30, etc.), and overlays that prior period as a dashed line on the time chart. The UTM and referrer bar charts are not compared.
- Hide unattributed – hides the Not Set and Unknown buckets so you can focus on attributed sources. Direct stays.
The plugin remembers your date range, compare-period, and hide-unattributed choices per user, so you don’t have to set them again on your next visit.
Performance and caching
The plugin computes reports from your Gravity Forms entries and caches the result, so repeat loads are fast. New entries invalidate that cache automatically, debounced behind a 60-second lock so high-volume forms don’t overload it. Developers can tune the debounce window (or disable it entirely) with the pb_gforms_rt_invalidate_debounce filter. See Hooks below.
Email digest
If you’d rather get attribution highlights delivered than open the dashboard, enable the email digest under Forms → Settings → Referral Tracking → Email Reports. The day and hour you pick are evaluated in your site’s timezone, but the reported period itself is measured in whole UTC days, ending at the last complete UTC midnight before the email sends. On sites far from UTC the covered range is offset from your local days.

Cadence and timing
- Weekly – pick the day of the week (Sunday through Saturday) and the hour the email sends.
- Monthly – pick the day of the month (capped at the 28th so the email always lands, even in February) and the hour.
- The send schedule follows your site’s timezone (WordPress → Settings → General), and the settings page shows the current one right next to the Hour selector. The reporting window itself is still measured in UTC days.
Recipients
One email address per line. Leave the field blank and the digest falls back to the site admin email at send time. That helps when the admin email might change later and you want the digest to follow it automatically.
The Send a test email to me now button delivers the same digest body using your saved settings. Two things differ from a scheduled send: the subject is prefixed [TEST], and it ignores Skip empty digests, so a test over a quiet period still arrives where the real digest would have stayed silent. The button auto-disables while there are unsaved changes; save first, then test.
Content options
- Skip empty digests – don’t send the email at all if the digest’s total for the period is zero. On a sparse form, that saves you an empty digest on quiet weeks. With Hide unattributed also on, that total ignores Not Set and Unknown entries, so a period holding only unattributed entries counts as empty and is skipped.
- Compare to previous period – show the percent change vs. the prior equivalent window at the top of the email (last week vs. the week before, last month vs. the month before, etc.).
- Hide unattributed – omit Not Set and Unknown values from the email tables so the focus stays on attributed sources.
Merge tags
{pb_ref_source} – value stored in the hidden “Source” field (defaulting to “Unknown” when the visit couldn’t be classified).
{pb_ref_params} – full string of captured referral parameters (UTMs and other query vars we keep together).
{pb_ref_referrer} – the referring URL for the visit. This is the effective referrer, not the raw browser value. When a click ID or a recognized utm_source identifies the platform, the plugin stores the canonical platform URL instead. As a result, a gclid visit records https://www.google.com/ even when the click came from an email. Same-domain and no-referrer visits record Direct. No merge tag exposes the untouched browser referrer.
{pb_ref_utm_id} – utm_id.
{pb_ref_utm_source} – utm_source.
{pb_ref_utm_medium} – utm_medium.
{pb_ref_utm_campaign} – utm_campaign.
{pb_ref_utm_term} – utm_term.
{pb_ref_utm_content} – utm_content.
{pb_ref_clid} – first detected click ID for the visit (gclid, fbclid, msclkid, and other platform click IDs).
{pb_ref_custom_source} – your own label for the visit, written by the pb_gforms_referral_tracking_source_label filter (see Hooks). The tag only exists when that filter has a callback attached. The plugin stores the detected Source separately and never changes it.
Last-touch merge tags
When last-touch attribution is enabled, the plugin adds a parallel set:
{pb_ref_last_source}{pb_ref_last_referrer}{pb_ref_last_params}{pb_ref_last_clid}{pb_ref_last_utm_source}{pb_ref_last_utm_medium}{pb_ref_last_utm_campaign}{pb_ref_last_utm_term}{pb_ref_last_utm_content}{pb_ref_last_utm_id}{pb_ref_last_custom_source}
Each mirrors its first-touch equivalent but stores the most recent source before submission. {pb_ref_last_custom_source} also needs the pb_gforms_referral_tracking_source_label filter, the same as its first-touch counterpart.
Sending data to Google Analytics
Referral Source Tracking never contacts Google on its own. Everything it captures stays on your Gravity Forms entry. If you turn the GA4 setting on, your own Google tag sends the event.
Since 1.6.0 you can opt in to a GA4 event. Turn on GA4 / Tag Manager under Forms → Settings → Referral Tracking → General. On confirmation the plugin sends a custom event named pb_referral_submit (rename it in the same setting) with the source, referrer, click ID, and UTM parameters, plus last-touch values when last-touch is on. A failed validation does not send. Redirect and page thank-you confirmations need 1.7.1.
Check GA4 Realtime or DebugView for the event. You do not need a Tag Manager trigger. Your own Google tag does the sending; the plugin never contacts Google.
Optional: you can also pass merge tags on a Redirect confirmation query string (below) if you already convert from campaign parameters on the thank-you URL. That is separate from the custom event.
What the event carries
Parameter keys match the merge tag names. Empty values are left out of the payload entirely, and the event fires at most once per pageview.
| Parameter | Value |
|---|---|
pb_ref_source | Labelled source, e.g. Google Ads |
pb_ref_referrer | Effective referrer URL |
pb_ref_clid | First detected click ID |
pb_ref_params | Full captured parameter string |
pb_ref_utm_source, _medium, _campaign, _term, _content, _id | The six UTM values |
pb_ref_last_* | The parallel last-touch set, only when last-touch attribution is on |
pb_ref_form_id | The Gravity Forms form ID. Only present on AJAX confirmations, where the ID is known |
Optional: pass values on the thank-you URL
- Open your form’s confirmations under Forms → [your form] → Settings → Confirmations, then edit (or add) a Redirect confirmation.
- In the Redirect URL field, enter your thank-you page URL followed by a query string built from the tracking merge tags:
https://yoursite.com/thank-you/?gclid={pb_ref_clid}&utm_source={pb_ref_utm_source}&utm_medium={pb_ref_utm_medium}&utm_campaign={pb_ref_utm_campaign}&utm_term={pb_ref_utm_term}&utm_content={pb_ref_utm_content}Gravity Forms fills in and URL-encodes each value at submission time, so a visitor who arrived from a Google Ads click lands on a URL like:
https://yoursite.com/thank-you/?gclid=EAIaIQ...&utm_source=google&utm_medium=cpc&utm_campaign=spring-saleYour GA4 or Google Tag Manager setup on the thank-you page then reads those parameters the same way it handles any campaign URL, firing your conversion or lead event with the captured source, campaign, and click ID attached. Values that weren’t captured for a given visit come through empty.
You can use any of the tracking merge tags here. See Merge tags for the full list. (If you prefer, the Pass Field Data via Query String option on the same Redirect confirmation accepts these same merge tags.)
Why use merge tags instead of your own hidden fields
If you’re already passing campaign data to your thank-you page from your own hidden fields, point the query string at our merge tags instead. Both the value saved on the entry and the value sent to GA4 then come from the same captured source, so the two can’t drift apart. The entry and GA4 always show the same campaign. It also means one less set of fields to maintain.
A note on click IDs
{pb_ref_clid} holds the first click ID detected on the visit, whichever platform it came from: gclid for Google, but also msclkid (Microsoft), fbclid (Meta), and others. If you’re mapping it specifically to a gclid= parameter for Google Ads, a non-Google visit would place its click ID in that slot. If you only want the click ID included on Google Ads visits, add conditional logic to the confirmation so the gclid= parameter is sent only when the Source is Google Ads.
Verifying it works
You can confirm the whole chain in four steps:
- Add test parameters to any landing page URL (for example
?gclid=TEST123&utm_source=google&utm_medium=cpc), then submit the form. - On the thank-you page, check the address bar: your values should be present in the URL.
- Open your browser’s developer tools, go to the Network tab, and filter for
collect. The request to Google should include yourgclidandutmvalues. - Confirm receipt in GA4’s DebugView or Realtime report.
Test in a private or logged-out window. While you’re logged in as an administrator the plugin deliberately runs in session-only mode, writing cookies with no expiry, so the attribution window can’t be reproduced from an admin session.
Those four steps check the optional query-string method. For the built-in custom event, submit the form, then on the confirmation or thank-you page open DevTools → Network, filter for g/collect, and look for en=pb_referral_submit (or your event name). Or use GA4 DebugView. If the event is in the Network tab but not in GA4, the gap is your Google tag. If it is not in the Network tab, the plugin did not fire.
Sending the event to GA4
Since 1.6.0 you can send the source already sitting on the Gravity Forms entry into GA4 as a custom event. It is off by default. Your own Google tag does the sending – the plugin never contacts Google itself. Check GA4 Realtime or DebugView for the event. You do not need a Tag Manager trigger.
Go to Forms → Settings → Referral Tracking → General. Tick Send captured parameters to GA4 as a custom event on form confirmation. Leave the event name as pb_referral_submit unless you have a reason to change it, then click Save Changes.

Translations
This plugin is translation-ready and includes bundled translations for:
- Arabic (
ar) - Bengali (
bn_BD) - Filipino (
fil) - German (
de_DE) - Spanish (
es_ES) - Spanish (
es_MX) - French (
fr_FR) - Hindi (
hi_IN) - Indonesian (
id_ID) - Italian (
it_IT) - Japanese (
ja) - Portuguese (
pt_BR) - Russian (
ru_RU) - Urdu (
ur) - Chinese Simplified (
zh_CN) - Chinese Traditional (
zh_HK)
Default language: English (en_US)
If your language isn’t listed under Translations above, you can still translate the plugin yourself. It’s translation-ready. Use the free Loco Translate plugin to create a translation for your site’s language/locale. New to Loco Translate? Here’s a beginner-friendly tutorial.
FAQs
Can I export the data?
Yes. The tracking values are saved on each Gravity Forms entry, so they show up in entry exports.
What exactly does the plugin capture?
We capture common attribution fields and store them on the Gravity Forms entry. That includes UTM parameters (source, medium, campaign, term, content), Click IDs (gclid, msclkid, gbraid/wbraid, etc.), the original referrer URL, and related landing-page context, so you can see where each lead came from.
Can I add custom sources?
Yes. Add rules under Forms → Settings → Referral Tracking → Custom Sources to label partner sites, affiliate traffic, branded campaigns, and similar visits by name. Each rule matches on referrer host or a UTM parameter and applies a Label you choose. See the Custom sources section for the field-by-field guide and worked examples.
My CRM / email / webhook add-on doesn’t see the tracking fields in its mapping dropdown. What do I do?
Our tracking fields are added to your form dynamically at render time, not saved to the form’s field list, so add-ons that build their dropdown only from saved fields can’t see them. You have two options. If your add-on has a “Custom Value” mapping, map our merge tags directly ({pb_ref_source}, {pb_ref_utm_source}, {pb_ref_clid}, and so on). If it only supports a field dropdown, open Form Settings → Form Options → Mirror fields and click Add mirror fields. This adds editor-visible Hidden fields, and the plugin fills them in. See the Mirror fields section for the full walkthrough.
Where is the referral data saved?
In your WordPress database, inside your Gravity Forms entries. The plugin never sends it anywhere on its own. If you want the captured values in GA4, turn on the GA4 setting. The plugin stays the source of the data; your own Google tag does the sending.
Is this first-touch or last-touch attribution?
Both. By default it uses first-touch attribution, storing the original referrer and campaign parameters that first brought the visitor to your site (within the attribution window). There is a checkbox to ignore direct return visits so last-touch keeps the previous ad or referral. Returning-visit click IDs are stored on Click ID (Last touch) only. That gives you a parallel set of {pb_ref_last_*} merge tags, entry-list columns, and CSV export columns. The Reports tab includes a First/Last toggle that switches every chart between the two views.
How long does it remember a visitor’s attribution data?
The attribution window defaults to 7 days, and you can change it under Forms → Settings → Referral Tracking. If a visitor submits a form within that window of their first tracked visit, that entry carries the original first-touch attribution values.
Does it work with caching/CDNs?
Usually, yes. Tracking runs client-side, so most caching/CDN setups work fine. If you use aggressive script optimization (minify or deferral), tick Protect Scripts from Optimization under Forms → Settings → Referral Tracking → Advanced, then clear your cache. It tags the plugin’s scripts so they’re skipped, and adds them to the exclusion lists of WP Rocket, LiteSpeed Cache, SG Optimizer, Autoptimize, and Cloudflare Rocket Loader automatically. If you use Breeze or another minifier not in that list, exclude the two files below by hand and purge CDN cache for them after an update.
For any optimizer that setting doesn’t cover, exclude these two files by hand and test a submission:
/wp-content/plugins/pb-gforms-referral-tracking/assets/js/front-end.js/wp-content/plugins/pb-gforms-referral-tracking/assets/dist/js.cookie.min.js
Does it work with AJAX-enabled Gravity Forms?
Yes. It works with AJAX forms and standard (non-AJAX) submissions. Redirect and page thank-you confirmations on Gravity Forms 2.9+ need 1.7.1 for the GA4 event.
Can I track more than one form?
Yes. It works across all of your Gravity Forms. Each submission saves its own attribution values to that entry.
Does this replace GA4 / Google Ads conversion tracking?
No. It’s a data source, not a conversion pixel, and it never fires pixels or contacts Google itself. If you want the attribution inside GA4, the opt-in GA4 / Tag Manager setting sends it as a custom event through your own Google tag on form confirmation.
Does it collect personal data?
By default, it captures attribution data (UTMs, gclid, referrer URLs). It does not capture additional PII by default. Your form fields and any parameters included in URLs are controlled by your site and marketing setup.
Is it GDPR/CCPA compliant?
If you need consent before any attribution data is captured, enable the optional consent gate. It holds first-touch data in the browser until the visitor grants consent through your cookie banner (via a window flag, callback, or event), then applies it.
Does it work with a WordPress Multisite network?
TL;DR
- Unlimited license: enable Network Mode once; one key can manage every subsite’s settings + support.
- Network-activated: all subsites run referral tracking and receive updates right away.
- Limited plan / no subsite license: tracking is inactive on that subsite. No tracking fields, merge tags, or entry data are captured until a key is activated there, or Network Mode pushes one.
- Support follows the license: sites covered by the active key are eligible.
Yes, once each subsite is licensed and switched on. Network-activating installs the plugin everywhere and updates are handled network-wide, but a subsite needs its own activated license (or an Unlimited key pushed to it via Network Mode) before the plugin adds any tracking fields or captures any values. After that, switch on Enable by Default there, or enable tracking per form.
If you have an Unlimited license, you can enable Network Mode from the main site and push that single key to every subsite in one batch (with live progress). Those subsites inherit the license-managed settings and support automatically.
Settings reference
Everything below lives under Forms → Settings → Referral Tracking, on the tab named in each heading.
Data & Privacy
| Setting | Default | What it does |
|---|---|---|
| Cookieless Fallback Storage | Off | Off keeps attribution in cookies only. Persistent falls back to browser local storage for visitors who block cookies, discarding anything older than the attribution window. It only engages when cookies are unavailable, and with the consent gate on, the tracking script writes to it only after consent arrives. Browser storage carries the same GDPR and ePrivacy obligations as cookies, so cover it in your policy. |
| Remove Data on Uninstall | Off | Off leaves everything in place when the plugin is deleted. On purges plugin settings, per-form tracking configuration, license data, scheduled events, and per-user Reports preferences. Your Gravity Forms entries and the tracking values saved on them are never touched either way. |
Advanced
| Setting | Default | What it does |
|---|---|---|
| Protect Scripts from Optimization | Off | Marks the plugin’s front-end scripts so minify and defer tooling skips them, and registers them with the exclusion lists of WP Rocket, LiteSpeed Cache, SG Optimizer, Autoptimize, and Cloudflare Rocket Loader. Turn this on if referral data goes missing after enabling a caching plugin. |
Consent gate
There is no checkbox for this one. The consent gate is a developer opt-in: set consentRequired through the pb_gforms_referral_tracking_js_config filter. The tracking script holds first-touch data in sessionStorage until consent arrives, then promotes it to durable storage.
add_filter( 'pb_gforms_referral_tracking_js_config', function( $config ) {
$config['consentRequired'] = true;
return $config;
} );Signal consent from your cookie banner in whichever of these three ways suits it:
- Set
window.PBReferralTrackingConsent = true. - Dispatch the event:
window.dispatchEvent( new Event( 'pb-ref-tracking:consent-granted' ) ). - Assign a
consentGrantedcallback that returns true once consent is held.
Hooks
Actions
pb_gforms_referral_tracking_loaded
Fires once the plugin is fully initialized: classes loaded, hooks registered, API ready. This is the reliable boot point for add-ons or companion plugins that extend Referral Source Tracking.
Parameters:
$plugin(Plugin) – The plugin instance.
add_action( 'pb_gforms_referral_tracking_loaded', function( $plugin ) {
// Safe to interact with the plugin's classes and filters here.
// Example: register your own add-on after the plugin is ready.
if ( class_exists( 'MyReferralAddon' ) ) {
new MyReferralAddon( $plugin );
}
} );Filters
pb_gforms_referral_tracking_enabled
Override whether referral tracking is enabled for a specific form. Return true to force tracking on, false to force it off, regardless of the per-form toggle or global default.
Parameters:
$enabled(bool) – Whether tracking is currently enabled.$form_id(int) – The ID of the current form.$form(array|null) – The form meta array, or null if not available.
// Disable tracking on a specific form (e.g. an internal staff-only form).
add_filter( 'pb_gforms_referral_tracking_enabled', function( $enabled, $form_id, $form ) {
$excluded_form_ids = [ 12, 27 ];
if ( in_array( $form_id, $excluded_form_ids, true ) ) {
return false;
}
return $enabled;
}, 10, 3 );pb_gforms_referral_tracking_field_definitions
Filter the array of hidden tracking field definitions before the plugin injects them into the form. Use this to add, remove, or modify any individual tracking field.
Parameters:
$fields(array) – Array of field definition arrays.$form(array) – The current form meta.
// Remove the Referral Parameters field from all forms.
add_filter( 'pb_gforms_referral_tracking_field_definitions', function( $fields, $form ) {
return array_filter( $fields, function( $field ) {
return ! isset( $field['cssClass'] ) || $field['cssClass'] !== 'pb-ref-tracking-ref-params';
} );
}, 10, 2 );pb_gforms_referral_tracking_form
Filter the complete form array after the plugin has appended all its tracking fields. The final form object is yours to change before it is rendered.
Parameters:
$form(array) – The form array with tracking fields already added.$field_definitions(array) – The field definitions that were used.
// Log which forms have tracking fields injected (useful for debugging).
add_filter( 'pb_gforms_referral_tracking_form', function( $form, $field_definitions ) {
error_log( 'Referral tracking fields added to form ID: ' . $form['id'] );
return $form;
}, 10, 2 );pb_gforms_referral_tracking_merge_tag_map
Modify the merge tag map that defines which merge tags are available and which field IDs they resolve to. Use this to add entirely custom merge tags or rename existing ones.
Parameters:
$map(array) – Associative array of tag => [ ‘label’ => string, ‘field_id’ => string ].$base_id(string) – The base field ID prefix.$constants(Constants) – The plugin constants instance.
// Rename the "Source" merge tag label as it appears in the GF dropdown.
add_filter( 'pb_gforms_referral_tracking_merge_tag_map', function( $map, $base_id, $constants ) {
if ( isset( $map['pb_ref_source'] ) ) {
$map['pb_ref_source']['label'] = 'Traffic Source';
}
return $map;
}, 10, 3 );pb_gforms_referral_tracking_value
Filter a raw tracking field value before the plugin formats it and uses it to replace a merge tag in a notification or confirmation. This is the place to sanitise or transform a specific value.
Parameters:
$value(string) – The raw field value.$tag(string) – The merge tag key (e.g. pb_ref_source).$data(array) – The merge tag metadata (label, field_id).$entry(array) – The current entry.$form(array) – The current form.
// Truncate long referrer URLs in merge tag output.
add_filter( 'pb_gforms_referral_tracking_value', function( $value, $tag, $data, $entry, $form ) {
if ( $tag === 'pb_ref_referrer' && strlen( $value ) > 100 ) {
return substr( $value, 0, 100 ) . '…';
}
return $value;
}, 10, 5 );pb_gforms_referral_tracking_formatted_value
Filter the fully formatted merge tag value after Gravity Forms has run its own formatting pipeline over it (escaping, URL encoding, etc.).
Parameters:
$formatted(string) – The formatted output string.$tag(string) – The merge tag key.$data(array) – The merge tag metadata.$entry(array) – The current entry.$form(array) – The current form.$url_encode(bool)$esc_html(bool)$nl2br(bool)$format(string)
// Wrap the source value in a bold tag in HTML-format notifications.
add_filter( 'pb_gforms_referral_tracking_formatted_value', function( $formatted, $tag, $data, $entry, $form, $url_encode, $esc_html, $nl2br, $format ) {
if ( $tag === 'pb_ref_source' && $format === 'html' && ! $url_encode ) {
return '<strong>' . $formatted . '</strong>';
}
return $formatted;
}, 10, 9 );pb_gforms_referral_tracking_default_value
Override the fallback value used when a tracking field is empty at submission time. The default is “Unknown”.
Parameters:
$default(string) – The current default value (“Unknown”).$key(string) – Context key: source, referrer, or front_end.
// Use "Direct" instead of "Unknown" for the source field fallback.
add_filter( 'pb_gforms_referral_tracking_default_value', function( $default, $key ) {
if ( $key === 'source' ) {
return 'Direct';
}
return $default;
}, 10, 2 );pb_gforms_referral_tracking_js_config
Override the entire front-end JavaScript configuration object before the plugin passes it to the tracking script. Your callback controls cookie settings, the source maps (utmSourceMap and utmReferrerMap), known sources, and the paidClickIds list that decides which query parameters prove a paid click.
Parameters:
$config(array) – The full JS config array.
The keys, with their defaults:
| Key | Default | Controls |
|---|---|---|
cookieExpiry | 7 | Attribution window in days. |
cookiePrefix | pb-ref-tracking- | Prefix on every stored key. |
cookiePath | / | Cookie path. |
cookieSameSite | Lax | SameSite attribute. |
defaultValue | Unknown | Value written when nothing was captured. |
appendOrganicPaid | true | Whether custom labels get the Organic/Ads suffix. |
paidClickIds | 10 IDs | Query parameters that prove a paid click, and so produce an Ads label. |
utmSourceMap / utmReferrerMap | see below | Plain string maps from a utm_source value to a label and a canonical referrer URL. |
customSources | [] | Custom source rules. Prefer the dedicated filter above. |
sessionOnlyMode | false | Session cookies with no expiry. Forced on for logged-in administrators. |
fallbackStorage | none | local enables the cookieless fallback. |
consentRequired / consentGranted | false / null | The consent gate. See Settings reference. |
enableLastTouch | false | Capture the last-touch set as well. |
enableDataLayerPush | false | Emit the GA4 event. |
dataLayerEventName | pb_referral_submit | Name of that event. |
trackingFieldBaseId | '' | Base field ID for the injected fields. |
debug | false | Set true to log capture decisions to the browser console. The quickest way to see why a visit was labeled the way it was. |
sourcePatterns is deliberately absent from that list. Its entries need live JavaScript RegExp objects, and anything a PHP callback returns arrives as a string once the config is JSON-encoded, which throws at match time. To extend the referrer patterns, assign to window.PBReferralTrackingConfig from JavaScript before the tracking script runs.
// Extend cookie lifetime to 30 days and add a custom paid medium.
add_filter( 'pb_gforms_referral_tracking_js_config', function( $config ) {
// Extend the first-touch attribution window to 30 days.
$config['cookieExpiry'] = 30;
// Turn on the cookieless localStorage fallback for visitors who block cookies.
$config['fallbackStorage'] = 'local';
return $config;
} );pb_gforms_referral_tracking_custom_sources
Programmatically inject custom source rules that run alongside rules configured in the admin UI. The plugin merges rules from this filter with the saved UI rules, sorts the combined set by priority, and passes it to the front-end.
Parameters:
$sources(array) – Empty array. Return an array of rule arrays to add.
Each rule must have: label, matchField (referrer, utm_source, utm_medium, utm_campaign, utm_term, utm_content), matchType (contains or equals), matchValue, and optionally priority (default 10, higher runs first).
Rules added through this filter can also use referrer_url as the matchField, which matches against the full referrer URL including its path and query rather than just the host. The admin UI doesn’t offer it, so it is available only here.
// Add partner and affiliate sources without touching the admin UI.
add_filter( 'pb_gforms_referral_tracking_custom_sources', function( $sources ) {
$sources[] = [
'label' => 'Partner: Acme Corp',
'matchField' => 'referrer',
'matchType' => 'contains',
'matchValue' => 'acme.com',
'priority' => 20,
];
$sources[] = [
'label' => 'Campaign: Spring Sale',
'matchField' => 'utm_campaign',
'matchType' => 'contains',
'matchValue' => 'spring-sale',
'priority' => 10,
];
return $sources;
} );pb_gforms_referral_tracking_source_label
Write your own label into a separate Custom Source field at submission time. The detected Source is never changed, so the entry keeps both: what the plugin worked out, and what you returned. Useful when a CRM needs a simplified or internal label and you don’t want to lose the real source. Since 1.6.0.
Attaching a callback is what turns the feature on. With nothing hooked, the Custom Source fields and their merge tags don’t exist. Add one and the plugin starts adding a Custom Source field to your forms, plus a Custom Source (Last touch) field when last-touch attribution is enabled. Return an empty string to leave the field blank for a given visit; it won’t fall back to the detected label.
Parameters:
$label(string) – The detected source label, for exampleGoogle Ads.$key(string) – Which touch is being labeled:sourceorlast_source.$form(array) – The current form object.
// Roll the detected source up into a few buckets for the CRM.
add_filter( 'pb_gforms_referral_tracking_source_label', function( $label, $key, $form ) {
if ( 0 === strpos( $label, 'Google' ) || 0 === strpos( $label, 'Bing' ) ) {
return 'Search';
}
if ( 0 === strpos( $label, 'Facebook' ) || 0 === strpos( $label, 'Instagram' ) ) {
return 'Social';
}
// Anything else: leave the Custom Source field empty.
return '';
}, 10, 3 );pb_gforms_referral_tracking_enqueue_assets
Control whether the plugin’s front-end assets (cookie library and tracking script) are enqueued. Return false to disable loading entirely on a page or condition.
Parameters:
$enqueue(bool) – Whether to enqueue assets. Default true.
// Disable tracking assets on the homepage only.
add_filter( 'pb_gforms_referral_tracking_enqueue_assets', function( $enqueue ) {
if ( is_front_page() ) {
return false;
}
return $enqueue;
} );pb_gforms_referral_tracking_inline_css
Override the inline CSS that hides tracking fields on the front-end and in the block editor preview. The default CSS hides the tracking, legacy Google Ads tracker, and mirror field wrappers, targeting .gform_wrapper .gfield with the pb-ref-tracking-, pb-gads-tracking-, and pb-ref-mirror- class prefixes.
Parameters:
$css(string) – The inline CSS string.
// Replace the default hide rule with a more specific selector.
add_filter( 'pb_gforms_referral_tracking_inline_css', function( $css ) {
return '.my-theme .gform_wrapper .gfield[class*="pb-ref-tracking-"] { display: none !important; }';
} );pb_gforms_rt_invalidate_debounce
Adjust (or disable) the Reports cache-invalidation debounce window. After a new entry comes in, the Reports cache is rebuilt at most once per this many seconds so high-volume forms don’t thrash it. Default is 60 seconds; return 0 to invalidate immediately on every entry.
Parameters:
$seconds(int) – The debounce window in seconds. Default 60.
// Rebuild Reports data immediately on every new entry (no debounce).
add_filter( 'pb_gforms_rt_invalidate_debounce', function( $seconds ) {
return 0;
} );pb_gforms_referral_tracking_mirror_field_definitions
Customize the persistent mirror field definitions created when mirror fields are added to a form. The label is the part you can safely change.
Leave cssClass alone. At submission the plugin reads the canonical tracking key back out of it, everything after pb-ref-mirror-, to find the value to copy across. Rename the class and the mirror field submits empty every time.
Parameters:
$fields(array) – Array of mirror field definition arrays.$form(array) – The current form meta.
// Prefix every mirror field label so they're easy to spot in the editor.
add_filter( 'pb_gforms_referral_tracking_mirror_field_definitions', function( $fields, $form ) {
foreach ( $fields as &$field ) {
$field['label'] = 'Tracking: ' . $field['label'];
}
return $fields;
}, 10, 2 );pb_gforms_referral_tracking_docs_url
Repoint the “Learn more in the documentation” link shown in the settings screen. Useful on white-label or agency installs that keep their own docs.
Parameters:
$url(string) – The documentation URL. Return your own to replace it.
// Point the settings-screen docs link at our own handbook.
add_filter( 'pb_gforms_referral_tracking_docs_url', function( $url ) {
return 'https://example.com/handbook/referral-tracking/';
} );