What's trending
UPCOMING EVENTS
Salesforce UTM Tracking: How to Capture Every Touchpoint
By Adam Erstelle
“Half the money I spend on advertising is wasted; the trouble is I don’t know which half.” This famous quote by John Wanamaker hits home for many Salesforce marketers struggling with attribution. We pour budget into Google, LinkedIn, webinars, and email campaigns… but connecting those dots in Salesforce? That’s often been a headache of UTM-sized proportions.
In this post, we’ll take a look at how UTM tracking traditionally worked in Salesforce (with the old-school “MacGyver” approach), why that method often made us want to pull our hair out, and how a new approach can ensure no UTM is left behind. Along the way, we’ll see how capturing every touchpoint (not just the first or last) leads to better campaign attribution and happier marketers. Let’s dive in!
Why UTMs Matter
UTM parameters might seem like tiny URL add-ons, but they play a big role in marketing attribution. By tagging your links with UTMs, you can trace exactly where a prospect came from, what campaign brought them in, and which marketing efforts are driving real results.
Here’s an example, with the UTM parameter names in light blue and their values in dark blue:

Without UTMs, it’s nearly impossible to distinguish between traffic from different emails, social channels, or ad variations.
While that’s all great, why do we (marketers) care? Ultimately, it’s going to be about measuring dollars and effort.
- Measure ROI by channel: Being able to answer the question: We spent $50k on LInkedIn Ads. What came of that?
- Identify which campaigns drive the highest quality leads: Where might we focus additional advertising dollars?
- Align marketing spend with actual revenue outcomes: High activity on campaigns that don’t drive revenue should cause you to reevaluate your approach. Is it a conversion issue (that you can fix), or are you attracting the wrong type of audience?
Reporting With Campaign Influence
At the end of the day, marketers want to prove their efforts are driving revenue – and in Salesforce, that means Campaign Influence. Campaign Influence reporting connects your marketing campaigns to closed deals and helps answer questions like: Which campaigns influenced the most opportunities? Where should we invest more budget?
For this to work, a specific chain of relationships needs to be in place:
- A Campaign with active Campaign Members.
- Contacts who are Campaign Members (even if they were originally added as Leads).
- That Contact must be associated with an Opportunity via an Opportunity Contact Role.

Campaigns, Contacts, and Opportunities are rarely the issue. The challenge often comes with the junction objects.
- CampaignMember: Marketers and Marketing Automation Platforms often take care of this. However, as this post demonstrates, this can sometimes be tricky.
- OpportunityContactRole: Manually populated by Sales (or more often not populated), with many organizations relying on custom automations or free AppExchange apps.
When all these pieces are connected, Salesforce can attribute that Opportunity back to one or more Campaigns. It’s how we move from “soft metrics” like clicks and opens to hard metrics like pipeline and revenue.
This is why capturing and syncing UTMs properly matters. Each UTM-tagged interaction can become a Campaign Member record, feeding into Campaign Influence and giving your team the data it needs to measure ROI accurately.
Whether you’re using Salesforce’s standard influence models or building custom ones, a strong UTM data pipeline gives your reports the fuel they need.
The Old Approach: UTMs With Duct Tape and JavaScript
For the last 10 years, marketers have relied on hidden form fields, browser cookies, and a good dose of JavaScript to grab those utm_source, utm_medium, utm_campaign, etc. from a landing page URL and sneak them into Salesforce.
The typical process looks like this: a visitor clicks an ad or link, lands on your form page, and the page’s JavaScript captures the UTM parameters from the URL, then populates invisible form fields. When the visitor submits the form, those UTM values flow into Salesforce (often onto the Lead or Contact record). Finally, Salesforce automation (like a Flow or Apex trigger) takes over to stamp those values onto a new Campaign Member record.

Once in Salesforce, the UTMs would be associated with a Campaign Member – effectively tying the lead/contact to a specific Salesforce Campaign with those UTM details. Some marketers even created custom fields on the Campaign Member object (e.g., Campaign Member UTM Source, UTM Medium, etc.) to store this info.
There are a lot of blog posts out there that have various evolutions of the javascript (including many on Salesforce Ben), which all have their pros and cons. The good ones will typically have two different scripts that are combined. The first one will take the UTM parameters and stuff them into your own site’s cookies (be sure you are honoring your own consent rules here!), which will look something like this:
<script type="text/javascript">
// Parse the URL
const utmParams = new URLSearchParams(window.location.search);
// Convenience code to save values into cookies
function saveParameterInCookie(name) {
const d = new Date();
d.setTime(d.getTime() + (90*24*60*60*1000));// 90 days
let expires = "expires="+ d.toUTCString();
let cookievalue = utmParams.get(name);
document.cookie = ${name}=${cookievalue}; ${expires};path=/;
}
// Stuff the values into a Cookie for later.
if(utmParams.keys().length > 0) {
saveParameterInCookie('utm_source');
saveParameterInCookie('utm_medium');
saveParameterInCookie('utm_campaign');
saveParameterInCookie('utm_content');
saveParameterInCookie('utm_term');
}
The next bit of JavaScript takes those cookie values and puts them into your form’s hidden fields (that you have to define on each form). It typically looks something like this (being sure to adjust the field names in the last block to match how your form is built).
<script type="text/javascript">
// Convenience code to get values from cookies
function getParameterFromCookie(name) {
return document.cookie
.split("; ")
.find((row) => row.startsWith(name+"="))
?.split('=')[1];}
// Get the URL parameter values from cookies into variables
var source = getParameterFromCookie('utm_source');
var medium = getParameterFromCookie('utm_medium');
var campaign = getParameterFromCookie('utm_campaign');
var content = getParameterFromCookie('utm_content');
var term = getParameterFromCookie('utm_term');
// Put the values into the hidden fields in the form.
document.getElementsByName('utm_source').value = source;
document.getElementsByName('utm_medium').value = medium;
document.getElementsByName('utm_campaign').value = campaign;
document.getElementsByName('utm_content').value = content;
document.getElementsByName('utm_term').value = term;</script>
Combine that JavaScript with a bunch of Custom Fields all over the place and you might just capture 1 set of UTM values when a form is submitted!

So far, so good – what’s not to love? Well, as any admin who’s been through it will tell you, this homegrown UTM solution comes with some baggage.
UTM Headaches: Why the Old Approach Made Us Cry
On paper, the “UTM hidden fields + Campaign Member stamping” approach works. In practice, it could be a comedy of errors (except nobody laughs). Here are some of the pain points that often came up, served with a side of humor:
- Too Many Moving Parts: To set this up, you needed an all-star team – A Salesforce Admin to create custom fields and Flows, an Account Engagement Admin to mirror those fields on forms, a web developer to wrangle the JavaScript on every landing page, the marketing team to remember to include those fields on every form, and even your ad agency to strictly follow your UTM naming conventions. One missed step, and your data could go off the rails.
- Fragile Setup: The solution was held together by what felt like duct tape. JavaScript snippets had to execute correctly on every page, cookies needed to persist, and any change to your forms or website could break the tracking. Handling things like iframes is especially tricky. If a prospect navigated to a new page without submitting a form, those UTMs might never get captured at all.
- First Touch vs. Last Touch Dilemma: Out-of-the-box, this method captured whatever UTM values the prospect had at the time of form fill. That’s usually the “last touch.” But what about their first touch? Many marketers cloned the whole setup to create another set of fields and scripts for “First UTM Source,” “First UTM Campaign,” etc., and added logic to only set them the very first time. Duplicating all those fields and automation rules made the process even more complex (and error-prone).
- Incomplete Data (Multi-Touch Misses): Perhaps the biggest issue: a prospect interacting with multiple campaigns before converting. Fields and JavaScript just can’t capture every touch. We’d get the first touch, and the last touch… but everything in between (or even after the form is submitted)? Not captured.
- Human Error and Maintenance Hell: This setup wasn’t “set and forget.” Every new form or landing page needed the UTM fields and scripts. Every new marketer requires training on how it all works. One little typo or forgotten script, and your UTMs could vanish.
It’s no wonder many of us felt like Bill Murray in Groundhog Day – living the same problem over and over.
Frustration and Change
Working at a Marketing-based Salesforce Consultancy for many years, I came across all the blog posts and tried all the solutions. Over and over, we were trying to solve this with each client’s slightly different setup in Form approach and what we were trying to capture.
Meanwhile, the raw UTM data was sitting in Account Engagement, but it was just not accessible. Imagine being able to get to this data, there would be no need for any of the JavaScript mentioned earlier, and no need for all the custom fields and automations.
API and Apps to the Rescue
While the Account Engagement API isn’t as rich as I wish it could be, it does give us the endpoints needed to extract this information and give us more robust reporting and touchpoint data than we could ever get with form submissions.

- Visitor Page Views: The “gold” that we are looking for. The field URL contains the tracked URL including all parameters, not just the UTMs. This means you can get the Google click ids, or click ids from other platforms as well.
- Visit: This links each page view with a single visit that a person made to your site. They may/may not be identified just yet, it will depend on whether they have submitted a form or performed some other activity that Account Engagement can tie to a Prospect.
- Prospect: This gives you details about the Prospect, and for our use case, the most important piece is if they were recently assigned to a CRM user, meaning they have become synced with Salesforce to become a Lead or Contact record.
Rolling your own code here has a few considerations you need to keep in mind, specifically around the state of a visitor when you pull in a Page View record. If they have not yet been identified, you definitely won’t have a Lead/Contact to associate them with, so you’ll need to watch/detect (using other API calls) when this happens, and it could be weeks or even months later.
The volume of records here will be another consideration, and you’ll likely want to build a good portion of the processing off-platform where you can work with more data at once. Data science and engineering teams familiar with Python and Pandas will be able to make quick work of this.
Now, if you’re thinking this sounds like a lot to build, you’re not wrong. You can DIY this with your own code, making the API calls. But for those who’d rather skip the headaches, I created an app that automates the whole process. It plugs into Account Engagement, captures UTMs automatically, and syncs touchpoints to Salesforce.
How Access to All Touchpoints Can Impact Reporting
When you have access to every UTM-tagged interaction, not just the first or last, your reporting becomes exponentially more robust. Rather than trying to infer which campaign “must have” influenced an opportunity, you can see the full picture of engagement across time.
This helps most when you are working with multi-touch attribution, where credit is shared across the campaigns that actually contributed to a deal.
If you load the extracted Page View information into Salesforce, you can get a more complete view of engagement within a Campaign, even if the people interacting with the links are anonymous or simply a prospect not yet synced as a Lead/Contact.

As an example, in the chart above, we can see that the link associated with this Campaign is highly engaged by anonymous visitors, with a small percentage currently as Salesforce Leads/Contacts. This additional information can be invaluable, especially when you might be paying for each “click”.
Final Thoughts
UTMs are the breadcrumbs of the buyer journey. If you’re only tracking the crumbs that land on your form submits, you’re missing the full story. By modernizing your UTM tracking strategy, you empower better reporting, smarter marketing decisions, and a sales team armed with the full picture.
So, whether you’re building it yourself or checking out tools others have made, it’s time to bring your UTM tracking out of the 2010s and into the present. Let’s make sure no UTM gets left behind (and your future self building campaign influence dashboards will thank you).
More like this:

Comments: