Marketers / Analytics

How to Attribute UTM Parameters to Salesforce Campaigns

By Carl Mortimer

Monitoring marketing channel performance in Salesforce (and Pardot) by each campaign is a challenge – and it’s even harder to determine which channel contributed to a prospect engaging with that campaign.

When it comes to collating this information into Salesforce Campaigns and Campaign Members (ultimately to utilize Campaign Influence), I’ve seen organizations create child Campaigns – one per channel (!) – to get a handle on this level of channel attribution. The downside is that not only does maintaining multiple campaigns and creating numerous assets waste time, but you also use an additional level within your Campaign hierarchy (that can only be a maximum of 5 levels).

There’s a better way, that taps into Salesforce Flow. In this guide, I’m going to show you how to use Salesforce Flow to stamp UTM parameters on the Campaign Member. You’ll have this granular channel performance data, without creating separate campaigns or duplicating marketing assets per channel.

Cool, let’s get straight to it!

Create UTM Custom Fields (Leads and Contacts)

For standard UTM tracking, you will want to create the following fields in both Pardot and Salesforce, exactly as shown:

  • utm_source
  • utm_medium
  • utm_campaign
  • utm_content
  • utm_term

This tutorial won’t cover how to create the UTM fields, JavaScript, or forms in Pardot to capture this data; if you are looking for guidance on this part, Hollie Fitzpatrick will guide you here. This tutorial is purely how get these values onto the Campaign Member records, using Salesforce Flow.

Also, note that in this tutorial (compared to Hollie’s), I’ve added “last touch” to the end of the field names to be more descriptive, but the process is the same.

Assuming you have already created the last touch UTM fields on the Lead and Contact records (those bullet pointed above), we now need to create the same fields that will help us check if the values have changed. As a result, we won’t sync historical, out dated UTM values into our Campaigns.

Repeat steps 1-3 below to create the following fields (on both Leads and Contacts):

  • utm_source checked
  • utm_medium checked
  • utm_campaign checked
  • utm_content checked
  • utm_term checked
  1. In Salesforce, go to Setup (the cog in the top right corner). Click on Object Manager and go to Lead.
  2. Create a new field, and select text as the data type*. Call it “utm_source check”.
  3. Select the profiles that should see this field. Leave off from page layouts as it’s only used for the Flow (automation). Hit Save and New, so you can repeat these steps faster for “utm_medium check” etc.

I’ve done the Lead object but you must repeat these steps for Contacts.

*The reason we aren’t using a boolean field (like a checkbox) is that we need to be able to say, field by field, that there is a difference. You’ll see this in action later.

Create UTM Custom Fields (Campaign Members)

Within Object Manager, go to the Campaign Member object and create the 5 UTM fields (eg. “utm_source”) the same way you did for the Leads and Contacts.

The Campaign Member record should look like this:

Awesome, now the fields are in place, we’re ready to build the Flow.

Building the Salesforce Flow

This is the Salesforce Flow that we’ll be using to stamp UTM parameters on the Campaign Member. I’ll break each step down and explain the logic.

1. Triggering the Flow

  • Select the Campaign Member as the object that will trigger the Flow.
  • Select when the record is created, along with Actions and Related Records.

This step needs to be when the record is created and not when the record is updated.

That way, we can be sure that the values that are attributed to the Campaign are true at the point the prospect (Lead/Contact) became a Campaign Member, and not synced to the Campaign Member later if the Lead/Contact record was edited in any way.

2. Decide if the Campaign Member is a Lead or Contact

The Campaign Member record can be related to either a Lead or a Contact, so we need to decide which record we are dealing with; that way, the Flow will use the correct record IDs in the steps that follow.

Create two outcomes, one for Lead and one for Contact.

  • For the Lead outcome, make sure all conditions are met. Select Record (Campaign Member) → Lead ID → ID
  • Select Is Null for the Operator. Global Constant is False.
  • Select Record → Contact ID → ID. Operator Is Null and Global Constant is True.

  • For the Contact outcome, repeat the steps with some changes. Make sure all conditions are met. Select Record (Campaign Member) → Contact ID → ID
  • Select Is Null for the Operator. Global Constant is False.
  • Select Record → Lead ID → ID. Operator Is Null and Global Constant is True.

The next steps for each path are identical, whether it’s a Lead or Contact. I’ll continue to use the Lead for this example, but for the Contact path, just swap out the Lead IDs for the Contact IDs.

3. Decide if the UTMs Have Changed

Now we come to the part of the Flow that will decide if the UTM parameters are different between the UTM last touch fields and the “check” fields we created earlier (ie. “utm_source” is different to “utm_source check”).

I’ve decided to stamp the Campaign Member with the values, even if just one value is different. The reason for this is a prospect can, for example, come through social for two campaigns but to only stamp those values that are different would mean we miss out on attributing social to the second campaign, since the value (“social”) isn’t different.

So, I’ve decided to use OR logic for the check, and assume that if one parameter is different, then the rest will be updated, too.

  • Create two outcomes, one called “utms are different” and the other default outcome as “utms are the same”.
  • For “utms are different”, ensure any condition is met.
  • In resource, select Record (Campaign Member) → Lead ID → utm source last touch field. Select Does Not Equal as your operator.
  • In value, select Record (Campaign Member) → Lead ID → the corresponding check field (in this case, “utm_source check”)
  • Repeat for the remaining fields.

Your decision node should now look like this:

4. Update Campaign Member Record with the new UTM parameters

  • Select “Use the Campaign Member that triggered the Flow”
  • For Filter Conditions, leave as: None – Always Update Record
  • Select the UTM fields and for the value, select the corresponding last touch field from the lead record. For example, “utm_source” → Record → Lead ID → utm_source last touch.

5. Transfer the values to the “check” fields

Finally, we need to update the “check” fields with the last touch values; that way, the Flow can run the checks next time, if our Lead/Contact becomes a Campaign Member of another Campaign in the future.

  • Select “Specify Conditions to identify records…”
  • Ensure all conditions are met → ID → equals → Record (Campaign Member) → Lead ID.
  • Under fields, select the check fields you created earlier.
  • In value, select the corresponding last touch fields from the Lead object.

Now, repeat the process for Contacts!


Having UTM parameters attributed to the Campaign Member is a fantastic way to monitoring which channels are contributing to Campaign success. You’ll avoid creating separate campaigns or duplicating marketing assets per channel – saving so much time, and resulting in a cleaner data model for reporting.

In this guide, I showed you how to use a Salesforce Flow to stamp UTM parameters on the Campaign Member.

If you need help to put something in place that will determine the success of all your marketing channels, get in touch and we’ll help you put a winning Campaign Hierarchy in place.

The Author

Carl Mortimer

Carl is a Salesforce Marketing Champion and a functional consultant at MarCloud Consulting, certified in Sales Cloud, Pardot and Marketing Cloud.


    June 02, 2022 9:45 pm
    Hi Carl. Thanks for the great article. We're already passing the UTM values through hidden form fields in order to place people into different campaigns per channel. I see where your solution cuts down on a lot of campaign maintenance and extra levels. However, I don't understand the point of using the check fields. If a campaign member can only have one campaign member record per campaign, and the flow only executes on the record creation, why not just always write the utm fields to the campaign member record, and then clear the utm fields on the lead/contact record at the end of the flow?
    Adam L
    June 21, 2024 2:02 am
    Hi Doug. The utm fields that the flow is checking for are all on the Lead/Contact records (not the newly created campaign member record). The reason for the "Check" fields is to see whether or not the Lead/Contact utm fields were updated with the latest form submission. You wouldn't want to populate the utm fields to the Campaign Member Record if it is old values from a previous touch. Because the fields are syncing between Pardot Prospect/CRM Lead/Contact records, the fields cannot be cleared. If you try to clear the fields in the flow, Pardot will just push back the previous value.
    August 15, 2022 4:47 pm
    Can these be achieved in SFMC?
    October 20, 2022 12:11 am
    Hi do you have a clue or a guide how to handle first touch UTM parameters in salesforce, regards and thanks
    February 07, 2023 7:31 pm
    How do you treat a subsequent submission of a cookied lead/contact without utm parameters? E.G. direct traffic?
    Adam L
    June 21, 2024 2:08 am
    Hi Dennis. I'm not sure how Carl does this, but I have seen instances where JavaScript is used to populate the value '' (or similar) for any form submissions that don't have utm parameters in the URL string. It's probably best to have something like this populated each time there is no available UTM or referring source info.
    July 12, 2023 7:43 am
    Hi do you have a guide how to handle first touch UTM parameters in salesforce. Or how to attribute campaigns by adding action rules to forms instead. regards and thanks

Leave a Reply