Tag: Lead Tracking

  • Pardot and WordPress: How to Track Lead Source Through to Salesforce

    Pardot and WordPress: The Lead Source Gap

    Pardot (now called Salesforce Marketing Cloud Account Engagement) is a B2B marketing automation platform built for longer sales cycles, complex lead nurturing, and tight integration with Salesforce CRM. Organizations using Pardot typically have a real demand for knowing where their leads came from — B2B marketing budgets are significant, sales cycles are long, and connecting marketing activity to closed revenue is the fundamental attribution question the whole team needs answered.

    The challenge: Pardot’s native forms and WordPress sites don’t share source data automatically. A prospect who clicks a LinkedIn ad, reads a blog post, and fills out a contact form on your WordPress site generates a Pardot lead with their name, email, and company — but often no information about which campaign introduced them to you.

    This guide covers how to capture UTM data from your marketing campaigns and pass it through to Pardot prospect records, so every lead in your pipeline carries the source data your sales team and marketing team actually need.

    Why Source Data Matters in a Pardot-Salesforce Pipeline

    In most Pardot implementations, leads become Salesforce opportunities when they’re sales-qualified. If source data travels with the prospect from lead to opportunity, your team can:

    • Measure marketing-sourced revenue. Filter closed-won opportunities by lead source and calculate actual revenue attributed to each channel, not just lead volume
    • Optimize campaign spend at the portfolio level. If LinkedIn campaigns generate expensive leads that close at a high rate, and Google Search generates cheaper leads that rarely close, your budget allocation decision is clear — but only if the data is there
    • Build source-aware nurture tracks. Pardot’s engagement programs support conditional branching. A prospect who found you through a branded search is further along in their awareness than one who clicked a cold display ad; their nurture sequence should reflect that
    • Report marketing contribution to leadership. The marketing-sourced pipeline number is a standard executive metric in B2B organizations. Without lead source data, this number is either absent or inaccurate

    How UTM Tracking Works in a WordPress-Pardot Setup

    The basic flow:

    1. A prospect arrives on your WordPress site from a tagged URL with UTM parameters (utm_source, utm_medium, utm_campaign, utm_content, utm_term)
    2. A JavaScript snippet reads those parameters and stores them in a first-party cookie that persists as the prospect navigates the site
    3. When the prospect submits a form, hidden fields capture the stored UTM values
    4. The form data — including the UTM fields — posts to Pardot, either through a Pardot form embedded on the page or via a WordPress form plugin integrated with Pardot through the Pardot API or Zapier
    5. Pardot stores the UTM values on the prospect record as custom fields
    6. When the prospect converts to a Salesforce lead or contact, the Pardot custom field values can sync to Salesforce custom fields on the lead/contact and opportunity records

    Step 1: Consistent UTM Tagging Across Campaigns

    Source data tracking starts with UTM tags on every marketing link. A tagged URL looks like:

    https://yoursite.com/resources/guide/?utm_source=linkedin&utm_medium=paid_social&utm_campaign=q3-enterprise-awareness&utm_content=cfo-targeting

    Every paid ad, email campaign link, partner referral, and event link should carry UTMs. Use consistent naming conventions — “linkedin” not “LinkedIn” not “LI” — because any variation creates a separate bucket in your data that you’ll have to reconcile later. Organic search traffic doesn’t need manual UTM tagging, but every paid and owned channel does.

    Use Google’s Campaign URL Builder to construct tagged URLs without typos. For large campaign sets, build a spreadsheet that generates tagged URLs from a consistent naming convention so you’re not manually typing UTMs for every ad.

    Step 2: Capture UTMs in Cookies on Landing

    UTM parameters exist in the URL only on the first pageview. A landing-page cookie script captures them immediately and persists the data across the session and across pages:

    document.addEventListener('DOMContentLoaded', function() {
      const params = new URLSearchParams(window.location.search);
      const utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
      
      utmParams.forEach(function(param) {
        const val = params.get(param);
        if (val) {
          document.cookie = param + '=' + encodeURIComponent(val)
            + '; path=/; max-age=7776000; SameSite=Lax';
        }
      });
      
      if (!readCookie('landing_page')) {
        document.cookie = 'landing_page=' + encodeURIComponent(window.location.href)
          + '; path=/; max-age=7776000; SameSite=Lax';
      }
    });
    
    function readCookie(name) {
      const m = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
      return m ? decodeURIComponent(m[2]) : '';
    }
    

    Install this on your WordPress site via WPCode, your theme, or a custom header script. It runs on every page and writes UTM values to 90-day cookies that survive navigation between pages.

    Step 3: Create Custom Fields in Pardot

    Pardot stores additional data on prospect records as custom fields. In your Pardot account, go to Admin > Configure Fields > Prospect Fields and create text fields for:

    • Lead Source (maps to utm_source)
    • Lead Medium (maps to utm_medium)
    • Lead Campaign (maps to utm_campaign)
    • Lead Content (maps to utm_content)
    • Lead Keyword (maps to utm_term)
    • Landing Page (maps to the first URL the prospect visited)

    If your Pardot-Salesforce sync is configured, also create matching custom fields on the Salesforce Lead and Contact objects (and optionally on the Opportunity, via a formula field or workflow) so the source data carries through when prospects become sales-qualified.

    Step 4: Pass UTMs Through Forms to Pardot

    The connection method depends on how your forms are set up:

    Option A: Pardot forms embedded on WordPress. Pardot’s native forms can be embedded on WordPress pages via the Pardot plugin or via iframe. In the Pardot form editor, add hidden fields for each UTM custom field. Use JavaScript to populate those hidden fields from cookies when the page loads:

    document.addEventListener('DOMContentLoaded', function() {
      const fieldMap = {
        'lead_source': 'utm_source',
        'lead_medium': 'utm_medium',
        'lead_campaign': 'utm_campaign',
        'lead_content': 'utm_content',
        'lead_keyword': 'utm_term',
        'landing_page': 'landing_page'
      };
      
      Object.entries(fieldMap).forEach(function([fieldName, cookieName]) {
        const val = readCookie(cookieName);
        if (val) {
          // Target by Pardot field name attribute
          const input = document.querySelector('[name="' + fieldName + '"]');
          if (input) input.value = val;
        }
      });
    });
    

    Note: Pardot iframe forms run in a separate browsing context. You cannot inject JavaScript into an iframe from the parent page. The cookie-reading JavaScript needs to be added inside the Pardot form’s own layout template (via Pardot’s form editor under Layouts), or you need to use Option B or C below.

    Option B: WordPress form plugins with Pardot integration. Gravity Forms has a Pardot add-on. WPForms and similar plugins can connect to Pardot via Zapier or the Pardot API. Add hidden fields to your WordPress form for each UTM value, populate them from cookies using JavaScript in the parent page (no iframe boundary issue), and map the fields to Pardot custom fields in the integration settings.

    Option C: Zapier with a Pardot integration. Route WordPress form submissions to Pardot via Zapier. Configure the Zap to create or update a Pardot prospect with UTM field values mapped to the custom fields you created. This works with any WordPress form plugin that can trigger a Zap.

    Step 5: Verify End to End

    Before the setup goes live, test the complete pipeline:

    1. Open an incognito window and visit: yoursite.com/?utm_source=test&utm_medium=email&utm_campaign=tracking-verify
    2. Navigate to another page (verify UTM cookies persist in DevTools > Application > Cookies)
    3. Submit your form with a test email address
    4. Find the prospect record in Pardot — check that Lead Source shows “test”, Lead Medium shows “email”, Lead Campaign shows “tracking-verify”
    5. If Pardot-Salesforce sync is active, verify the lead/contact record in Salesforce shows the same values

    Pardot-Specific Considerations

    Pardot’s built-in Source field. Pardot has a default “Source” field on prospect records. This field is populated by Pardot’s own tracking mechanism (based on referrer and campaign association), not by UTM parameters directly. It’s useful but limited — it captures channel-level data (organic search, direct, paid search) but not campaign-specific data. The custom UTM fields you create above layer on top of this and provide the campaign-level granularity you need.

    Prospect deduplication. Pardot deduplicates prospects on email address. If the same email submits twice (once with UTMs and once without), Pardot updates the existing record. Depending on your field update rules, the existing UTM data may or may not be overwritten. Configure your custom UTM fields with “Do not update unless blank” if you want to preserve first-touch source data across multiple form submissions from the same prospect.

    Salesforce field sync order. When Pardot syncs to Salesforce, the direction and update rules for each field matter. Confirm that your UTM custom fields are configured to sync from Pardot to Salesforce (not the other way around, which would overwrite Pardot data with empty Salesforce fields).

    Using Source Data in Pardot

    Once source data arrives with each prospect:

    Segmentation lists. Create Pardot dynamic lists filtered by Lead Source or Lead Campaign. A list of “LinkedIn-sourced prospects” or “Q3 awareness campaign prospects” can receive targeted content without mixing them into a general nurture track.

    Engagement program branching. Add source-based conditions to your engagement programs. A branch that checks “if Lead Medium = paid_social, send sequence A; else send sequence B” lets you tailor follow-up to where someone came from.

    Salesforce reports by source. In Salesforce, build reports that filter opportunities by the Lead Source field (synced from Pardot). Calculate pipeline value and closed-won revenue by source to show marketing’s contribution to the business in revenue terms.

    The Manual Maintenance Problem

    This setup works, but it requires ongoing maintenance. Every new form added to your WordPress site needs the hidden UTM fields and JavaScript wiring. If you add a campaign landing page, you need to set up the form integration again. When Pardot form layouts change, the JavaScript may need updates.

    A dedicated WordPress attribution plugin installs once and handles the UTM capture-and-pass pipeline automatically across all forms — Pardot, and any other platform connected to your site. When a new form goes live, source data flows through without a separate configuration step.

    If reliable lead source data from WordPress through Pardot to Salesforce is something your team needs working consistently, Sales Provenance is the faster path.

  • MailerLite and WordPress: How to Track Lead Source for Every Subscriber

    MailerLite and WordPress: The Attribution Problem

    MailerLite is one of the most popular email marketing platforms for small businesses and growing teams. It’s clean, affordable, and handles most email needs well. But like every email marketing platform, it has a blind spot: it doesn’t automatically tell you where each subscriber came from before they landed on your WordPress site and filled out your form.

    You can see that someone subscribed. You can see which emails they open. But the source data — the Google Ad they clicked, the organic search that brought them to your blog, the Facebook campaign that introduced them to your brand — lives on the WordPress side of the equation and doesn’t automatically make its way into MailerLite.

    This guide covers how to bridge that gap: capturing UTM parameters from your marketing campaigns and passing them to MailerLite subscriber records as custom fields, so you can see which channels are actually growing your list.

    Why Lead Source Data Matters for Email Marketing

    Email list growth is only meaningful if you understand which sources are producing subscribers who actually engage, convert, or buy. Without source data:

    • You can’t tell whether your Google Ads are building your list or just generating traffic that doesn’t subscribe
    • You can’t compare list quality across channels (organic subscribers often have higher lifetime value than paid ad subscribers)
    • You can’t send source-specific email sequences that speak to where someone came from and why they subscribed
    • You can’t defend or expand a marketing budget based on which channels are building your email list

    With source data in MailerLite, you can segment by where subscribers came from, build automations triggered by source, and report accurately on which marketing activities are growing your most engaged subscriber segments.

    How the Tracking Works

    The setup follows a consistent pattern whether you’re passing data to MailerLite, another email platform, or a CRM:

    1. A visitor arrives on your WordPress site from a tagged URL (one with UTM parameters in the query string)
    2. A JavaScript snippet reads those UTM values from the URL and stores them in a first-party cookie
    3. When the visitor fills out a form anywhere on your site — even several pages later — hidden fields in that form capture the stored UTM values
    4. The form submission, including the hidden UTM data, posts to MailerLite (through native integration, Zapier, or MailerLite’s API)
    5. MailerLite adds the subscriber with source data stored as custom fields on their subscriber record

    Step 1: Tag Your Traffic Sources

    UTM tracking only works if your marketing links carry UTM parameters. A tagged link looks like this:

    https://yoursite.com/free-guide/?utm_source=google&utm_medium=cpc&utm_campaign=summer-offer&utm_content=search-ad-v1

    Every paid ad, email campaign link, social post, and partnership link should be tagged. Google Analytics and Google Ads can handle auto-tagging for their own traffic, but UTM tags make source data available in your own systems, not just in Google’s dashboard.

    Use Google’s Campaign URL Builder to construct tagged links without typos. Keep your naming conventions consistent — “google” is different from “Google” and “G” in any field that you’ll filter on later.

    Step 2: Capture UTMs in Cookies on Landing

    UTM parameters only exist in the URL on the first pageview. As a visitor navigates from the landing page to other pages, those parameters disappear from the address bar. A cookie-based capture script reads them immediately on landing and persists them across the session:

    document.addEventListener('DOMContentLoaded', function() {
      const params = new URLSearchParams(window.location.search);
      const utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
      
      utmParams.forEach(function(param) {
        const val = params.get(param);
        if (val) {
          document.cookie = param + '=' + encodeURIComponent(val)
            + '; path=/; max-age=7776000; SameSite=Lax';
        }
      });
      
      // Store the first landing page URL
      if (!readCookie('landing_page')) {
        document.cookie = 'landing_page=' + encodeURIComponent(window.location.href)
          + '; path=/; max-age=7776000; SameSite=Lax';
      }
    });
    
    function readCookie(name) {
      const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
      return match ? decodeURIComponent(match[2]) : '';
    }
    

    Add this script to your WordPress site using WPCode, your theme’s functions.php (via wp_enqueue_scripts), or a custom header script. It runs on every page load and writes UTM cookies that persist for 90 days.

    Step 3: Create Custom Fields in MailerLite

    MailerLite supports custom subscriber fields where you’ll store the source data. In your MailerLite account, go to Subscribers > Custom Fields and create text fields for:

    • Lead Source (from utm_source)
    • Lead Medium (from utm_medium)
    • Lead Campaign (from utm_campaign)
    • Lead Content (from utm_content)
    • Lead Keyword (from utm_term)
    • Landing Page (the first URL the subscriber visited)

    Note the field keys MailerLite assigns to each — you’ll use them when configuring the form integration.

    Step 4: Connect Your WordPress Forms to MailerLite With Hidden UTM Fields

    This step depends on how your opt-in forms are built.

    Option A: MailerLite’s embedded forms. MailerLite has a WordPress plugin that lets you embed their forms directly on your site. In the form editor, add hidden fields for each UTM custom field and populate them with JavaScript from the cookies:

    document.addEventListener('DOMContentLoaded', function() {
      const fieldMap = {
        'fields[lead_source]': 'utm_source',
        'fields[lead_medium]': 'utm_medium',
        'fields[lead_campaign]': 'utm_campaign',
        'fields[lead_content]': 'utm_content',
        'fields[lead_keyword]': 'utm_term',
        'fields[landing_page]': 'landing_page'
      };
      
      Object.entries(fieldMap).forEach(function([fieldName, cookieName]) {
        const val = readCookie(cookieName);
        if (val) {
          const input = document.querySelector('[name="' + fieldName + '"]');
          if (input) input.value = val;
        }
      });
    });
    

    Replace the field names with the actual input names from your MailerLite form’s HTML.

    Option B: WordPress form plugins with MailerLite integration. If you use WPForms, Gravity Forms, Fluent Forms, or similar plugins, many have native MailerLite add-ons. Add hidden fields to your form for each UTM value, use the same JavaScript to populate them from cookies, and map those fields to your MailerLite custom fields in the integration settings.

    Option C: Zapier or Make.com. If you’re using a form plugin without a native MailerLite integration, route form submissions through Zapier or Make.com. Configure the Zap to add the subscriber to MailerLite with the UTM hidden field values mapped to custom fields.

    Step 5: Test End to End

    Before relying on the data, verify the full pipeline works:

    1. Open an incognito window and visit: yoursite.com/?utm_source=test&utm_medium=cpc&utm_campaign=tracking-test
    2. Navigate to another page (confirm UTMs are still in the cookies via DevTools > Application > Cookies)
    3. Submit your form with a test email address you control
    4. Check the subscriber in MailerLite — the Lead Source field should show “test”, Lead Medium should show “cpc”, Lead Campaign should show “tracking-test”

    If the fields arrive empty, work backwards: Are the cookies being written on landing? Are the hidden fields being populated? Is the field mapping in the integration set up correctly? Each step is independently verifiable.

    Using Source Data in MailerLite

    Once source data arrives with each subscriber, you can put it to work:

    Segments by source. Create a MailerLite segment for subscribers where Lead Source = “google” or Lead Medium = “cpc”. This lets you see the size and behavior of your paid-traffic subscriber segment, and send targeted campaigns to them.

    Source-specific automation triggers. MailerLite’s automation builder supports custom field conditions as triggers. An automation that fires “when subscriber joins AND lead_source = facebook” can send a different welcome sequence than one that fires for organic subscribers. Someone who found you through a Facebook ad is in a different context than someone who found your blog through search.

    Reporting and channel evaluation. Export or filter your subscriber list by source. Compare open rates, click rates, and downstream conversion rates (purchases, bookings, appointments) by channel. This analysis often surfaces surprising findings — a smaller, high-engagement organic segment may outperform a larger paid segment in revenue terms.

    Campaign attribution. When you run a paid campaign and want to know if it built your list, filter MailerLite subscribers by the campaign’s utm_campaign value. You’ll see exactly how many subscribers that campaign generated, at what cost per subscriber.

    A Simpler Path

    The manual setup works, but it involves writing custom JavaScript, adding hidden fields to each form separately, configuring field mapping in each integration, and repeating the process whenever you add a new form or landing page to your site. A new opt-in box on a new page means starting the setup over again for that form.

    Sales Provenance installs once as a WordPress plugin and handles the capture-and-pass pipeline automatically across all forms on your site. UTM data (and additional first-party attribution data beyond just UTMs) passes to MailerLite and other connected platforms without per-form configuration.

    If you want lead source data flowing from your WordPress site into MailerLite without setting it up form by form, Sales Provenance is the faster path.

  • GoHighLevel and WordPress: How to Track Lead Source Through to Your CRM

    GoHighLevel and WordPress: The Attribution Gap

    GoHighLevel (GHL) has become one of the most popular all-in-one platforms for agencies and service businesses. It combines CRM, pipeline management, email marketing, SMS, landing pages, and booking into a single platform — and many businesses run it alongside a WordPress website for their main web presence.

    The problem: when leads come in through your WordPress forms or landing pages and land in GoHighLevel, the source data often doesn’t come with them. You see a new contact in your GHL CRM, but you don’t know if they came from a Google Ad, a Facebook campaign, an organic blog post, or a referral. That blind spot makes it impossible to evaluate which marketing is actually working.

    This guide covers how to capture UTM parameters and lead source data from your WordPress site and pass it through to GoHighLevel contacts automatically.

    Why Lead Source Data Matters in GoHighLevel

    GoHighLevel is built around pipelines and contact management. When every contact has source data attached, you can:

    • See which ad campaigns are filling your pipeline — not just generating website clicks, but producing real CRM contacts and booked appointments
    • Filter pipeline deals by source — understand whether Google Ads leads close at a higher rate than Facebook leads, which is often true for service businesses
    • Trigger source-specific automations — send a different nurture sequence to a Google search lead vs. a Facebook ad lead vs. an organic visitor
    • Report accurate ROI to clients — if you use GHL to manage client funnels, source data lets you show exactly which campaigns are driving pipeline

    How Lead Source Tracking Works With WordPress and GoHighLevel

    The technical flow is the same regardless of which CRM or platform you’re connecting to:

    1. A visitor arrives on your WordPress site from a tagged URL (one with UTM parameters: utm_source, utm_medium, utm_campaign, etc.)
    2. A script on your site captures those UTM values and stores them in a first-party cookie so they persist as the visitor navigates between pages
    3. When the visitor submits a form, hidden fields in that form are populated with the stored UTM values
    4. The form submission — including the UTM data — gets sent to GoHighLevel, either through a native integration, Zapier, or a webhook
    5. GoHighLevel creates or updates the contact with the source data attached as custom fields

    Step 1: Make Sure Your Campaigns Are UTM-Tagged

    Before any tracking can happen, your traffic sources need to be tagged. A tagged URL carries UTM parameters that tell your tracking system where the visitor came from:

    https://yoursite.com/service/?utm_source=google&utm_medium=cpc&utm_campaign=spring-special&utm_content=search-ad-v1

    Tag every paid ad, every email campaign link, and every social post you control. Organic search traffic doesn’t need manual UTM tags — you’ll track that separately via Google Search Console. Direct traffic (visitors who type your URL) won’t have UTM data, which is expected.

    Step 2: Capture UTMs in a Cookie on Landing

    UTM parameters only exist in the URL on the first pageview. Once a visitor clicks to another page, they disappear from the address bar. You need a script that reads them on landing and writes them to a first-party cookie that persists across the session:

    document.addEventListener('DOMContentLoaded', function() {
      const params = new URLSearchParams(window.location.search);
      const utmParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
      
      utmParams.forEach(function(param) {
        const val = params.get(param);
        if (val) {
          document.cookie = param + '=' + encodeURIComponent(val)
            + '; path=/; max-age=7776000; SameSite=Lax';
        }
      });
      
      // Capture the landing page URL (only set on first visit)
      if (!readCookie('landing_page')) {
        document.cookie = 'landing_page=' + encodeURIComponent(window.location.href)
          + '; path=/; max-age=7776000; SameSite=Lax';
      }
    });
    
    function readCookie(name) {
      const m = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
      return m ? decodeURIComponent(m[2]) : '';
    }
    

    Add this script to your WordPress site via a plugin (like WPCode) or directly in your theme’s header. It runs on every page load and writes UTM values to cookies with a 90-day expiry.

    Step 3: Create Custom Fields in GoHighLevel

    GoHighLevel supports custom contact fields where you’ll store the source data. In your GHL account, go to Settings > Custom Fields > Contacts and add the following text fields:

    • Lead Source — maps from utm_source
    • Lead Medium — maps from utm_medium
    • Lead Campaign — maps from utm_campaign
    • Lead Content — maps from utm_content
    • Lead Keyword — maps from utm_term
    • Landing Page — maps from the landing page URL

    Note the field keys that GHL assigns to each — you’ll need these when you configure the integration.

    Step 4: Pass UTMs Through Your WordPress Forms to GoHighLevel

    Now you need to connect your WordPress contact forms to GoHighLevel with the UTM data included. There are several common paths depending on your setup:

    Option A: WordPress form plugin with a native GHL integration. Some form plugins (like WPForms with its CRM addons, or Fluent Forms) have native GoHighLevel integrations. Add hidden fields to your form for each UTM value, populate them with JavaScript from cookies on page load, and map them to the corresponding GHL custom fields in the integration settings.

    Option B: GoHighLevel’s WordPress plugin. GHL offers a plugin that lets you embed GHL forms directly on your WordPress site. Add hidden fields to the GHL form and populate them with the UTM cookie values via JavaScript. The form submits directly to GHL, and the hidden fields land as contact data.

    Option C: Webhook or Zapier. If your WordPress form plugin (Gravity Forms, Contact Form 7, WPForms) doesn’t have a native GHL integration, send the form data to a webhook and route it to GHL via Zapier or Make.com. Include the hidden UTM fields in the webhook payload and map them to GHL custom fields in your Zap.

    Regardless of which path you use, the JavaScript to populate hidden UTM fields from cookies is the same:

    document.addEventListener('DOMContentLoaded', function() {
      const fieldMap = {
        'lead_source_field': 'utm_source',
        'lead_medium_field': 'utm_medium',
        'lead_campaign_field': 'utm_campaign',
        'lead_content_field': 'utm_content',
        'lead_keyword_field': 'utm_term',
        'landing_page_field': 'landing_page'
      };
      
      Object.entries(fieldMap).forEach(function([fieldName, cookieName]) {
        const val = readCookie(cookieName);
        if (val) {
          const input = document.querySelector('[name="' + fieldName + '"]');
          if (input) input.value = val;
        }
      });
    });
    

    Replace the field names in fieldMap with the actual input field names or IDs in your form.

    Step 5: Test End to End

    Run a complete test before you trust the data in your GHL CRM:

    1. Open a private browser window and visit a tagged URL: yoursite.com/?utm_source=test&utm_medium=cpc&utm_campaign=tracking-test
    2. Navigate to another page on your site — confirm the cookies persist (check in DevTools > Application > Cookies)
    3. Submit your contact form with a test email address
    4. In GoHighLevel, find the new contact and check their custom fields — Lead Source should show “test”, Lead Medium should show “cpc”, Lead Campaign should show “tracking-test”

    If the fields are empty, work backwards: Are the cookies being written? Are the hidden fields being populated by JavaScript? Is the integration mapping the fields correctly to the GHL custom fields?

    Using Source Data in GoHighLevel Automations and Pipelines

    Once data flows, put it to work:

    Source-based workflow triggers: GHL’s automation workflows support conditions on contact fields. Create a branch that sends a different nurture sequence based on Lead Source. A contact from “google” who searched for your exact service is in a different mindset than one from “facebook” who saw your ad in their feed.

    Pipeline filtering by source: Add Lead Source as a visible column in your pipeline views. You can quickly see whether one source is dominating at the top of the funnel, or whether a source that looks busy is actually converting to closed deals at a low rate.

    Attribution reporting: With source data on every contact, you can build simple reports in GHL or export contacts and analyze in a spreadsheet. Track new contacts by source over time, deal close rates by source, and revenue by source if you’re logging deal values.

    Opportunity tagging: When a contact converts to an Opportunity in GHL, the custom fields carry over. Tag opportunities by source to track which campaigns are generating pipeline, not just leads.

    The Simpler Path: One Plugin Setup

    The setup above works, but it involves custom JavaScript, per-form configuration, and ongoing maintenance whenever you change forms or update your site. Each new form or landing page requires the hidden fields and cookie-reading script to be wired up.

    A dedicated WordPress attribution plugin removes that overhead. Sales Provenance installs once, captures UTM data automatically on every landing, and passes it to GoHighLevel (and other platforms) through every form on your site — no per-form JavaScript, no custom field mapping for each new form, and more data than basic UTM tracking alone (including first-click vs. last-click source and full session data).

    If getting clean lead source data into your GoHighLevel CRM is something you want working this week, Sales Provenance is the fastest way to do it.

  • Brevo and WordPress: How to Track Lead Source for Every Contact

    The Lead Source Problem With Brevo and WordPress

    Brevo (formerly Sendinblue) is one of the most widely used email marketing and CRM platforms for small and mid-sized businesses. Connect it to your WordPress site and you can capture subscribers, send campaigns, and manage contacts — all in one place.

    But Brevo has the same blind spot as most email platforms: it captures who opted in, not what drove them there. Your Brevo contacts list might show 5,000 subscribers with names and email addresses, but no source data. Did they come from Google Ads? Facebook? Organic search? A referral campaign? Without that information, you can’t measure which marketing is actually building your list.

    This guide shows you how to track lead source through WordPress and pass it to Brevo so every contact has channel, campaign, and landing page data attached from the moment they sign up.

    Why Source Data in Brevo Changes What You Can Do

    Brevo is more than email — it includes contacts, deals, and pipeline features that function as a lightweight CRM. When you add source data to your contacts, you unlock capabilities that most Brevo users never use:

    • Filter and segment by source: Create a list of all contacts from Google Ads vs. organic search. Compare their engagement rates. Make informed decisions about where to invest your marketing budget.
    • Trigger source-specific automations: Send a different welcome email to someone who found you through a specific ad campaign vs. someone who subscribed from a blog post. Personalized first touchpoints improve conversion rates.
    • Report on marketing ROI: If you close deals in Brevo, you can attribute revenue back to the lead source — finally showing which campaigns are driving actual business, not just traffic.
    • Build better lookalike audiences: Export your highest-converting contacts by source and use them to build lookalike audiences in Facebook or Google Ads for better targeting.

    How the Tracking Setup Works

    The technical flow has four steps:

    1. UTM parameters arrive on landing. When a visitor clicks your ad or a tagged link, UTM parameters appear in the URL: utm_source, utm_medium, utm_campaign, and optionally utm_content and utm_term.
    2. A cookie script captures and stores them. A script runs on every page load, reads the URL for UTM values, and writes them to first-party cookies. This preserves the data as the visitor navigates through your site.
    3. Hidden form fields are populated. When a visitor reaches your opt-in form, JavaScript reads the cookies and populates hidden fields in the form — one for each UTM value you want to capture.
    4. Brevo receives the data as contact attributes. When the form submits, Brevo receives the hidden field values alongside the subscriber’s name and email. Those values get stored as contact attributes on their profile.

    Step 1: Tag Your Campaigns With UTM Parameters

    UTMs are the foundation. Every paid ad, every email campaign, every social media link you control should include UTM parameters so you know exactly where traffic is coming from.

    A properly tagged URL looks like this:

    https://yoursite.com/offer/?utm_source=google&utm_medium=cpc&utm_campaign=summer-launch&utm_content=headline-v2

    Organic search traffic doesn’t need UTM tags — Google provides that data via Google Search Console and GA4. Direct traffic (visitors who type your URL directly) will naturally have no UTM data, which is expected and normal.

    Step 2: Capture UTMs in Cookies When Visitors Land

    UTM parameters only exist in the URL on the first pageview. If a visitor lands on your homepage, reads a blog post, then navigates to your pricing page and fills out a form there, those original UTMs are long gone from the URL.

    You need a script that reads UTMs on landing and stores them in browser cookies so they’re available whenever the visitor converts. A basic version:

    document.addEventListener('DOMContentLoaded', function() {
      const params = new URLSearchParams(window.location.search);
      const utms = ['utm_source','utm_medium','utm_campaign','utm_content','utm_term'];
      
      utms.forEach(function(param) {
        const value = params.get(param);
        if (value) {
          document.cookie = param + '=' + encodeURIComponent(value) 
            + '; path=/; max-age=7776000; SameSite=Lax';
        }
      });
      
      // Also save the landing page URL
      if (!getCookie('landing_page')) {
        document.cookie = 'landing_page=' + encodeURIComponent(window.location.href)
          + '; path=/; max-age=7776000; SameSite=Lax';
      }
    });
    
    function getCookie(name) {
      const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
      return match ? decodeURIComponent(match[2]) : '';
    }
    

    The max-age=7776000 is 90 days in seconds — enough to capture most conversion journeys. Adjust based on your typical sales cycle.

    Step 3: Create Contact Attributes in Brevo

    Brevo stores subscriber data in contact attributes. Before you can pass source data to Brevo, you need to create the custom attributes where that data will live.

    In Brevo, go to Contacts > Settings > Contact Attributes > Add new attribute. Create the following as “Text” type attributes:

    • LEAD_SOURCE — the utm_source value (e.g., “google”, “facebook”)
    • LEAD_MEDIUM — the utm_medium value (e.g., “cpc”, “email”, “organic”)
    • LEAD_CAMPAIGN — the utm_campaign value
    • LEAD_CONTENT — the utm_content value (ad creative or link identifier)
    • LEAD_KEYWORD — the utm_term value (paid keyword)
    • LANDING_PAGE — the URL the visitor first landed on

    These attributes will appear on every contact’s profile once you start sending data.

    Step 4: Pass Cookie Values Through Your Opt-In Form

    Now connect your WordPress opt-in form to the cookies. The approach depends on which form plugin you’re using to integrate with Brevo.

    Using Brevo’s native WordPress plugin: Brevo’s official plugin lets you add hidden fields to their embedded forms. Add hidden fields for each attribute and use JavaScript to populate them from cookies when the page loads.

    Using WPForms, Gravity Forms, or Fluent Forms with a Brevo integration: Add hidden fields to your form and wire them to the cookie values via JavaScript. The Brevo integration then maps those form fields to the contact attributes you created.

    The JavaScript to populate the hidden fields:

    document.addEventListener('DOMContentLoaded', function() {
      const fieldMap = {
        'LEAD_SOURCE': 'utm_source',
        'LEAD_MEDIUM': 'utm_medium',
        'LEAD_CAMPAIGN': 'utm_campaign',
        'LEAD_CONTENT': 'utm_content',
        'LEAD_KEYWORD': 'utm_term',
        'LANDING_PAGE': 'landing_page'
      };
      
      Object.entries(fieldMap).forEach(function([attr, cookie]) {
        const value = getCookie(cookie);
        if (value) {
          const input = document.querySelector('[name="' + attr + '"]');
          if (input) input.value = value;
        }
      });
    });
    

    Step 5: Test the Full Pipeline

    Before you trust the data in Brevo, run a manual test:

    1. Open a link with UTM parameters in a private/incognito browser window: yoursite.com/?utm_source=test&utm_medium=email&utm_campaign=pipeline-test
    2. Click around your site for a page or two to confirm the cookies persist across pages
    3. Submit your opt-in form with a test email address
    4. In Brevo, find that contact and check their attributes — LEAD_SOURCE should show “test”, LEAD_MEDIUM should show “email”, LEAD_CAMPAIGN should show “pipeline-test”

    If the attributes are empty, debug in order: check whether the cookies were written (DevTools > Application > Cookies), then check whether the hidden fields are being populated (inspect the form HTML after load), then check whether the integration is mapping the fields correctly to the Brevo attributes.

    Using Source Data in Brevo Automations and Segments

    Once data is flowing, put it to work:

    Source-based automation triggers: In Brevo’s automation builder, you can trigger different flows based on contact attributes. Create one welcome sequence for Google Ads contacts (“You found us while searching — here’s what you’re probably looking for”) and a different one for organic contacts (“You found us through content — here’s more depth on the topic you were reading”).

    Segment by lead source for reporting: Create saved segments like “Source = google” and “Source = facebook.” Use these to compare list growth over time, open rates, and click rates by acquisition channel.

    Campaign reporting by source: When you run a broadcast email, you can filter your recipients by segment. This tells you whether subscribers from different sources respond differently to the same campaign.

    Deal attribution if using Brevo CRM: If you use Brevo Deals, the lead source attribute flows into the contact associated with each deal. You can filter deals by source to calculate revenue by marketing channel.

    The One-Setup Alternative

    The approach above works. But it requires custom JavaScript on every page, per-form configuration, and maintenance whenever you change forms or update your site. If you add a new landing page, you need to make sure the cookie script and hidden fields are wired up there too.

    A dedicated WordPress attribution plugin removes that overhead. Install it once, connect to Brevo, and source data flows to every new contact automatically — regardless of which page or form they convert on.

    Sales Provenance is built for exactly this: WordPress sites that use Brevo (or any email/CRM platform) and need to know which marketing is actually working. It handles the cookie capture, the landing page tracking, and the Brevo integration in a single setup — no per-form JavaScript, no maintenance burden, and more data than basic UTM tracking alone.

    If getting clean lead source data into Brevo is on your list, Sales Provenance is the fastest way to get there.

  • Mailchimp and WordPress: How to Track Lead Source for Every Subscriber

    Why Mailchimp Doesn’t Tell You Where Your Subscribers Came From

    Mailchimp is one of the most widely used email marketing platforms in the world. Millions of WordPress sites use it to collect subscribers and run campaigns. But Mailchimp has a blind spot: it captures who signed up, not what drove them to sign up.

    Your Mailchimp audience might have 3,000 subscribers. Did they come from Google Ads? Facebook? Organic search? A referral from a partner? Mailchimp doesn’t know, and neither do you — unless you build the tracking yourself.

    This guide shows you how to wire up UTM-based lead source tracking between WordPress and Mailchimp so every subscriber’s profile includes the campaign and channel that brought them in.

    What You’re Missing Without Lead Source Data

    Most email marketers track opens and clicks. Those metrics tell you how subscribers behave after they join your list. But they don’t tell you which acquisition channels are building a high-quality list vs. a low-quality one.

    With lead source data in Mailchimp, you can:

    • See which campaigns drive signups — not just impressions or website visits, but actual email subscribers
    • Compare list quality by source — do Google Ads subscribers open at 40% while Facebook subscribers open at 18%? That changes where you invest
    • Segment and personalize by source — send a different welcome sequence to someone who found you via organic search vs. a paid ad
    • Calculate true cost per subscriber — if you’re spending $2,000/month on Facebook and getting 200 subscribers, that’s $10/subscriber — worth knowing

    How Mailchimp Lead Source Tracking Works

    The mechanics follow the same pattern used across all CRM and email platform integrations:

    1. A visitor arrives on your WordPress site via a tagged URL (UTM parameters in the query string)
    2. A first-party cookie captures those UTM values and stores them for the duration of the session (and beyond, if set to persist)
    3. When the visitor fills out a Mailchimp opt-in form, hidden fields in the form are populated with the stored UTM values
    4. On form submission, those values are sent to Mailchimp as custom merge fields on the subscriber’s profile

    The result: every new subscriber in your Mailchimp audience has source, medium, campaign, and landing page data attached to their contact record.

    Step 1: Tag Your Traffic Sources With UTM Parameters

    UTM parameters are the query string values that tell your tracking system where a visitor came from. They look like this:

    https://yoursite.com/?utm_source=facebook&utm_medium=paid-social&utm_campaign=summer-sale&utm_content=carousel-v2

    Tag every paid ad, every email campaign link, and every social post you share. Organic search doesn’t need tags — you’ll see those as “(organic)” in your tracking. Direct traffic (no referrer) shows up without UTM data, which is expected.

    If you run Google Ads, enable auto-tagging instead of manual UTMs — Google will append its own gclid parameter automatically, which carries more data than manual UTMs for Google campaigns.

    Step 2: Capture UTMs in a First-Party Cookie on Landing

    UTM parameters only exist in the URL on the first pageview. The moment a visitor clicks to another page, they’re gone from the address bar.

    You need a script that runs on every page load, checks the URL for UTM parameters, and writes them to a cookie if it finds any. The cookie persists across pageviews so the data is available when the visitor finally fills out a form.

    A basic version of this script:

    // On page load
    const params = new URLSearchParams(window.location.search);
    const utmFields = ['utm_source','utm_medium','utm_campaign','utm_content','utm_term'];
    
    utmFields.forEach(field => {
      const value = params.get(field);
      if (value) {
        document.cookie = field + '=' + encodeURIComponent(value) + '; path=/; max-age=' + (60*60*24*90);
      }
    });
    

    This writes each UTM to its own cookie with a 90-day expiry. Most attribution tools use a 30-90 day window — adjust based on your typical sales cycle.

    Step 3: Create Custom Merge Fields in Mailchimp

    Mailchimp stores subscriber data in merge fields. The default fields are EMAIL, FNAME, LNAME, and PHONE. You need to add custom merge fields for each UTM value you want to capture.

    In Mailchimp, go to Audience > Manage contacts > Settings > Audience fields and *|MERGE|* tags and add the following fields (type: Text for all):

    • Lead Source — merge tag: *|LEADSRC|*
    • Lead Medium — merge tag: *|LEADMED|*
    • Lead Campaign — merge tag: *|LEADCAMP|*
    • Lead Content — merge tag: *|LEADCONT|*
    • Lead Keyword — merge tag: *|LEADKW|*
    • Landing Page — merge tag: *|LANDPG|*

    Keep these fields hidden from the subscriber (not visible on the public form) — they’re for your internal tracking only.

    Step 4: Populate Hidden Form Fields With Cookie Data

    Now you need a script that reads those UTM cookies and populates the hidden Mailchimp merge fields on your opt-in forms when the page loads.

    If you’re using embedded Mailchimp forms on your WordPress site:

    // After the form is in the DOM
    function getCookie(name) {
      const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
      return match ? decodeURIComponent(match[2]) : '';
    }
    
    const fieldMap = {
      'LEADSRC': 'utm_source',
      'LEADMED': 'utm_medium', 
      'LEADCAMP': 'utm_campaign',
      'LEADCONT': 'utm_content',
      'LEADKW': 'utm_term'
    };
    
    Object.entries(fieldMap).forEach(([mergeTag, cookieName]) => {
      const input = document.querySelector('[name="' + mergeTag + '"]');
      if (input) input.value = getCookie(cookieName);
    });
    
    // Also capture current URL as landing page
    const landingInput = document.querySelector('[name="LANDPG"]');
    if (landingInput) landingInput.value = getCookie('landing_page') || window.location.href;
    

    If you’re using a WordPress form plugin (WPForms, Gravity Forms, Fluent Forms) with a Mailchimp integration, you’ll add hidden fields to your form and use the same cookie-reading approach to populate them on load. The integration will then map those fields to the Mailchimp merge fields you created.

    Step 5: Verify the Data Is Flowing

    Before you trust your Mailchimp source data, run a complete test:

    1. Open a link with UTM parameters in an incognito window (e.g., yoursite.com/?utm_source=test&utm_medium=email&utm_campaign=test-run)
    2. Navigate around your site for a page or two
    3. Submit your opt-in form with a test email address
    4. In Mailchimp, find that subscriber and check their profile — the Lead Source, Lead Medium, and Lead Campaign fields should show the UTM values you used

    If the fields are blank, work backwards: are the cookies being written? (Check in browser DevTools > Application > Cookies.) Are the hidden form fields being populated? (Inspect the form HTML.) Is the integration mapping the fields correctly?

    Using Lead Source Data in Mailchimp

    Once data is flowing, you can put it to work:

    Segment by source: Create segments for subscribers where Lead Source equals “google”, “facebook”, “organic”, etc. Analyze open rates, click rates, and conversion rates by segment.

    Trigger source-specific automations: Use merge field conditions in your automation triggers to send different welcome sequences based on how someone found you. A subscriber from a Google Ads campaign for a specific product is in a different mindset than someone who found your lead magnet through a blog post.

    Track subscriber acquisition in reports: Export your audience with the source fields and analyze in a spreadsheet or connect to a reporting tool. You’ll see subscriber growth by channel over time.

    Improve your ad targeting: If subscribers from one campaign have dramatically lower engagement than others, that’s a signal your ads may be attracting the wrong audience — even if the click-through rate looks good.

    The Simpler Approach: Use a WordPress Attribution Plugin

    The setup above works, but it requires custom JavaScript on every form, maintenance when you update your forms or switch form plugins, and careful testing across different browsers and form types.

    A dedicated WordPress attribution plugin handles all of this automatically. You install it once, connect it to Mailchimp, and it passes lead source data to every new subscriber without per-form configuration.

    Sales Provenance is built for this exact use case. It captures UTM parameters and landing page data on arrival, persists them through the browsing session, and passes them to Mailchimp (and other email and CRM platforms) automatically. No custom JavaScript. No form-by-form setup. Clean source data on every subscriber from day one.

    If tracking which channels are building your Mailchimp list matters to your business, Sales Provenance is the fastest way to get it working.

  • Klaviyo and WordPress: How to Track Lead Source Through to Your Account

    The Problem With Klaviyo Lead Tracking in WordPress

    You’re running ads, publishing content, sending emails, and posting on social. Leads are coming through your WordPress contact forms and landing on your Klaviyo email list. But when you look at your Klaviyo profiles, you have no idea where those people actually came from.

    Was it Google? Facebook? Organic search? A referral? Klaviyo captures the email address. It doesn’t automatically capture what drove that person to your site in the first place.

    This guide shows you how to fix that — so every Klaviyo subscriber has a lead source attached to their profile from the moment they opt in.

    Why Lead Source Data Matters in Klaviyo

    Klaviyo is primarily known for email and SMS marketing, but it also holds rich subscriber profile data. When you know where each subscriber came from, you can:

    • Segment by source — send different welcome flows to Google Ads leads vs. organic search leads
    • Measure channel ROI — connect Klaviyo revenue (for ecommerce) or conversions back to the original source
    • Optimize your ad spend — know which campaigns are building a high-quality list vs. a low-quality one
    • Score leads intelligently — organic subscribers tend to convert differently than paid subscribers

    Without source data, all of that segmentation is guesswork.

    How Klaviyo Lead Source Tracking Works

    The approach is straightforward:

    1. UTM parameters arrive on your WordPress site from the traffic source (Google Ads, Facebook, etc.)
    2. A tracking script captures those UTMs and stores them in the visitor’s browser session
    3. When a visitor submits a form, the UTMs are passed as hidden fields alongside their contact info
    4. Your form plugin sends the form data (including UTMs) to Klaviyo as custom profile properties
    5. Klaviyo stores the source data on the subscriber profile permanently

    The result: every Klaviyo profile shows exactly which campaign, channel, and keyword drove that subscriber to opt in.

    What You Need

    • WordPress site with contact forms or opt-in forms
    • Klaviyo account (any plan)
    • UTM tracking setup on your ad campaigns and links
    • A way to capture UTMs and pass them to Klaviyo — either a dedicated attribution plugin or custom code

    Step 1: Make Sure Your Campaigns Use UTM Parameters

    Before anything else, your traffic sources need to be tagged. UTM parameters are the query string values that tell your tracking system where a visitor came from.

    A properly tagged URL looks like this:

    https://yoursite.com/free-guide/?utm_source=facebook&utm_medium=paid-social&utm_campaign=fall-promo&utm_content=carousel-ad

    Tag every ad, every email campaign, and every link you control. Organic search doesn’t need tags — Google Search Console handles that separately.

    Step 2: Capture UTMs on Landing

    When a visitor lands on your site, their UTM parameters live in the URL for that first pageview. The moment they click to another page, those parameters disappear from the URL.

    You need a script that reads the UTM parameters on landing and stores them — typically in a first-party cookie or localStorage — so they’re available when the visitor finally fills out a form (which may happen several pages and several minutes later).

    Most attribution plugins handle this automatically. If you’re building this yourself, you’ll read window.location.search on page load, parse the UTM values, and write them to cookies with a 30-day or 90-day expiry.

    Step 3: Pass UTMs Through Your Opt-In Form as Hidden Fields

    Your Klaviyo forms or embedded opt-in forms need hidden fields that populate with the stored UTM values when the form loads.

    If you’re using Klaviyo’s own embedded forms, this requires custom JavaScript that populates hidden input fields before the form submits. If you’re using a WordPress form plugin (WPForms, Gravity Forms, Formidable) that integrates with Klaviyo via Zapier or a direct integration, you add hidden fields to the form and populate them with JavaScript on page load.

    The hidden fields you want to capture:

    • lead_source — maps to utm_source (e.g., “google”, “facebook”)
    • lead_medium — maps to utm_medium (e.g., “cpc”, “email”, “organic”)
    • lead_campaign — maps to utm_campaign
    • lead_content — maps to utm_content (ad creative or link)
    • lead_keyword — maps to utm_term (paid keyword, if applicable)
    • landing_page — the first URL the visitor landed on

    Step 4: Map Form Fields to Klaviyo Profile Properties

    When the form submits to Klaviyo (via their API or an integration), those hidden field values need to land as custom profile properties on the subscriber.

    In Klaviyo, custom properties can be named anything. You’ll configure your form integration so that:

    • The form’s lead_source field maps to a Klaviyo property called Lead Source
    • The form’s lead_campaign field maps to Lead Campaign
    • And so on for each UTM field

    Once this is set up, every new subscriber who submits that form will have those properties written to their profile automatically.

    Step 5: Verify It’s Working

    Test the full flow before you trust the data:

    1. Click a tagged link (e.g., one with utm_source=test&utm_medium=test)
    2. Navigate a few pages to make sure the UTMs persist
    3. Submit an opt-in form with a test email address
    4. Find that profile in Klaviyo and check the profile properties — you should see Lead Source, Lead Campaign, etc. populated correctly

    If the properties aren’t there, the most common culprits are: the hidden fields aren’t being populated by JavaScript, the integration isn’t mapping the fields correctly, or the UTMs aren’t being stored in cookies properly.

    Using Lead Source Data in Klaviyo Flows and Segments

    Once the data is flowing, you can put it to work immediately:

    Segment by lead source: Create a segment for “Lead Source equals google” and another for “Lead Source equals facebook.” Now you can see list growth by channel and compare engagement rates.

    Trigger different welcome flows: A subscriber who came from a paid Google Ad is in a different mindset than someone who found you through an organic blog post. Personalize your welcome sequence accordingly.

    Filter reports by source: When you run a campaign and want to know how paid subscribers performed vs. organic, you can filter by the Lead Source property.

    Lead scoring: Some businesses score leads differently based on source. An organic subscriber who found you by searching for your exact service often converts at a higher rate than a cold paid subscriber.

    The Easier Way: Use an Attribution Plugin That Does This Automatically

    Setting up UTM capture, cookie storage, hidden field population, and Klaviyo field mapping manually takes time and ongoing maintenance. Every form you add to your site needs to be updated. The cookie logic has to be tested across browsers.

    A dedicated WordPress attribution plugin handles all of this in a single setup. You install it, connect it to Klaviyo, and it automatically passes lead source data to every form on your site — no per-form JavaScript, no manual mapping.

    Sales Provenance is built for exactly this use case: WordPress sites that send leads to Klaviyo (or any CRM) and need to know which channel drove each one. It captures UTMs on landing, persists them through the session, and populates them into your Klaviyo profiles automatically — including the first landing page and the referring URL, not just the UTMs.

    If you want your Klaviyo list to have clean, complete lead source data without the manual setup, Sales Provenance is the fastest way to get there.

  • Copper CRM and WordPress: How to Track Lead Source Through to Your CRM

    Copper is the CRM built for Google Workspace. It lives inside Gmail, syncs your contacts automatically, and gives sales teams a pipeline that feels native to the tools they already use every day. But if your leads come through a WordPress contact form, Copper still has the same attribution gap as every other CRM: a name, email, and phone number arrive, with no record of which campaign or channel brought that person to your site.

    This guide covers exactly how to fix that — connecting your WordPress forms to Copper so that lead source, campaign, and keyword data flows into every new contact and lead automatically.

    Why Copper users lose attribution data

    Copper’s Gmail integration means contacts often get created automatically when a new email arrives. But the email that arrives from a WordPress contact form submission contains only what the visitor typed — it does not carry UTM parameters from the URL they clicked to reach your site.

    If someone clicked a Google Ad tagged with utm_source=google&utm_medium=cpc&utm_campaign=accounting-software, visited your site, filled out a contact form, and triggered a notification email that created a Copper contact, that contact record has no UTM data attached. The traffic source is gone.

    The fix is to intercept those UTM parameters before the form submits and route them into Copper alongside the standard contact fields.

    Step 1: Add custom fields to Copper

    Copper lets you add custom fields to People, Companies, Leads, and Opportunities records. For attribution tracking, create text fields on your Leads (or People) record type:

    • Lead Source (utm_source)
    • Lead Medium (utm_medium)
    • Lead Campaign (utm_campaign)
    • Lead Term (utm_term)
    • Lead Content (utm_content)
    • Landing Page
    • GCLID (for Google Ads offline conversions)

    In Copper, go to Settings > Custom Fields, select the record type, and add each as a Text field. Note the field names exactly as you create them — you will need them when mapping data from your form integration.

    Step 2: Tag your traffic with UTM parameters

    Every link pointing to your site from an ad, email, or campaign should include UTM parameters. At minimum, use utm_source and utm_medium. For paid campaigns, add utm_campaign and utm_term.

    For Google Ads, enable auto-tagging in your account settings (which adds the gclid parameter automatically) or use a URL suffix:

    utm_source=google&utm_medium=cpc&utm_campaign={campaign}&utm_term={keyword}

    For Facebook and Instagram ads, add UTM parameters in the “URL Parameters” field. For email campaigns, tag every link before sending.

    Step 3: Capture UTMs in WordPress with JavaScript

    When a visitor lands on your site with UTMs in the URL, JavaScript should capture and store them immediately — including in a cookie so the data persists if they navigate to another page before submitting a form.

    Add this script to your WordPress site via Google Tag Manager (Custom HTML tag, All Pages trigger) or through your child theme’s functions.php:

    <script>
    (function() {
      function getParam(name) {
        return new URLSearchParams(window.location.search).get(name) || '';
      }
      function getCookie(name) {
        var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
        return match ? decodeURIComponent(match[2]) : '';
      }
      function setCookie(name, value, days) {
        if (!value) return;
        var expires = new Date(Date.now() + days * 864e5).toUTCString();
        document.cookie = name + '=' + encodeURIComponent(value) + '; path=/; expires=' + expires;
      }
    
      // Store UTMs from URL into 30-day cookies
      ['utm_source','utm_medium','utm_campaign','utm_term','utm_content','gclid'].forEach(function(p) {
        var val = getParam(p);
        if (val) setCookie(p, val, 30);
      });
    
      // Store first landing page
      if (!getCookie('landing_page')) {
        setCookie('landing_page', window.location.href, 30);
      }
    
      // Populate hidden form fields when DOM loads
      document.addEventListener('DOMContentLoaded', function() {
        var map = {
          'field_utm_source': getCookie('utm_source') || getParam('utm_source'),
          'field_utm_medium': getCookie('utm_medium') || getParam('utm_medium'),
          'field_utm_campaign': getCookie('utm_campaign') || getParam('utm_campaign'),
          'field_utm_term': getCookie('utm_term') || getParam('utm_term'),
          'field_utm_content': getCookie('utm_content') || getParam('utm_content'),
          'field_gclid': getCookie('gclid') || getParam('gclid'),
          'field_landing_page': getCookie('landing_page') || window.location.href
        };
        Object.keys(map).forEach(function(id) {
          var el = document.getElementById(id);
          if (el && map[id]) el.value = map[id];
        });
      });
    })();
    </script>

    Replace the field IDs (field_utm_source, etc.) with the actual IDs of the hidden fields in your WordPress form. Find these in your form plugin’s field configuration.

    Step 4: Connect WordPress forms to Copper

    Copper does not have a native WordPress plugin, so you need one of the following approaches to get form submissions into Copper with the UTM data attached.

    Option A: Zapier (most common approach)

    Zapier connects virtually every WordPress form plugin to Copper with no custom code. The flow is straightforward:

    1. Add hidden fields to your WordPress form for each UTM parameter (utm_source, utm_medium, utm_campaign, utm_term, utm_content, gclid, landing_page)
    2. In Zapier, create a Zap: Trigger = New submission in your form plugin (WPForms, Gravity Forms, Ninja Forms, etc.), Action = Create Lead or Create Person in Copper
    3. Map each hidden field value to the corresponding Copper custom field
    4. Test with a real form submission and verify the contact record in Copper shows the correct custom field values

    Zapier’s Copper integration supports creating Leads, People, Companies, and Opportunities, and can also look up existing records to avoid duplicates. Use “Find or Create Lead” if you want to update an existing record when the same email submits again.

    Option B: Copper API via webhook

    If you want to avoid Zapier’s cost or need more control, you can send form submissions directly to the Copper REST API using a WordPress webhook. Gravity Forms and WPForms both support webhooks natively.

    In your form plugin’s webhook settings, point the webhook to a small intermediary script (or a service like Pipedream or Make) that forwards the payload to https://api.copper.com/developer_api/v1/leads with your Copper API key and user email in the headers.

    The Copper API endpoint for creating a lead accepts a JSON body with name, email, phone, and a custom_fields array. Each custom field entry needs the Copper field ID and the value you want to store.

    Option C: Google Sheets as an intermediary

    Since Copper is built for Google Workspace, a Google Sheets middle layer works well: form submissions go to a Google Sheet (via WPForms or Gravity Forms native Sheets integration), and a Zapier Zap or Google Apps Script processes each new row and creates a Copper lead. This approach gives you a backup log of every submission and makes it easy to audit attribution data.

    Step 5: Track attribution through to Opportunities

    Copper’s pipeline tracks People through stages to Opportunities. To maintain source attribution all the way to revenue, copy the custom attribution fields from your Lead or Person record to the Opportunity when it is created.

    You can do this with a Zapier automation: when a new Opportunity is created in Copper, find the linked Person, pull their attribution custom fields, and update the Opportunity record with the same values. This means your closed-won report can show not just how much revenue you closed, but which campaign it came from.

    Step 6: Report on lead source in Copper

    With UTM data in custom fields, you can filter and report by source in several ways:

    • Copper’s built-in filters: In the Leads or People list view, filter by any custom field value to see all leads from a specific source or campaign.
    • Pipeline reports: Use Copper’s reporting to see how many Opportunities were created from each source, and how many reached “Closed Won” status.
    • Google Sheets reports: Export your Copper data to Sheets (Copper has a native Google Sheets integration) and build pivot tables showing conversion rate and revenue by utm_source and utm_campaign.

    The Google Sheets export path is particularly useful for Copper users since it keeps everything in the Google Workspace ecosystem and makes the data easy to share with clients or stakeholders.

    Google Ads offline conversions with GCLID

    If you are running Google Ads, capturing the gclid parameter opens up offline conversion import — telling Google Ads which clicks actually turned into leads or customers, not just which clicks happened.

    Once you have gclid stored on your Copper lead records, you can export a CSV of leads (with gclid, conversion date, and conversion value) and upload it to Google Ads under Tools > Conversions > Upload. Google matches the gclid to the original click and credits the campaign, ad group, and keyword that drove the actual lead.

    This is especially powerful for service businesses where the value of a lead varies significantly by type. Uploading offline conversions with revenue values lets Google’s smart bidding optimize toward the campaigns that drive your most valuable customers, not just the most form fills.

    Common mistakes to avoid

    Letting Copper auto-create contacts from Gmail without UTM data. Copper’s Gmail integration creates contacts from email threads automatically. Those contacts will never have UTM data because the email arrives after the source visit. Make sure your Zapier or webhook path creates the lead FIRST, before the email auto-create adds a duplicate record with no attribution.

    Storing UTMs only in URL, not cookies. If a visitor lands on a blog post with UTMs and then navigates to your contact page before submitting, the UTMs are no longer in the URL. Cookie-based capture preserves them across the full session.

    Not testing with a real UTM-tagged URL. Submit a form from a URL that includes UTM parameters and verify the resulting Copper record has the correct values in each custom field. A missing Zapier field mapping or incorrect field ID is easy to miss without a real test.

    What attribution looks like when it works

    When everything is connected, every lead in Copper tells a complete story. A new lead arrives from a Google Ad campaign — utm_source: google, utm_medium: cpc, utm_campaign: cloud-accounting, utm_term: accounting software for small business, landing_page: /features/accounting/. The lead converts to a customer at $4,800 per year. That revenue traces back to the specific campaign and keyword that drove it.

    Over time, that data shows you which campaigns produce customers (not just leads), which keywords drive your highest-value deals, and where to shift budget to improve return on ad spend. And because Copper lives in Google Workspace, the data flows naturally into the Sheets reports your team already uses.

    The setup takes an afternoon. The data it produces is what makes every marketing budget decision going forward more defensible.

  • Keap and WordPress: How to Track Lead Source Through to Your CRM

    Keap and WordPress: How to Track Lead Source Through to Your CRM

    Keap (formerly Infusionsoft) is one of the most capable CRM and marketing automation platforms built for small service businesses. But if your leads come through a WordPress contact form, there’s a good chance Keap has no idea where those leads came from. You know a lead filled out a form. You don’t know whether they clicked a Google Ad, found you through a blog post, or came from an email campaign.

    That gap makes it nearly impossible to answer the most important question in marketing: which campaigns are actually producing customers?

    This post walks through exactly how to close that gap — connecting WordPress lead forms to Keap so that lead source, campaign, and keyword data flows into every contact record automatically.

    Why lead source tracking is harder with Keap

    Keap has powerful automation and tagging built in, but it does not automatically capture UTM parameters from your website. When someone clicks a Google Ad with a UTM like utm_source=google&utm_medium=cpc&utm_campaign=roofing-services and then fills out a WordPress contact form, Keap receives the form submission — but not the UTM data.

    The result: a contact record with a name, email, and phone number, and no record of how they found you. Over time, you accumulate hundreds of contacts with no source attribution. Every lead looks the same.

    Keap’s tagging system is particularly powerful when it has good data. You can tag leads by source, trigger different automation sequences based on how they found you, and build reports that show which channels produce your best customers. But that system only works if source data gets into Keap in the first place.

    The solution: UTM parameters into hidden form fields into Keap

    The tracking approach works in three stages:

    1. A visitor lands on your site with UTM parameters in the URL
    2. JavaScript captures those UTMs and stores them in hidden form fields
    3. When the form submits, those hidden fields pass source data into Keap alongside the contact information

    Getting this working requires a few pieces: custom fields in Keap, hidden fields in your WordPress form, and a bit of JavaScript to bridge the two. Here’s how to set it up.

    Step 1: Create custom fields in Keap

    Keap stores extra data on contact records using custom fields. Before you can pass UTM data in, you need fields to receive it.

    In Keap, go to Settings > Custom Fields > Contacts and create the following fields as text fields:

    • Lead Source (utm_source)
    • Lead Medium (utm_medium)
    • Lead Campaign (utm_campaign)
    • Lead Term (utm_term)
    • Lead Content (utm_content)
    • Landing Page (the URL where the visitor first arrived)

    Save the field IDs or internal names — you will need them when configuring your form integration.

    Step 2: Set up UTMs on your campaigns

    For tracking to work, your traffic sources need to include UTM parameters. Any link pointing to your site should include at minimum utm_source and utm_medium. For paid campaigns, add utm_campaign and utm_term.

    Example for a Google Ad:

    https://yoursite.com/contact/?utm_source=google&utm_medium=cpc&utm_campaign=emergency-plumbing&utm_term=plumber+near+me

    Google Ads can auto-apply UTMs using ValueTrack parameters. In your campaign settings, enable auto-tagging or use a final URL suffix like:

    utm_source=google&utm_medium=cpc&utm_campaign={campaign}&utm_term={keyword}&utm_content={creative}

    For Facebook and Instagram Ads, add UTM parameters in the “URL Parameters” field of each ad. For email campaigns, tag every link in your emails before sending.

    Step 3: Capture UTMs in your WordPress forms

    Most WordPress form plugins support hidden fields that users never see but that submit alongside the visible fields. The goal is to populate those hidden fields with UTM values as soon as the page loads.

    Add the following JavaScript to your site. You can add it via a Custom HTML block in WordPress, through your child theme’s functions.php, or through Google Tag Manager as a Custom HTML tag that fires on all pages.

    <script>
    function getUrlParam(name) {
      var url = new URL(window.location.href);
      return url.searchParams.get(name) || '';
    }
    
    function getCookie(name) {
      var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
      return match ? match[2] : '';
    }
    
    // Store UTMs in cookies so they persist across page visits
    var utmParams = ['utm_source','utm_medium','utm_campaign','utm_term','utm_content'];
    utmParams.forEach(function(param) {
      var val = getUrlParam(param);
      if (val) {
        document.cookie = param + '=' + encodeURIComponent(val) + '; path=/; max-age=2592000';
      }
    });
    
    // Store landing page on first visit
    if (!getCookie('landing_page')) {
      document.cookie = 'landing_page=' + encodeURIComponent(window.location.href) + '; path=/; max-age=2592000';
    }
    
    // Populate hidden form fields on DOM ready
    document.addEventListener('DOMContentLoaded', function() {
      var fieldMap = {
        'utm_source_field': getCookie('utm_source') || getUrlParam('utm_source'),
        'utm_medium_field': getCookie('utm_medium') || getUrlParam('utm_medium'),
        'utm_campaign_field': getCookie('utm_campaign') || getUrlParam('utm_campaign'),
        'utm_term_field': getCookie('utm_term') || getUrlParam('utm_term'),
        'utm_content_field': getCookie('utm_content') || getUrlParam('utm_content'),
        'landing_page_field': getCookie('landing_page') || window.location.href
      };
      Object.keys(fieldMap).forEach(function(fieldId) {
        var el = document.getElementById(fieldId);
        if (el) el.value = fieldMap[fieldId];
      });
    });
    </script>

    Replace the field IDs (utm_source_field, etc.) with the actual IDs of the hidden fields in your form. You will find those IDs in your form plugin’s field settings.

    Step 4: Connect WordPress forms to Keap

    How you pass the hidden field data to Keap depends on which tools you use. There are three common paths.

    Option A: Native Keap hosted forms (simplest setup)

    Keap provides hosted web forms you can embed on your WordPress site. When you build a form in Keap, add hidden fields for each UTM parameter and map them to your Keap custom fields. Then embed the form on your WordPress page.

    The JavaScript above will still populate those hidden fields since it targets fields by ID. Make sure the IDs in the Keap form embed match the IDs in your script.

    The trade-off is that Keap-hosted forms are less flexible to style. If the form design matters, the options below give you more control.

    Option B: WPForms or Gravity Forms with Zapier

    If you use WPForms, Gravity Forms, or a similar WordPress form plugin, you can pass form submissions to Keap via Zapier.

    1. Add hidden fields to your WordPress form for each UTM parameter
    2. In Zapier, create a Zap: Trigger: New form submission (WPForms or Gravity Forms), Action: Create or update contact in Keap
    3. Map the hidden field values from the form to the corresponding Keap custom fields
    4. Test the Zap with a real form submission to confirm the data is flowing correctly

    This approach works reliably and requires no custom code beyond the JavaScript above. The downside is Zapier’s cost at higher submission volumes.

    Option C: WPForms Keap addon or Gravity Forms Keap addon

    Both WPForms and Gravity Forms offer native Keap integration addons. These connect directly without Zapier and let you map form fields to Keap fields and tags inside the WordPress admin.

    With the Gravity Forms Keap Add-On, you can:

    • Map any form field to any Keap custom field
    • Apply Keap tags based on form answers or submission
    • Trigger Keap sequences when a form is submitted

    The native addons are typically more reliable than Zapier for high-volume sites and give you tighter control over automation triggers.

    Step 5: Use Keap tags to segment by lead source

    Once UTM data is flowing into Keap, the real power comes from using Keap’s tagging system to segment and route leads by source.

    In your Keap automation builder, create a sequence that fires when a new contact is created. Add a Decision Diamond that checks the utm_source custom field:

    • If utm_source contains “google” — apply tag “Lead: Google Ads” and start the Google Ads follow-up sequence
    • If utm_source contains “facebook” — apply tag “Lead: Facebook” and start the social follow-up sequence
    • If utm_source contains “organic” — apply tag “Lead: Organic” and start the organic nurture sequence

    This lets you send different follow-up emails depending on where a lead came from, which usually improves conversion rates significantly. A lead from a Google Ad has different intent than a lead from a blog post.

    Step 6: Report on lead source in Keap

    With tags applied by source, you can run meaningful reports in Keap:

    • Go to Reports > Contacts and filter by tag to see how many leads each source produced
    • Cross-reference your Keap lead counts against your ad spend to calculate cost per lead by channel
    • Track which source tags most often progress to “Customer” stage to find your best-converting channels

    If you move customers through a pipeline in Keap, you can also tag contacts when they convert and run a report showing which source tags produced the most conversions — giving you a clear picture of which campaigns drive actual revenue, not just form fills.

    What good attribution looks like in practice

    Once this is set up, every contact record in Keap tells you a complete story. A new lead named Sarah arrives with:

    • utm_source: google
    • utm_medium: cpc
    • utm_campaign: hvac-repair-madison
    • utm_term: ac repair near me
    • landing_page: /ac-repair/
    • Tags: Lead: Google Ads, HVAC Repair

    You know exactly which campaign and keyword drove Sarah to your site, which landing page she saw, and that she came from paid search. If Sarah books a job worth $1,200, that revenue traces back to your HVAC repair campaign. Over dozens of customers, you can see which campaigns produce revenue at a profitable cost per acquisition — and make confident budget decisions based on real data.

    Common mistakes to avoid

    Not storing UTMs in cookies. If your visitor lands on a blog post and then navigates to the contact page before filling out the form, the UTMs disappear from the URL. Storing them in cookies on first touch preserves them until the form is submitted.

    Skipping the landing page field. Knowing which page a lead visited when they first arrived is often as useful as knowing the campaign. It tells you which content or offer is actually converting.

    Only tagging Google Ads leads. Set up source tags for every channel you actively use: organic search, email campaigns, Facebook Ads, referral partners. If you only tag one source, your “no source” bucket grows and becomes meaningless.

    Not testing after setup. Submit a test form with UTMs in the URL and confirm the contact record in Keap shows the correct custom field values and tags before you rely on the data.

    The bottom line

    Keap is built for the kind of automated follow-up that converts leads into customers. But that automation is most powerful when Keap knows where each lead came from. Connecting your WordPress forms to Keap with UTM tracking gives you source data on every contact, better segmented follow-up sequences, and the reporting you need to see which marketing channels are actually worth the investment.

    The setup takes a few hours, but the payoff is attribution data that gets more valuable the longer you run it.

  • Zoho CRM and WordPress: How to Track Lead Source Through to Your CRM

    Zoho CRM is one of the most popular CRM platforms for small and mid-sized businesses. It is affordable, flexible, and integrates with almost everything. But like every CRM on the market, it has a quiet attribution problem.

    When a lead fills out your WordPress form, Zoho captures their name, email, and phone number. What it does not capture is how they found you. The UTM parameters in their URL, the Google Ads click ID, the campaign they came from, the keyword they searched, the landing page they hit first — all of that disappears. Zoho gets a lead. You get no idea which marketing channel sent it.

    This guide walks through how to fix that. By the end, every lead that enters Zoho CRM from your WordPress site will carry full attribution data, and every deal you close will be traceable back to the ad, campaign, or channel that started it.

    Why Zoho Does Not Track UTMs by Default

    Zoho CRM has a native web forms feature and integrates directly with Zoho Forms. Both can send submission data into Leads or Contacts in your CRM. But neither product reads the URL parameters that tell you where the visitor came from.

    When someone clicks a Google Ad and lands on your site, their URL might look like this:

    yourdomain.com/service-page/?utm_source=google&utm_medium=cpc&utm_campaign=service-name&gclid=AbC123xyz

    Zoho’s form does not read that URL. It only captures what is in the form fields. So unless you explicitly pass those parameters through hidden fields — and set up the infrastructure to capture them in the first place — none of that data reaches your CRM.

    The fix is a two-layer approach: capture attribution data from the URL and store it in a first-party cookie, then pass that data through hidden form fields into Zoho CRM as custom fields on the Lead or Contact record.

    Step 1: Capture UTMs and Click IDs to a First-Party Cookie

    The first layer is a small JavaScript snippet that runs on every page of your WordPress site. When a visitor lands with UTM parameters or a Google click ID (gclid) or Meta click ID (fbclid) in the URL, the script saves those values to a first-party cookie. If the visitor navigates to other pages before submitting the form, the cookie persists and the attribution data is still there at form submission time.

    The fields you want to capture are:

    • utm_source
    • utm_medium
    • utm_campaign
    • utm_term
    • utm_content
    • Landing page URL (first page the visitor hit)
    • gclid (Google Ads click ID)
    • fbclid (Meta Ads click ID)

    Set the cookie expiration to 30 days. This ensures attribution is preserved even when a visitor comes back a few weeks after their first click to finally submit the form.

    See the full implementation guide at UTM parameter tracking on WordPress for the exact script and installation steps via Google Tag Manager or WPCode.

    Step 2: Create Custom Fields in Zoho CRM

    Before you can store attribution data in Zoho CRM, you need somewhere to put it. Create the following custom fields on both the Leads module and the Contacts module:

    • Lead Source UTM (single-line text) — maps to utm_source
    • Lead Medium UTM (single-line text) — maps to utm_medium
    • Lead Campaign UTM (single-line text) — maps to utm_campaign
    • Lead Term UTM (single-line text) — maps to utm_term
    • Lead Content UTM (single-line text) — maps to utm_content
    • Landing Page (URL field) — the first page they visited
    • GCLID (single-line text) — Google Ads click ID
    • FBCLID (single-line text) — Meta Ads click ID

    In Zoho CRM: go to Setup > Customization > Modules and Fields. Select the Leads module, click Fields, and add each field above. Repeat for Contacts.

    You will also want to add the same fields to the Deals module. This is where deal-level attribution reporting happens — and it is how you eventually trace a closed deal back to the keyword or campaign that drove it. More on that below.

    Step 3: Connect Your WordPress Form to Zoho CRM

    There are three main ways to send form submissions from WordPress into Zoho CRM. The right path depends on which form plugin you are using and how much customization you need.

    Option A: Zoho Forms with Hidden Fields

    If you are using Zoho Forms embedded on your WordPress site, you can add hidden fields to the form and populate them with JavaScript from the cookie you set in Step 1. Zoho Forms supports hidden fields natively. Map each hidden field to the corresponding custom Zoho CRM field when setting up your form-to-CRM connection in Zoho Forms.

    This is the simplest path if you are already in the Zoho ecosystem, but it limits your WordPress form design flexibility.

    Option B: WordPress Form Plugin with Native Zoho Integration

    Several popular WordPress form plugins have native Zoho CRM integrations:

    • Gravity Forms — Zoho CRM Add-On (official add-on, maps fields directly to CRM modules)
    • WPForms — Zoho CRM integration via the Zapier add-on or direct REST webhook
    • Fluent Forms — Zoho CRM integration (direct, included in the Pro version)

    The flow is: add hidden fields to your WordPress form, populate them with JavaScript from the attribution cookie, and then map those hidden fields to the custom fields you created in Zoho CRM. When a form is submitted, the plugin sends the lead data including UTM values directly into Zoho.

    This is the recommended path for most WordPress sites. You keep full control of form design and UX while getting clean Zoho CRM integration.

    Option C: Webhook to Zoho CRM API

    For maximum control, you can configure your WordPress form to POST directly to the Zoho CRM API via webhook. This bypasses any third-party plugin integration and lets you build exactly the payload Zoho expects.

    Zoho CRM’s REST API accepts Lead creation at POST /crm/v2/Leads. You pass a JSON body with all standard and custom field values. This approach works well if you have a developer available or are using a form plugin like Gravity Forms that supports custom webhooks with full control over the request body.

    See the broader integration guide at CRM integration for WordPress for the direct webhook architecture and field-mapping approach that applies across CRM platforms.

    Step 4: Copy Attribution Fields from Lead to Deal with Zoho Workflow

    Getting attribution data into the Lead record is only half the job. When a Lead converts to a Contact and a Deal is created, those attribution fields do not automatically carry over in Zoho CRM. You need a Workflow to copy them.

    In Zoho CRM, go to Setup > Automation > Workflow Rules. Create a new rule for the Deals module. Set the trigger to “A record is created.” Add a field update action for each attribution field — source from the associated Contact record’s custom fields and write them to the corresponding Deal fields.

    After this workflow is active, every new Deal will automatically inherit the attribution data from the Contact that created it. Your sales pipeline now carries full source, medium, campaign, keyword, and click-ID data on every open and closed opportunity.

    Step 5: Report on Deals by Attribution in Zoho Analytics

    Once attribution fields are on your Deal records, Zoho CRM’s built-in reporting becomes genuinely useful for marketing decisions.

    Create a custom report on the Deals module and group by Lead Source UTM or Lead Campaign UTM. You can then compare close rate, deal value, and revenue by channel. This is the closed-loop view that most marketing attribution setups never achieve — not just “which channel drove leads” but “which channel drove revenue.”

    Zoho Analytics (their dedicated BI product) connects directly to Zoho CRM and lets you build more sophisticated dashboards, but the Deals module reports in core Zoho CRM are sufficient for most use cases.

    Step 6: Upload GCLIDs to Google Ads as Offline Conversions

    If you are running Google Ads, the GCLID on each Deal record is valuable beyond just reporting. You can upload closed Deals back to Google Ads as offline conversions, telling the bidding algorithm exactly which clicks produced revenue rather than just form submissions.

    There are two paths to do this from Zoho:

    • Manual CSV upload: Export won Deals with their GCLID and deal close date from Zoho CRM. Upload the CSV in Google Ads under Tools > Conversions > Upload. This works and takes about 10 minutes per week.
    • Automated via Zoho Flow: Use Zoho Flow (their native automation platform, similar to Zapier but within the Zoho ecosystem) to trigger on “Deal Stage Changed to Closed Won” and POST the GCLID and conversion value to the Google Ads offline conversions API. This runs automatically with no weekly manual step.

    The same logic applies to Meta Ads via the fbclid field — Meta accepts offline conversions through its Conversions API. A Zoho Flow trigger on Closed Won can POST the fbclid and conversion data directly to Meta.

    For a detailed walkthrough of the Google Ads side, see Google Ads conversion tracking on WordPress.

    Testing the Full Stack

    Before you trust the data, run an end-to-end test:

    • Visit your WordPress site with UTM parameters in the URL (e.g., ?utm_source=test&utm_medium=cpc&utm_campaign=test-campaign&gclid=test123)
    • Submit a test form with a recognizable email address
    • Open the Lead record in Zoho CRM and confirm all 8 attribution fields populated correctly
    • Convert the Lead to a Contact and Deal
    • Confirm the Workflow fired and the Deal record now has the same attribution values
    • Run a Deals report grouped by Lead Source UTM and confirm your test Deal appears

    If any field is missing, work backward: check the cookie (browser dev tools > Application > Cookies), then the hidden field (inspect the form element), then the Zoho field mapping, then the Workflow trigger.

    The Attribution Gap Most Zoho Users Never Close

    Most businesses using Zoho CRM and WordPress have a usable lead pipeline but no idea which marketing channel drives their best customers. They know their Google Ads spend and their form fill rate. They do not know their close rate by channel, their revenue per click by campaign, or which keywords actually pay off.

    The setup above closes that gap. It is not a complicated integration — it is a UTM capture script, eight custom fields, a form field mapping, and one Workflow. Once it is running, every lead that comes in carries attribution data, and every deal you close is traceable back to the click that started it.

    If you use a different CRM, the same approach applies — see the guides for HubSpot, Pipedrive, Salesforce, and ActiveCampaign.

  • ActiveCampaign and WordPress Lead Tracking

    ActiveCampaign is one of the most widely used CRM and email automation platforms for small and mid-size service businesses. Its combination of contact management, deal pipelines, and marketing automation makes it a practical all-in-one choice.

    But like most CRMs, ActiveCampaign has an attribution gap: it records that a lead arrived, but not which campaign, keyword, or ad brought them there. The UTM parameters and click IDs that identify your best-performing channels stay in the browser and never make it into the contact or deal record.

    This guide covers how to close that gap — from UTM capture through hidden form fields to custom ActiveCampaign fields, deal-level reporting, and offline conversion upload to Google Ads and Meta.

    The Attribution Gap in ActiveCampaign

    When a visitor lands on your WordPress site from a paid ad, the URL looks something like this:

    https://yoursite.com/contact/?utm_source=google&utm_medium=cpc&utm_campaign=roofing-leads&gclid=abc123

    The UTM parameters identify the source, channel, and campaign. The gclid (Google Click ID) ties the visit to a specific ad click for offline conversion reporting.

    What happens to those values? By default, they disappear the moment a form is submitted. ActiveCampaign receives a name, email, and phone number — but nothing about where the lead came from.

    The result: you know you got a lead. You have no way to know it came from the campaign costing $80 per click, or from an organic search that costs nothing. You cannot see whether the leads from one campaign close at twice the rate of another. You cannot tell Google Ads which clicks are turning into paying clients.

    Step 1: Capture UTMs in First-Party Cookies

    The fix starts with a JavaScript snippet that runs when a visitor first lands on your site and stores UTM parameters in first-party cookies before they navigate to your contact page or anywhere else.

    The snippet captures six values:

    • utm_source — the traffic source (google, facebook, email)
    • utm_medium — the channel (cpc, organic, social)
    • utm_campaign — the campaign name
    • utm_term — the keyword that triggered the ad
    • utm_content — the specific ad or creative variant
    • gclid and fbclid — Google and Facebook click identifiers for offline conversion upload

    The cookie persists for 30 days, so a visitor who clicks your ad on Monday and fills out your form on Thursday still carries their original source data.

    You can install this snippet via Google Tag Manager (one GTM tag, fires on all pages), WPCode (a free WordPress code injection plugin), or directly in your theme’s functions.php. GTM is generally the cleaner path since it keeps tracking code version-controlled without requiring theme edits.

    Full implementation details in UTM Parameter Tracking on WordPress.

    Step 2: Create Custom Fields in ActiveCampaign

    ActiveCampaign supports custom fields at two levels: on the contact record and on the deal record. You want both.

    Contact-level fields capture attribution for every lead and enable email segmentation by source. Deal-level fields carry attribution through the pipeline so you can filter and report on revenue by channel.

    Contact-level custom fields to create:

    • Lead Source (stores utm_source)
    • Lead Medium (stores utm_medium)
    • Lead Campaign (stores utm_campaign)
    • Lead Term (stores utm_term)
    • Lead Content (stores utm_content)
    • Landing Page
    • GCLID
    • FBCLID

    To create these: go to Contacts > Manage Fields, add each as a Text field. Note the field IDs — you will need them when mapping form fields to AC fields.

    Deal-level custom fields:

    Go to Deals > Manage Fields and add a “Lead Source” field at minimum. You can mirror the full set if you want campaign-level deal filtering. These fields get populated automatically via an automation (Step 4), not by the form submission itself.

    Step 3: Connect Your WordPress Forms to ActiveCampaign

    There are three reliable paths for getting form submissions — including hidden UTM fields — into ActiveCampaign from WordPress.

    Option A: WordPress Form Plugin with Native AC Integration

    This is the cleanest approach for most setups. Several form plugins have built-in ActiveCampaign integrations that map form fields directly to AC contact fields:

    • Gravity Forms with the ActiveCampaign Add-On: full field mapping, supports hidden fields pre-populated from cookies via a small JS snippet
    • WPForms with ActiveCampaign integration: similar capability, simpler setup
    • Fluent Forms with AC integration: lightweight option with solid field mapping support

    The workflow: add hidden fields to your form (one per UTM value), use JavaScript to populate them from the stored cookies on page load, then map each hidden field to the corresponding AC contact field in the plugin’s integration settings.

    Option B: ActiveCampaign’s Native WordPress Plugin

    ActiveCampaign’s official WordPress plugin lets you embed their hosted forms directly on pages. These forms support hidden fields, but they render in an iframe — which can complicate hidden field injection. Test carefully before relying on this path for attribution capture.

    Option C: Webhook to the ActiveCampaign API

    For full control without a form plugin dependency, you can POST form data directly to ActiveCampaign’s Contacts API. Your form fires a webhook on submission; a Zapier zap or server-side function creates or updates the AC contact with all attribution fields included.

    More setup, but complete flexibility. This path also makes it straightforward to handle duplicate contacts (look up by email first, then update rather than create).

    For a deeper comparison of all three paths across CRM platforms, see CRM Integration for WordPress.

    Step 4: Copy Attribution to Deals via Automations

    When a contact is created from a form submission, an ActiveCampaign automation can immediately create a deal and copy attribution fields from the contact to the deal record.

    Build this automation in the Automations builder:

    1. Trigger: Contact is created (or submits a specific form)
    2. Action: Create a deal in your pipeline with the contact’s name and source info as the deal title
    3. Action: Update deal field “Lead Source” = contact field “Lead Source”
    4. Repeat the Update action for each field you want mirrored (campaign, medium, GCLID, etc.)

    This runs at the moment of contact creation, so attribution is on the deal from day one. The sales team sees the source in the deal card without having to cross-reference the contact record.

    Step 5: Build Deal-Level Attribution Reports

    Once deal-level fields are populated, you can filter your pipeline by channel and see which sources are generating actual revenue — not just lead volume.

    Two views worth building:

    Open pipeline by source: Filter deals by the “Lead Source” field to see how much pipeline value is sitting from Google Ads vs. organic vs. referral. This shows you where your best-value prospects are coming from before deals close.

    Won deals by campaign: Filter closed-won deals by “Lead Campaign” to compare revenue by campaign. A campaign generating $40K in won deals at a $6K cost looks completely different from one generating 30 leads at $120 each with a 5% close rate.

    ActiveCampaign’s built-in reporting is limited, but deal-view filtering on custom fields is enough to make channel-level spend decisions without exporting to a spreadsheet. For deeper reporting, export won deals with attribution fields to a Google Sheet and build a simple pivot table.

    Step 6: Close the Loop with Offline Conversion Upload

    If you are running Google Ads or Meta Ads, you can push won deals back to the ad platforms as offline conversions. This tells the platforms which clicks actually turned into clients — not just form fills.

    Google Ads: When a deal is marked won in ActiveCampaign, trigger an automation that fires a webhook containing the stored gclid and a conversion event name. A Zapier zap catches this and uploads the conversion to Google Ads via the Conversions API. Google attributes the closed client back to the specific campaign, ad group, and keyword that drove the click — and Smart Bidding learns to favor the placements that generate revenue, not just form submissions.

    Meta Ads: The same process applies using the fbclid stored in the deal record. Send the event to Meta’s Conversions API when a deal closes. This improves Meta’s optimization signal and reduces underreporting caused by iOS privacy restrictions.

    Full setup details in Google Ads Conversion Tracking on WordPress and Meta Ads Conversion Tracking on WordPress.

    The Full Stack, End to End

    Here is what the complete attribution chain looks like for an ActiveCampaign and WordPress setup:

    1. Visitor clicks a Google Ads ad; URL contains UTM parameters and gclid
    2. JavaScript fires on landing and stores utm_source, utm_medium, utm_campaign, utm_term, gclid in first-party cookies (30-day expiration)
    3. Visitor fills out your contact form; hidden fields are populated from the cookies
    4. Form plugin sends the contact to ActiveCampaign with all attribution fields mapped to custom contact fields
    5. ActiveCampaign automation creates a deal and copies attribution fields to the deal record
    6. Sales team works the deal in the pipeline with full source and campaign visibility
    7. Deal is marked won; automation fires a webhook with gclid to Google Ads offline conversion upload
    8. Google Ads Smart Bidding now optimizes for closed clients, not form fills

    The same chain works for Meta Ads (fbclid), organic search (utm_medium=organic), email campaigns (utm_source=email), and any other channel with UTM tagging.

    Related Guides