Three Seven Gravity Forms Source Capture
Saves where each inquiry came from on its Gravity Forms entry: the first visit, every visit in order, the latest Google Ads click ID and the first landing page. Adds the same source data to email and phone link clicks.
Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/37designs/wordpress-marketing-attribution/archive/refs/heads/main.zipA WordPress plugin by Three Seven. It saves where each inquiry came from on its Gravity Forms entry:
- The first visit's source and landing page
- Every visit's source in order, up to 8 visits within 90 days
- The most recent Google Ads click ID, ready for offline conversion uploads
- The visitor's own answer to "How did you hear about us?" (optional)
Gravity Forms on its own records only the page an entry was submitted from. Someone who clicks an ad, reads three pages and submits from a contact page shows no ad source at all.
Install (about 30 minutes per site)
- Download
gf-source-capture.zipfrom the latest release. Upload it under Plugins > Add New > Upload Plugin and activate it. - Open Settings > Source Capture. Check the cookie domain, add any payment or sign-in domains the site redirects through, edit the "How did you hear about us?" answers if needed, and save.
- Copy the snippet from that page into a Google Tag Manager Custom HTML tag. Fire it on all page views, with the same consent condition the site's other marketing tags use. Publish the container.
- In the forms table, tick each form that counts as an inquiry, then click "Add fields to ticked forms."
- Run the tests below.
The GTM tag holds a copy of the script. Re-paste the snippet and republish the container after a plugin update that changes assets/tracker.js, or after changing the cookie domain or ignore list.
How it works
- Cookie script. On each page view, the script checks whether the visitor arrived from outside the site: with ad or UTM parameters, from another site, or with no referrer at the start of a session. If so, it records the visit in first-party cookies (
tssc_ftfor the first visit,tssc_pathfor the visit list). Clicks within the site, page reloads and sign-in or payment redirects are skipped. - Mediums. Each visit gets a source and a medium:
cpcfor Google Ads clicks,organicfor search engines,ai-assistantfor ChatGPT, Perplexity, Claude, Gemini and Copilot,socialfor LinkedIn, Facebook, Instagram, X, YouTube, Reddit and Bluesky,referralfor other sites, and(none)for direct visits. UTM parameters override all of these. - Filling the fields. On pages with a tagged form,
assets/fill.jscopies the cookies into the hidden fields in the visitor's browser. It runs again when the visitor focuses a field and when they submit. Page caching can't mix up visitors, because each browser fills its own copy of the form. - Server check. At submission, the plugin re-reads the cookies if they reach WordPress. If a host's cache layer strips them, it uses the values the browser posted. It keeps only known keys, trims each value, and works out the gclid and landing page from the visit list.
- Notification emails. In
{all_fields}, the first touch and touch path show as readable lines, for example "2026-10-07 14:02 UTC · google / cpc · landed on /services/". The entry keeps the JSON.
Field reference
The plugin finds fields by their dynamic population parameter name. You can add them by hand instead of using the settings page.
| Field | Type | Parameter name |
|---|---|---|
| First touch | Hidden | tssc_first_touch |
| Touch path | Hidden | tssc_touch_path |
| Google click ID | Hidden | tssc_gclid |
| Landing page | Hidden | tssc_landing_page |
| How did you hear about us? | Drop Down | tssc_heard_about |
| Tell us more (optional) | Single Line Text | tssc_heard_about_detail |
Consent
The cookies need the same consent as other marketing cookies. With GTM delivery, the consent banner controls the tag. With "load from plugin" delivery, the consent tool has to block the script itself; use the tssc_script_tag filter to change the opening tag, for example to `