About Adam Erstelle

Adam Erstelle is a Solution Engineer & Product Development Lead with Sercante. He loves learning about and solving really interesting challenges with Pardot and Salesforce often by building some cool tools.

The Simple Way to Create Multi-Language Account Engagement Forms

Handling multiple languages with Account Engagement (Pardot) forms has always been complex — especially when it comes to reporting. But there is a way to multi-language Account Engagement forms.

The traditional solution — one form per language — has its drawbacks. But it’s something that’s super important for companies that use Account Engagement on a global scale to do in a logical and user-friendly way. 

Today, we’ll explore a new, more efficient method that improves reporting and streamlines the translation process.

Challenges with traditional solutions for creating multi-language Account Engagement forms

There are a few ripple effects that we have to handle when we use multiple forms to realistically capture one set of data. 

First, we need a way of figuring out which form we want to display. Commonly this is done as a piece of dynamic content driven off a known Prospect field.

Next, we need to handle submissions for a single goal across multiple forms. The approach we take can vary depending on how complex our Automations and Reporting strategies are, and it all can add up.

A new solution for handling multiple languages

We can still work within the constraints of Account Engagement (Pardot) and leverage a common web development pattern of internationalization (or i18n for short). With the power of JavaScript, we can have one Account Engagement form and feel confident that our visitors will be able to have it in their language.

JavaScript and Handlebars.js

Before we dive into the actual code (honestly my favorite), it might be helpful to talk about what we are going to use.  We have a mix of a little bit of custom JavaScript with a common JavaScript library called HandlebarsJS, not to be confused with Account Engagement Handlebars Merge Language (HML).

The custom JavaScript takes the HTML that Account Engagement will render, look for the i18n placeholders and do a real-time replacement with the translations you have set up. This gives you full control over the wording and design in each language for every page.

Both HML and HandlebarsJS (by default) use double curly braces for wrapping placeholders. We’ve chosen to help differentiate between the two easily by specifying square brackets.  

Getting into the details

So as a super simple example, you can use the label [[i18n.firstname]] to have English, French, Spanish (or any other language you want) for the value {{Recipient.first_name}}.

Example of single Account Engagement form supporting 3 languages

Ok, let’s show what this can look like. Here we have a demo form that supports three languages.

Pre-work to do for your multi-language Account Engagement forms

If you’ve previously filled out the form, we will render the form in the language you specified. If you haven’t, we’ll try to use your browser’s language. Form error messages and thank you content are all translated.

Back in Account Engagement, there are a few things that need to be done.

Here’s what to do:

  1. Edit form fields – Each Form Field needs to be edited to use a label in the format [[i18n.TOKEN]] (where the TOKEN can be a field name or anything you like
  2. Edit dropdown field values – Each Dropdown field value needs to be edited to use a label in a similar format
  3. Ensure dropdown fields store language code – The Form should have a Language dropdown field that stores the language code. Language choice labels should use a label in a slightly different format. It should use [[lang.CODE]].
  4. Check submit button text – Submit button text should be edited to use a label in a similar format.
  5. Check thank you content – Thank you content should be edited to use labels in a similar format.

Add JavaScript to the form

Once you have all your labels set up, we need to actually add the JavaScript to the form.  There are a few ways you can do this and the approach will depend on just how reusable (and large) you want your JavaScript to be.

In our example, we’ve placed the JavaScript in the Layout Template, which provides a balance of re-usability (can be used by multiple forms) and maintenance (common, but not all translations for the entire site).

Ok, time for the code. I’ve split this JavaScript into three sections, but it can all be copy and pasted into a single <script> block in your Layout Template.

Define languages the form will support

First, we have a JavaScript object that defines the languages that we will be supporting, as well as the label of that language. Feel free to adjust this as necessary, just keep the structure intact.

// the supported languages by this script
const languages = {
  lang: {
    en: 'English',
    fr: 'Français',
    es: 'Español'

Add the translations

Next we have all of the translations

// the translations for each language
const translations = {
  'en': {
    i18n: {
      firstname: "First Name",
      lastname: "Last Name",
      company: "Company",
      email: "Email",
      industry: "Industry",
      hospitality: "Hospitality",
      tech: "Tech",
      submit: "Save now",
      language: "Language",
      formErrors: "Please correct the errors below:",
      fieldError: "This field is required",
      thankyou: "Thanks for submitting!"
  'fr': {
    i18n: {
      firstname: "Prénom",
      lastname: "Nom de famille",
      company: "Société",
      email: "Email",
      industry: "Secteur d'activité",
      hospitality: "Hospitality",
      tech: "Technologie",
      submit: "Enregistrer",
      language: "Langue",
      formErrors: "Corrigez les erreurs ci-dessous:",
      fieldError: "Ce champ est obligatoire",
      thankyou: "Merci d'avoir soumis"
  'es': {
    i18n: {
      firstname: "Primer nombre",
      lastname: "Apellido",
      company: "Compañía",
      email: "Correo electrónico",
      industry: "Industria",
      hospitality: "Hospitalidad",
      tech: "Tecnología",
      submit: "Guardar ahora",
      language: "Idioma",
      formErrors: "Por favor corrija los siguientes errores:",
      fieldError: "Este campo es obligatorio",
      thankyou: "Gracias por enviar"

For each token you want to be translated, you will need to add a translation for each language. Like how languages are set up, you can make any adjustments/additions you want… just keep the structure intact.

Add the main functionality to apply translations you defined

Next, we have the main functionality. This handles the actual work of applying the translations we have defined already.

function i18nForm(prospectLang) {
  document.addEventListener("DOMContentLoaded", function(event) {
    //used to convert into handlebars. Not entirely necessary if this JS is in Layout Template, but needed if JS is in Form
    const brO = '{', brC = '}';
    let formErrors = document.querySelector('#pardot-form p.errors');
    if (formErrors != null) {
      // look for error messages in the original HTML. Pardot won't let us translate that, so we will hack it a bit here
      document.querySelector('#pardot-form p.errors').innerHTML = `[[i18n.formErrors]]`;
      [...document.querySelectorAll('#pardot-form p.error.no-label')].forEach(node => { // loops through each field error
        node.innerHTML = `[[i18n.fieldError]]`;
    // stores the original HTML, or what was rendered from Pardot initially (with our placeholders)
    // also converts from using square braces (to make Pardot happy) to using Curly Braces (to make handlebarsjs happy)
    const originalHtml = document.querySelector('body').innerHTML
      .replace(/\[\[/g, `${brO+brO}`).replace(/\]\]/g, `${brC+brC}`);
    // creates the Template that Handlebars can use to generate processed (translated) HTML later on
    const processTemplate = Handlebars.compile(originalHtml);

    // get the language the Browser is using
    const browserLang = window.navigator.language.substr(0, 2);
    // console.log(`browserLang=${browserLang} and prospectLang=${prospectLang}`);
    // figure out which language we are going to go with
    let currentLangCode = prospectLang || browserLang;
    let currentLangVal = '';

    // retrieves the allowed languages, as Pardot doesn't actually use the language values we need to use, they change it to numbers (blegh)
    const pardotLanguages = new Array();
    const langNodes = document.querySelectorAll('.langChoice select option');
    [...langNodes].forEach(option => { // loops through the values in the Language Dropdown, storing lang code and numeric value for use
      let lang = option.text.replace(/\[|\]|lang./g, '');
      //console.log(`lang=${lang} and option value=${option.value}`);
      pardotLanguages[option.value] = lang;
    [...langNodes].forEach(option => { // loops through the values in the Language Dropdown, checking to see if one was selected
      let lang = option.text.replace(/\[|\]|lang./g, '');
      if(option.selected) {
        currentLangVal = option.value;
        currentLangCode = lang;
    console.log(`initially translating form to ${currentLangCode}`);

    function applyTranslations() {
      let translatedHtml = processTemplate({
      //replaces the visible HTML with the translations in place
      document.querySelector("#pardot-form").innerHTML = translatedHtml;
      document.querySelector('.langChoice select').value = currentLangVal;

      //handle when the language dropdown value is changed, translating on the fly
      document.querySelector('.langChoice select').onchange = function() { // we only want to translate to a valid language
        let selectedLang = pardotLanguages[this.value];
        if (selectedLang in languages.lang) {
          currentLangCode = selectedLang;
          currentLangVal = this.value;
          // console.log(`new language is ${currentLangVal} which is ${currentLangCode}`);
        applyTranslations(); // re-apply the translations when the value in this dropdown changes
    applyTranslations(); // apply the translations for the first time

Enable the form to detect language for known prospects

The last thing we need to do is tie this all together. Because we want to try to leverage the Prospect Language (if a known Prospect and we have a value in their Language Custom Field), we need to add just a little bit of JavaScript to each Form, in the Form’s Look & Feel as well as the Thank You content.

  // get the language the Prospect has saved
  const prospectLang = "{{{Recipient.Language}}}"; //Pardot HML  
  // kick off translations

Test and revise

All that’s left to do is test it out, and then mold this example into what you need.


Like any JavaScript examples you might find online, they are opinionated in approach. Making minor changes can sometimes break the code due to assumptions that might not be well documented/understood. I’ve left a bunch of console.log statements commented throughout the code to hopefully help you troubleshoot when things go wrong.

One of those opinions is using the “i18n” and “lang” prefixes. We think this makes the placeholders easier to read, even if it slightly complicates the JavaScript object itself. Feel free to remove this if you want, just know to make the various adjustments.

One Account Engagement form can handle all the languages you need

If your company works with audiences who speak a variety of languages, then this is the perfect solution for you to simplify the way you build forms in Account Engagement. Our new approach simplifies translating Pardot Forms, improves reporting, and offers a better user experience for a multilingual audience.

Still not sure how to approach your global marketing strategy? Then reach out to the team at Sercante for guidance along the way.

Original article: The Simple Way to Create Multi-Language Account Engagement Forms

©2023 The Spot. All Rights Reserved.

The post The Simple Way to Create Multi-Language Account Engagement Forms appeared first on The Spot.

By |2023-07-08T16:40:38+00:00July 8th, 2023|Categories: Emails & Forms, Pardot, Pro Tips, revive, Strategy|

Campaign Audience Builder: A Solution to Harness your Salesforce Data Now

Before the advent of Data Cloud and Customer Data Platforms (CDPs), businesses strived to integrate their data into their CRM to obtain a holistic view. If you’re considering another expansive platform, there’s an excellent interim solution to consider: the Campaign Audience Builder (CAB).

Where to get Campaign Audience Builder

The Campaign Audience Builder is a package on the Salesforce AppExchange developed by Lightblaze. Known for its user-friendly interface, CAB allows you to create audience segments using your Salesforce data, making it an efficient substitute or preliminary step towards a full-scale CDP solution.

Campaign Audience Builder Ease of Use

Campaign Audience Builder has a simple point-and-click interface that allows you to navigate and filter data related to the people you are trying to add to an audience.  It simply gets installed alongside your data and has a very short implementation time (I was up and running in 10 minutes).

Once installed, it really is a 3-step process of getting your first audience created and usable:

  1. Define the Criteria: as a techie myself, this was really the fun part. Connecting data and filtering the right records feels natural and familiar.
  2. Generate the Audience: This is basically running the process based on all the work you did in the previous step to see who matches. As always, it’s a great idea to spot-check that some people you expected to appear were successfully matched!
  3. Populate the Campaign: you have your list of people, it is time to put them somewhere that you can act on. This is when you choose which Campaign to use, how often the audience should be evaluated, and if people should be removed should they no longer meet your criteria.

Unlike CDPs and other types of data platforms, which require accommodating complex data relationships and aren’t always user-friendly, CAB offers a seamless alternative.

Advanced Segmentation Features in Campaign Audience Builder

Looking for Contacts that have Closed Won Opportunities with Products in a certain Product Family? Yep, Campaign Audience Builder can do that. 

Do you also want to ensure those same people don’t have a Case?  Yep, you can do that too. 

While not unlimited in its power, there’s no data scenario that you cannot segment with CAB (compared to report builder or segmentation in Account Engagement).

CAB allows you to select either a Lead or Contact as your audience driver and connect it with any related object. After defining your audience, you can populate a Campaign by creating CampaignMember records. CAB also provides controls on how frequently your audience should be evaluated and whether it should clean records that no longer meet your criteria.

With your audience defined, you can now use that information to populate a Campaign by creating CampaignMember records. You have some controls on how often CAB should be building your audience and if it should clean CampaignMember records that no longer meet the criteria.

Integration and Data Security

CAB stands out with its ability to directly publish the audience into Account Engagement (Pardot) into a static list. This feature eliminates the need to clumsily attach data to the Lead/Contact records for list population.

A key feature of CDPs is the ability to “act” on the new audience that you’ve created in downstream systems. While CAB doesn’t really integrate with a bunch of other third-party tools, it can call APEX/Flows (where you can do almost anything integration-wise).

Data security is paramount for Salesforce organizations. Moving data into other systems like data platforms or CDPs can potentially jeopardize these security controls. Since CAB operates within your Salesforce organization, it only accesses the data you can, thereby ensuring data security.

CAB may be the stepping stone you seek

In summary, the Campaign Audience Builder (CAB) offers a user-friendly, efficient, and secure way to handle your Salesforce data. It’s a practical stepping stone if you’re considering a more complex Customer Data Platform (CDP) solution. 

With its easy setup, advanced features, and commitment to data security, CAB is a smart choice for businesses looking to maximize their data management and audience segmentation without taking on a full CDP solution just yet.

Thinking about implementing CAB in your org? Contact the team at Sercante to learn more about the tool and how it will work with your overall technology strategy.

Original article: Campaign Audience Builder: A Solution to Harness your Salesforce Data Now

©2023 The Spot. All Rights Reserved.

The post Campaign Audience Builder: A Solution to Harness your Salesforce Data Now appeared first on The Spot.

By |2023-06-29T17:38:06+00:00June 29th, 2023|Categories: API & Integration, Data Management, Pro Tips, revive, Strategy|

Twilio SMS Messages and Pardot: A Complete Guide

We’ve previously talked about External Actions and External Activities, with some general ideas of how each can be applied separately. Where the real power comes in, is tying them together. In this blog post, let’s explore using a Marketing Cloud Account Engagement (Pardot) Engagement Studio Program to send an SMS message and act on the Prospect replying to it.

Installation and Configuration for Twilio SMS Messages and Pardot

Say your company is going to attend a big conference, and you want to see if there is interest for nearby Prospects (far enough in their journey with you) to meet with your team. A quick text asking if they are interested, followed up with sales outreach and/or a “book a meeting” page is a great example of sending the right message at the right time.

There’s a lot of installing and configuration needed to pull this off: 

  1. Set up Twilio for Salesforce
  2. Set up Twilio for Pardot
  3. Create a Flow to be called by External Action
  4. Configure the Marketing App Extensions
  5. Create the Engagement Studio Program
  6. Handle SMS Responses with a Flow

Set Up Twilio for Salesforce

The first thing we are going to do is to integrate Twilio with our Salesforce org. Twilio has a really good instruction video for setting things up, we highly recommend watching it and following along.


Install instructions written out can be found here:


Setup Twilio for Pardot

Once Twilio is set up for Salesforce, there are a couple of steps to enable it to work with Pardot.

  1. Add the B2BMA Integration User as a “Twilio for Salesforce” Licensed User (enables Pardot to send the SMS)
    • In Salesforce Setup, use the Quick Find window to search “Installed Packages.”
    • Click Manage Licenses beside the Twilio package, add the B2BMA Integration User
  2. Add the “Twilio User” Permission Set to B2BMA Integration User
  3. Create a “Latest SMS Campaign” field on both the Lead & Contact (Lookup to Campaign). You do not need to sync this field with Pardot, though the B2BMA Integration User should have access to edit the field values.

4. Create a Pardot custom field named “MobilePhone.” Sync this field to the Salesforce field of the same name. The Twilio Lightning Components you added when setting up Twilio for Salesforce relies on the MobilePhone field.

For the purpose of this blog post, we are not taking into consideration whether the prospect has opted in or out of SMS messages. Though, you should consider this when putting together a solution in your environment.

Create a Flow to be called by External Action

External Actions can be powered by APEX, External Services (which make APEX behind the scenes), and Flows. Whenever possible, we recommend using a Flow, as it makes it a bit easier to test and troubleshoot later on.

  1. From Salesforce Setup, use the Quick Find window to search for “Flows.”
  2. Select Create New Flow, then choose Autolaunched Flow.
  3. We need to create a few resources (variables) that will be exposed to Pardot and provide the information we need. These should all be set to:
    • Resource Type: Variable
    • API Name: varPhoneNumber (The phone number we are sending the SMS to)
    • Data Type: Text
    • Available for input: checked
  4. Repeat step 3 for the following variables:
    • varCampaignId – The Salesforce Campaign ID we want to use for tracking
    • varCrmLeadContactId – The Salesforce ID of the Lead or Contact record
    • varMessage – The text we want to include in the SMS message
    • varCampaignStatus – the CampaignMember status you want to use when sending the SMS. This is optional, you could just hard-code the flow to use “Sent”
  5. Create a couple more variables to help simplify the flow. These will be Text, and we will not be selecting the “Available for input” checkbox (they are only used within the flow)
    • varLeadId – set only if the varCrmLeadContactId is a Lead (Decision-based on prefix starting with 00Q)
    • varContactId – set only if the varCrmLeadContactId is a Contact (Decision, prefix starting with 003)
  6. The Flow itself will be composed of a few sections
    • Send SMS via Twilio
    • Update the “Latest SMS Campaign” field on Contact/Lead records with the Campaign ID if the Prospect is synced to CRM
    • Create/Update CampaignMember record for the Contact/Lead and Campaign
    • When done, your Flow might look something like this:
  7. Save and Activate your Flow

Configure the Marketing App Extensions

Next, we need to actually expose the Flow to Pardot. This is done with Marketing App Extensions in Salesforce Setup.

  1. In Salesforce Setup, use the Quick Find window to search for “Marketing App Extensions”
  2. Create a new extension named “Twilio” (don’t create a bunch of tests, currently these cannot be removed and you have a limit of 10)
  3. In the Related Tab, for Action Types click New.
    • Type Action Name: Send SMS w Campaign, type in a good API name
    • For Invocable Action, search for your newly created Flow
    • Once selected, the Action Schema will automatically fill in. We will want to edit it
      • adjust titles, set merge for varCrmLeadContactId, varPhoneNumber. This enables the system to automatically grab the values from the Prospect record.
      • remove view components for varCrmLeadContactId and phoneNumber. Since they are being auto-populated, no need to ask for the values.
      • Set varMessage, varCampaignId as required
    • Make sure “Active in Automations” is checked.
    • Once done, it will look like this (we adjusted the line spacing to make a decent screenshot:
    • Note: because you are directly editing JSON, if mistakes are made there isn’t great feedback in terms of errors upon saving. We’ve found it best to just click Cancel and try again, being a bit more careful.
  4. Next, we will create an Activity Type. This will enable us to send information back to Pardot when a Contact/Lead replies to one of our messages (we will walk you through handling this later in the post).
    • For Activity Name & API Name, simply use “FirstReply”
    • Make sure “Active in Automations” is checked.
  5. Lastly, we will enable these Actions and Activities for our Business Unit(s). Assign this Extension to your Business Unit(s) by clicking New, and choosing the Business Unit.

Create the Engagement Studio Program

Next, we will build an Engagement Studio Program that will begin to tie this all together.

  1. In Pardot, navigate to Automations > Engagement Studio
  2. Select + Add Engagement Program
  3. Add a new Action, choose “Send SMS w Campaign” (bottom of the list)
    • SF Campaign ID: provide an 18-character Campaign Id
    • Campaign Status: provide a valid CampaignMemberStatus for the Campaign
    • Message: let your creativity shine!
    • When done, it should look something like this:
  4. Next, we want to Listen for their First Reply to our Campaign. Add a new Trigger
    • Choose External Activity 
    • Extension Name: Twilio
    • Activity Type: FirstReply
    • Value: The Campaign Id you provided in the earlier step. We want these to match
    • Specify when the Trigger should be evaluated.
    • When done, it should look something like this:
  5. Next, you can decide what happens if the Prospect does reply. In our example, we add the Prospect to a Suppression List (as ideally, they are now engaging with Sales, we don’t want to keep bugging them right?

Ok, our Engagement Studio Program is done. How will it know when someone has replied to our message?

Handling SMS Responses

With the Twilio integration, we can create a Record Triggered Flow based on the “Twilio Message” object, looking for inbound SMS messages. When a message is received, we can check to see if we should take action (based on the “Latest SMS Campaign” field still having a value).

In our example, we will use the Pardot API to send an External Activity record (with some help from a free AppExchange package) to allow our Engagement Studio Program’s trigger to work, update the Campaign Member Status for the Lead/Contact and create a Task for Sales to follow up.

To begin, we will install & configure the Flow Actions for Pardot package, which makes it easy to make Pardot API calls (since you can’t natively do this within Salesforce).

Create the Flow

Next, we will create our Flow:

  1. From Salesforce Setup, use the Quick Find window to search for “Flows”, and create a new Flow
  2. Choose a Record Triggered Flow
    • Select “Twilio Message” as the Object
    • Trigger when a Record is created
    • Entry Conditions: TwilioSF__Direction__c Equals “inbound”
    • Optimize for Actions and Related Records, and Include a Run Asynchronously path.
  3. We will need a decision based on the Twilio Message being linked to a Lead or Contact. The logic we use for both Leads and Contacts will be similar, let’s start with Leads
  4. Use a Get Records element to retrieve the Lead based on the ID matching the Twilio Message’s Lead value
  5. Check to see if we need to take action on the Lead by checking if the “Last SMS Campaign” field has a value. If it does not, we can end the flow.
  6. If “Last SMS Campaign” does have a value, create a new Element: “Pardot – External Activity Add to Prospect”
    • Activity Type: FirstReply (this is what you provided when setting up the Extension earlier in the post)
    • Extension Name: Twilio (again, this was setup earlier)
    • Prospect Email: Grab the Email value from the Get Records element in Step 4 above
    • Value: Grab the “Latest SMS Campaign” value from the Get Records element
    • When done, it should look something like this:
  7. Update Lead’s CampaignMember record, create a new Update Records element
    • Specify conditions to identify records, and set fields individually
    • Update records of object: Campaign Member
    • Update records matching the CampaignId and Lead Id from the Get Records element in Step 4 above.
    • Set the Status to what you need it to be (we chose Responded). You will really want consistency across your Campaigns to reduce complexity.
    • When done, it should look something like this:
  8. Create a Task for Sales. You can do this with either a Quick Action, or with a Create Record element, it really depends on your setup and what level of detail you want to provide.
  9. After taking all of our actions, we will want to clear the “Latest SMS Campaign” field on the Lead, so that we don’t take the same actions the next time the person replies.
  10. Repeat steps 4-9 for a Contact, being sure to select the Contact’s Get Record variable in steps 5-9
  11. When done, your Flow should look something like this:

Phew, it’s all done. Give it all a try by sending your own Prospect record through the Engagement Studio Program. It will take a while once started, but you should get your Text message. Once received, check your Lead/Contact record to make sure it was stamped correctly and that you were added to the right Campaign.  

Send a reply from your phone and check your Lead/Contact record again to make sure that your Campaign Status changed, and check Pardot to see that your External Activity record was created.


As with any “internet example,” there are a few things that we skirted around to avoid extra complexities, and there are a few things that might not be obvious.

  • This solution is best run when all Prospects (entering the ESP) are synced in Salesforce.
  • Prospects that are not synced to Salesforce, if they reply Twilio will create a Lead record and it might not be synced to Pardot fast enough to receive the External Activity resulting in a break in the process.
  • Our example handled ANY SMS response in the same way. While it is possible to add keywords and build branching logic into Flows and Engagement Studio Program, the solution will get exponentially more difficult to maintain.
  • In our example, we created the Task in the Flow instead of the Engagement Studio Program. We made this choice as it can give us more flexibility in what is provided in the Task and how it can be assigned. If you really want to keep that in the Engagement Studio Program, you certainly can!
  • Twilio does charge PER SMS, so be careful when selecting your audiences, especially during testing!
  • Working with External Activities in Pardot is still somewhat limiting, in that you can only look for “a record with a specific value.” You can’t look for External Activities created in the last X days or anything like that, so it really is a “First Response” mentality.
  • If you have multiple Twilio sending numbers, you could expose this as an input variable in your Flow and External Action, so that it can be specified when sending a message.

Happy Building! And Let Us Know If You Need Help

External Actions and External Activities are a great way to leverage other solutions with Pardot. But as you saw, there is still a lot that needs to be built to glue it all together. 

We hope this guide is helpful so you can take it on and build this solution yourself. And you can always reach out to Sercante to build this solution for you if you’re ready to hand it over to the experts. Visit our contact page here to raise your hand, and we’ll get back to you ASAP.

Original article: Twilio SMS Messages and Pardot: A Complete Guide

©2022 The Spot. All Rights Reserved.

The post Twilio SMS Messages and Pardot: A Complete Guide appeared first on The Spot.

By |2022-12-30T18:51:09+00:00December 30th, 2022|Categories: Pardot, Pro Tips|

Creating a Custom Pardot Campaign Influence Model: Lessons Learned

Sometimes the standard Campaign Influence models that come with Marketing Cloud Account Engagement (Pardot) just don’t quite fit what you are looking to measure. We recently went through the exercise of creating a Custom Model, and it wasn’t quite as straightforward as we would have liked it to be. 

To save you some ramp-up time we’ve decided to share some of the things we learned. Here they are!

Lessons Learned the Hard Way while Creating a Custom Pardot Campaign Influence Model

We went ahead and created a custom Pardot Campaign Influence model and took excellent notes so you can reap all the benefits. 

Here’s what you should know before you start your own custom Pardot Campaign Influence Model project.

Simplify your Custom Model, then nail it down

There’s a lot of calculations needed in Campaign Influence, and the last thing you want to do is build this a few times as you discover exactly what you are looking for. 

Spend some time with the business and really think about which touches you really want to measure and if having them measured will drive meaningful business value. Can you explain it in 20 seconds or less? No? Your model might be too complex.

You have 2 options for integrating your Model

The simple example Salesforce provides as part of its documentation is to have a Trigger on the CampaignInfluence object, which allows you to create your records when Salesforce creates theirs.  This example is okay for demonstrative purposes, and it avoids a lot of the complexities. 

The example also works okay if the Model that you are “watching out for” creates and deletes CampaignInfluence records at the same time you need to. Though for us, often we discovered that we wanted our Model to recalculate, but it never did. This is because the default model didn’t need recalculating so no new records were created/edited. As a result, ours never had the chance to run. 

One way around this is to watch out for the b2bmaEvenDistributionModel as it has the most chance of adding/removing records, and firing off your trigger.

Another thing to consider (if you are relying on another model’s calculation to trigger your custom one) is that Salesforce doesn’t properly batch influence calculation. We learned this when turning off the Even Distribution Model and turning it back on hoping it would trigger calculation on all Opportunities. We ended up having our own Batch APEX class run to initially populate data for our new model.

If you need a little more control, you would need to introduce triggers on various objects (such as CampaignMember, OpportunityContactRole, Opportunity) looking for the events that would have an impact on your Model and cause it to recalculate. You might find luck here using Platform Events to separate the triggering event from all the processing that the Model might need, especially important as Opportunities often already have a lot of custom automations hanging around them.

Campaign Influence code runs as a special User

Salesforce’s CampaignInfluence records are created by a Special Salesforce User “Salesforce Administrator” which you can’t pick when setting up debug logs. You can find this User’s ID by looking at the CreatedById field of any of the CampaignInfluence records in your org.

Setting up a Debug log for this user is a bit more involved than normal, and needs you to manually create a TraceFlag entry referencing the special User as well as the Id of DebugLevel. We used https://workbench.developerforce.com ‘s REST explorer to create the record, and we used the SFDC_DevConsole DebugLevel allowing us to use the DeveloperConsole to check out the logs as we were testing.  A bit of setup for each debugging session, but worth it.

Break your code into debuggable chunks

We ran into a few different challenges as we were putting this together, and we found having our code broken up really sped up our debugging process. Each chunk of code had debug statements giving us an idea of the overall state / progress, which made it easy to quickly diagnose where things might be going awry.

While we aren’t yet ready to share a precise recipe, we can at least give you the ingredients we used!

  1. Build a list of Opportunity IDs of the Opportunities that need to be calculated
  2. Get all Opportunity details (including Opportunity Contact Roles)
  3. Get all needed CampaignMember records
  4. Calculate the “winning” CampaignMember records for each Opportunity
  5. Calculate the CampaignInfluence records needed from the “winning” CampaignMember records
  6. Insert final results

Plan for custom Campaign Influence Model success

Creating a Custom Campaign Influence Model is not for the faint of heart. It takes quite a bit of planning and work to put together even the simplest of Models (which might be why there’s so little out there when we tried googling for examples). 

If you are looking to take this on, hopefully these tips save you a bit of frustration and colorful language. If it still looks daunting and you need some help, we would love to have a chat!

Further Reading

Original article: Creating a Custom Pardot Campaign Influence Model: Lessons Learned

©2022 The Spot. All Rights Reserved.

The post Creating a Custom Pardot Campaign Influence Model: Lessons Learned appeared first on The Spot.

By |2022-10-19T18:44:00+00:00October 19th, 2022|Categories: Analytics & Reporting, Pro Tips, revive, Strategy|

External Actions: The Long-Awaited Pardot Feature

Alas, Salesforce External Actions for Pardot is finally here.

Until now, our options to have Marketing Cloud Account Engagement (Pardot) trigger a third-party system have been limited to either: pre-existing connectors or syncing to Salesforce and relying on a Salesforce-side integration. 

With the Salesforce Winter ‘23 release, External Actions gives us the capability to integrate into any third-party system and do cool things. It’s a far cry from having true webhooks. Though, it is a step in the right direction. 

(We’ve built something to fill in the gap. Drop us a line — we’re happy to talk details with you).

Note: This feature is available to Plus, Advanced, and Premium editions of Pardot.

The Lowdown on External Actions for Pardot

External Action allows Pardot to do things like: 

  • Send an SMS message via Twilio or MogliSMS
  • Create a new Salesforce record (such as Lead, Opportunity, any Object!)
  • Send information to your favorite Star Wars API
  • Register a Prospect in another system
  • and whatever else you dream up! 

While there are some considerations (detailed later in this post), External Actions are a great way to plow through the barriers that have prevented you from automating your entire workflow. 

It’s important to note that there’s a similarly named feature called External Activities.  With Pardot External Activities, you can receive data from third-party systems to use in Pardot. With External Actions, you can send data to third-party systems so they can do cool things.

How does a Pardot External Action work?

Once an External Action is built, it will appear as an Action option in an Engagement Studio Program. Depending on the action, you may need to provide additional information through text inputs. You can use HML Merge Tags here, too!

When the Engagement Studio Program is running and hits your action, Pardot will call into Salesforce (via API behind the scenes), and call the functionality.  It does this in a “fire and forget” manner, so there’s no error handling inside your Engagement Studio Program. It is also not “bulkified,” meaning it will make an API call for EACH Prospect. So, you may need to take the API limits of Salesforce AND your external system into consideration.

For this blog post, we built an External Action that tracks Favorite Color. 

Once you pick “Track Favorite Color” you have the ability to provide a value. In the screenshot below, we are using HML to pull this value from a Prospect’s record, though you can also provide static text if you want to say everyone’s favorite color is Sercante Green.

How can I set up a Pardot External Action?

To set up an External Action, there are 2 key pieces:

  1. You need something in Salesforce that can “do the thing” you want. It can be any of the following:
    • Autolaunched Flow
    • External Service
    • APEX InvocableMethod
  2. Marketing App Extensions have been configured inside Salesforce Setup

No-code options to configure Pardot External Actions

If you are looking to integrate with a third-party system, you might luck out on #1 and be able to leverage something built by that third-party in their Salesforce package. This could be your quickest way to being able to use an External Action.

If this isn’t available for you, first look at seeing if you can make an Autolaunched Flow that can meet your needs. This option is also great for creating Salesforce Records of any object type (keeping in mind you are limited to text input types in Pardot).

When working with another API, and if that API supports the OpenAPI protocol, you can use Salesforce External Services to hook things up. That will give you everything you need.

 The Trailhead Module on External Services is a great way to learn how to get started.

Code option to get started with Pardot External Actions

If the above aren’t an option, it’s time to break out your development skills (or work with someone who has them). We’ve got a sample APEX class here that gives you all the structural ingredients you need to make this work, you just have to fill in what you want it to actually do.

public class MyNewExternalAction {

    // Classes to be used by the Flow Designer
    public class FlowRequest {
        @InvocableVariable(label='Prospect Email')
        public String email;
        @InvocableVariable(label='Favorite Color')
        public String favColor;
        // add any other String or number-based attributes you need

    // If you are calling an External API, this would be a great
    // place to put Classes to represent the response
    public class ApiResponse {

    @InvocableMethod(callout=true label='My New External Action')
    public static void performActions(List<FlowRequest> flowRequests) {
        System.debug('Start performActions');
        // at time of writing, Pardot DOES NOT BATCH these, it's always 1
        // per batch
        FlowRequest flowRequest = flowRequests.get(0);
        System.Http http = new System.Http();

        try {
            // This is where you put what you want to do!
            // you can call another API, call other APEX
            // read & write Salesforce Objects.. Whatever you want

        } catch (Exception e) {
            System.debug('There was an issue executing the request');
            throw e;
        System.debug('Done performActions');

Once you have the functionality ready, you need to tell Pardot about it. This is done by configuring Marketing App Extensions inside Salesforce Setup.

Configuring the Marketing App Extensions

This is the “glue” that ties everything together and makes External Actions usable by Pardot. There are a few easy things to configure to make this “glue” work.

First, we need the Top-Level Marketing App Extension. Be careful with these, as you cannot delete them once created (so don’t go making a bunch of test records!).

  1. In Salesforce Setup, search for Marketing App Extensions
  2. If you don’t have one, create New
    • Provide an Extension Name and an API Name, as well as check “Active in Automations”
    • Click Save

Next, we need to enable this for Business Unit(s).

  1. With the Extension still open, go to the Related tab
  2. Click New beside Business Unit Assignments
  3. Add an assignment for each Business Unit you want this extension to be available for

Now we can create the External Action.

  1. With the Extension still open, go to the Related tab
  2. Click New beside Actions
  3. Provide an Action Name (this will be the name visible when selecting it from Engagement Studio)
  4. Provide an API Name (this does not auto-fill like you may be used to)
  5. (Recommended) Provide a description of what this Action does, since you might not remember in three months
  6. Search for your functionality. Once selected, the Action Schema will auto fill with JSON that you need to review and likely modify
  7. Review & Modify the Action Schema
    • Properties – this contains details about the parameters/values that you want to provide to the Automation.
      • type:  currently can only be “string” and “number”
      • title: the Label of the input when viewing in Engagement Studio
      • value: Allows you to provide a default value. You can use HML merge tags here!
      • Note: Sometimes when working with Flows, you might have properties that are not relevant (like flow interview id). You should remove them from Properties (assuming they aren’t an input variable that your flow requires to function)
    • View Components – this allows you to specify which properties you want to provide inputs for in Engagement Studio. Currently, definition should always be “lightning/control” and “scope” should always point to one of the properties
    • Required – a list of properties that would be required from within Engagement Studio
  8. Action Params auto fills, no changes needed
  9. When you are ready to have this available in Pardot, check the Active in Automations box.

Here’s what it would look like for our sample APEX class above. Note that we’ve chosen to only display the favorite color field in the Engagement Studio, though we are passing the Prospect’s email behind the scenes.

Save the Action and, after a few moments, it will be available for testing!

Can I use an External Action to do things in Pardot?

Imagine being able to take action on another Prospect record from an Engagement Studio Program! While not natively available within the platform, you could build this when combining External Actions with our Free package Flow Actions for Pardot. After setting up the package, you would only need to configure the Marketing App Extension to have any of our Flow Actions available as an External Action.

Create Unified Experiences with Pardot External Activities

External Actions are available with the Winter ‘23 release. These Actions, as well as External Activities, allow Marketers to automate across platforms for a more unified experience. 

How do you plan on using these features to better automate your processes? Tell us in the comments!

Original article: External Actions: The Long-Awaited Pardot Feature

©2022 The Spot. All Rights Reserved.

The post External Actions: The Long-Awaited Pardot Feature appeared first on The Spot.

By |2022-10-13T14:36:51+00:00October 13th, 2022|Categories: API & Integration, Automations, New Features, Release Notes|

How to Update iFrames & References to the Default Pardot Domain Before the Deadline

In early March, Salesforce announced changes to how it serves content via go.pardot.com. In short, this impacts your Pardot content that might be placed on your website through iFrames. 

We’ll walk you through how to find where the go.pardot.com domain is in use. Then we’ll show you how to fix it across your website.

A bit of detail on the Pardot domain challenge

Pardot is making security enhancements that can affect users of the go.pardot.com domain who use this domain for iFrames. That means you’ll have to take action by April 22, 2022, to update your website forms that meet the criteria outlined in this blog post.

Website forms with iFrames + default Pardot domain + JavaScript = pay attention

Specifically, you should pay attention to the enhancements if your website forms:

  1. Embed Pardot forms or other content inside iFrames
  2. Include JavaScript in that content
  3. Serve this content over the default Pardot domain (go.pardot.com)

The main impact will be to any Pardot form served standalone or in an iFrame using the go.pardot.com domain.

Also included are forms that make use of included JavaScript to make external calls. This includes JavaScript that:

  • Communicates from within the iFrame to the pages that contain the iFrame
  • Makes an AJAX call to a server

Examples of these kinds of calls are:

  • JavaScript that resizes the iFrame on the page to better fit the form
  • Submission of forms using reCAPTCHA
  • Changing form behavior based on changes to the email address field, such as showing a message to a prospect if they previously unsubscribed

Other impacts with assets using iFrames are possible. For example, with these new changes you will no longer be able to embed a landing page within another webpage. This change also affects JavaScript callouts on form handlers and dynamic content when served directly via an iFrame.

Preparing for the fix

There are a few preparatory steps you can do before going and making (or requesting) changes to your website.

Step 1. Set up Pardot tracker domain

If you don’t already have a Pardot tracker domain, we will need to create one. If you aren’t sure, here are steps to follow:

  1. Log in to Salesforce & Pardot
  2. Go to your Pardot Settings > Domain Management page
  3. Look for a tracker domain that is custom. It should be one that’s similar to your website address (similar to the screenshot below)

If you don’t have a custom tracker domain set up yet, our friends at Nebula Consulting have a great set of instructions here.

If you have multiple tracker domains, you will need to know which one to use.

Step 2. Enable first-party cookie tracking

While not necessarily needed for this fix, it is best to set yourself up for success for the future of cookie tracking within Pardot.

To enable first-party web tracking cookies:

  1. Log in to Salesforce & Pardot
  2. Go to your Pardot Settings, Account Settings page and click Edit
  3. Scroll down to “First-Party Tracking” and make sure all 3 checkboxes are checked
  4. Save account

Step 3. Find website pages using the go.pardot.com domain in iFrames

I mean this is the whole reason you are here right? You have a challenge and want actionable steps on how to actually solve it instead of some blogger babbling.

We’ve created a tool that can leverage your website sitemap .xml file (the same sitemap Google crawls) to look for web pages that have embedded iFrames that also use go.pardot.com as the iFrame source.

Use the form below to find the forms on your website you’ll need to update. After submitting, we’ll gather some results and email them to you after a few minutes.


Make changes to the website

With your list of pages in hand, you can begin the work of editing each page, swapping the go.pardot.com part of the iFrame “src” attribute with your new tracker domain. Try this out on one or two pages, testing out the forms to make sure nothing has broken. Then, roll it out across your site.

But… what if I can’t add a custom tracker domain?

You might ask yourself, “What if I can’t add a custom domain?” If this is you, you’re gonna be okay. 

Because of the change being made, you won’t be able to use iFrames with the default go.pardot.com domain to host standalone or embedded forms. If you plan on using a form, you’ll need to use the form on a landing page. If you have JavaScript needed for the form, it can be included in the landing page to keep the form functioning as it did before. 

If you have other assets you need in an iFrame, unfortunately you won’t be able to continue using the default domain to display them. You’ll need to get creative with these assets. Maybe convert the information into a downloadable PDF or display it as an image on a landing page.

It’s going to be okay

With new Pardot security enhancements comes a more stable marketing automation platform. But it also brings new complications — and we have your back. 

If you need further assistance with setting up a custom tracker domain, finding and fixing the use of go.pardot.com, or just a refresher on best practices, get in touch or tell us in the comments. We’re always happy to help.

The post How to Update iFrames & References to the Default Pardot Domain Before the Deadline appeared first on The Spot for Pardot.

By |2022-03-29T13:40:58+00:00March 29th, 2022|Categories: Data Management, Emails & Forms, Pro Tips, revive|

Implementing Pardot External Activities Natively in Salesforce

Pardot is delivering a whole new way to leverage your prospect data in the Salesforce Winter ‘22 release. Our earlier blog post covers this new feature and how to set up the Pardot External Activity in Salesforce so any third-party service can begin sending these activities to Pardot via API. This post explains what third-party services need to do to send these activities to Salesforce using Salesforce declarative solutions (Flow/Process builder). 

At a high level, we need to:

  • Configure Salesforce to allow our solution to call the Pardot API
  • Implement Salesforce APEX code to handle the Pardot API request
  • Add an action to a Flow to make use of our new code
  • Test

This solution is a little more technical than our post on Zapier. Once you are done, you will end up with a Flow like this:

Start Record-triggered flow

Configure Salesforce

Any time we want to work with the Pardot API, we need to “authenticate” with Salesforce in order to get an Access Token. 

First, follow the steps in our earlier blog post Connecting to Pardot API from APEX. By the end, you should have:

  • A brand new Connected App (to avoid issues, don’t re-use previously created Connected Apps unless they were created using the instructions above) 
  • Named Credential for connecting to the API 

Salesforce APEX code

To build this capability, we need to create an @InvocableMethod so that our Salesforce declarative automations can see it and call it to do our bidding.As with any code solution, there are a variety of ways that we can tackle this. The code sample below will work for readers with one Pardot Business Unit. The original code file (and APEX Tests) can be found in our GitHub repository: export-activities-sfdx

public with sharing class PardotExternalActivityPublisher {
    public static final Integer HTTP_REQUESTS_PER_BATCH = 50;
    public static final String ONLY_ONE_BUSINESS_UNIT_ID = '0UvB00000004000AAA';
    public static final String NAMED_CREDENTIAL = 'APEX_Pardot_Credential';

    public class ExternalActivity {
        // @InvocableVariable(label='Business Unit Id')
        // public String businessUnitId;
        @InvocableVariable(label='Extension' required=true)
        public String extension;
        @InvocableVariable(label='Type' required=true)
        public String type;
        @InvocableVariable(label='Value' required=true)
        public String value;
        @InvocableVariable(label='Prospect Email' required=true)
        public String email;

    @InvocableMethod(label='Send Activity to Pardot')
    public static void sendActivityToPardot(List<ExternalActivity> activities) {
        //Very quickly pass this request into the ASYNC Queue, eliminating delays for Users
        System.enqueueJob(new QueueablePardotCall(activities));

     * Handles Asynchronously firing each Activity to Pardot
    public class QueueablePardotCall implements System.Queueable, Database.AllowsCallouts {
        private List<ExternalActivity> activities;

        public QueueablePardotCall(List<ExternalActivity> activities) {
            this.activities = activities;

        public void execute(System.QueueableContext ctx) {
            //depending on how many Activities we are processing, 
            //we might hit the APEX limit of 100 Web Callouts
            List<ExternalActivity> remainingActivities = new List<ExternalActivity>();
            Integer processedCount = 0;

            for(ExternalActivity activity : activities) {
                if(processedCount < HTTP_REQUESTS_PER_BATCH ) {
                    HttpRequest req = new HttpRequest();
                    req.setHeader('Pardot-Business-Unit-Id', ONLY_ONE_BUSINESS_UNIT_ID);
                    req.setHeader('Content-Type', 'application/json');
                    // req.setHeader('Pardot-Business-Unit-Id', activity.businessUnitId);
                    // activity.businessUnitId=null;

                    String body = System.JSON.serialize(activity, true);
                    System.debug('Submitting: ' + body);
                    Http http = new Http();
                    try {
                    catch(Exception e) {
                        //we fire it off and don't do anything if there's an error
                        //probably not the best approach for Production, though it will
                        //be up to you how to handle it
                        System.debug('There was an error submitting the External activity');
                        System.debug('Message: ' + e.getMessage() + '\n' +
                                        'Cause: ' + e.getCause() + '\n' +
                                        'Stack trace: ' + e.getStackTraceString());
                else {
                    //we will process this in the next batch of Payloads
            if(!remainingActivities.isEmpty()) {
                System.enqueueJob(new QueueablePardotCall (remainingActivities));

To use this code, make sure you replace the Business Unit ID at the top of the code with your Business unit ID (to find this, navigate to Salesforce Setup > Pardot Account Setup).

For readers with multiple Pardot Business Units, remove the constant ONLY_ONE_BUSINESS_UNIT_ID and then uncomment the businessUnit lines throughout. You will need to either specify the Business Unit ID in your Flow, or you could write additional APEX to iterate through your Pardot Business Units by working with the PardotTenant object in Salesforce.

You might also want to specify how you want to handle any exceptions you get from making the Pardot API call. In our example, we simply write exceptions to the debug log.

Our APEX code does assume that the Contact has synced over to Pardot already. If you can’t make this assumption, you may consider calling a Pardot Form Handler to make sure that the prospect is in Pardot already. We have an APEX example for that too (which follows a very similar pattern, so it should be easy to merge them).

Adding an Action to a Flow

Once the APEX has been deployed, you will now be able to use it declaratively.

In our example, we have a Zoom Webinar Member (which is a Junction Object between a Zoom Webinar and a Contact).

To set this up in a Flow:

  1. Navigate to Setup > Flows
  2. Select “New Flow” or edit an existing Flow
  3. Select the + symbol to add a new Element, select “Action”
  4. In the “Search all actions” window, locate “Send Activity to Pardot”
  5. Provide a meaningful Label and Description
  6. Set your input values
    1. Extension: Enter the name of the Marketing App Extension you created in Salesforce
    2. Prospect Email: Source the email from one of the fields/variables in your flow
    3. Type: Enter one of the activities you set up and associated with your Marketing App Extension in Salesforce
    4. Value: Enter (or source from a field/variable) the unique value to identify this Activity, event IDs work great here
  7. Click “Done”
Send activity to pardot


Once all elements of your Flow are ready, testing can begin. Activate your Flow and perform the action you are using to trigger the Flow. After a couple of moments, check the Pardot prospect you are testing with, and you should now see all the information you passed through.

prospect activities

Testing is a little bit tricky, for two reasons:

  1. We are executing this functionality asynchronously, meaning a problem won’t show up in Salesforce like you are used to seeing. Debug logs will be your friend here. But don’t worry, there isn’t too much to sort through.
  2. If the Named Credential or anything else isn’t quite set up right (from step 1), Salesforce and debug logs aren’t very helpful in troubleshooting. You will have to painstakingly go through the instructions again to make sure that nothing was missed / done incorrectly.


  • The Export Activity API call only works for known prospects, and it will not work if the email address is not already associated with a prospect in your Pardot Business Unit (this is why we have the form handler in our example).
  • If you have multiple Pardot Business Units, there is no intelligence of “choosing the right one.” You need to target the right one with your APEX solution, which assumes all prospects going through this code are from the same Pardot Business Unit. As we mentioned in the APEX section, you have the flexibility to code whatever you need to handle your business case. 

 For assistance with this or other Pardot External Activities, reach out to Sercante!

The post Implementing Pardot External Activities Natively in Salesforce appeared first on The Spot For Pardot.

How to Implement Pardot External Activities with Zapier

Pardot is delivering a whole new way to leverage your prospect data in the Winter ‘22 release. Similar to webhooks, the new Pardot External Activities feature allows users to receive data from third-party systems and use the data in automations and Engagement Studio Programs. For instance, you could record when a prospect registers for a webinar, completes a survey, or watches a video.

In an earlier blog post, we describe how to set up the External Activity in Salesforce so a third party can begin sending activities to Pardot via API. This post will detail how to actually send the activities with Zapier. Similar approaches can be done with other meta-services. If you want hands-on help, we’d love to work with you.

Pardot External Activities Zapier Solution

Before we get started, it is important to note that Zapier doesn’t actually support this Pardot API request. Zapier only supports four of the many API requests possible, so we will be taking advantage of the Zapier Webhook capability to build our solution.

At a high level, we need to:

  • Configure Salesforce to allow our Zap to make API requests to Salesforce and Pardot
  • Create a new Zap which listens for a third-party event (such as registering for a Webinar)
  • Enhance the Zap to submit prospect information to a Pardot Form Handler
  • Enhance the Zap to get an OAuth token from Salesforce
  • Enhance the Zap to publish the External Activity (which works well as the Form Handler has ensured the Prospect exists already)
  • Test

Now I realize this is a lot, but don’t worry, we’ll walk through it all. Once you are done building this Zap, you’ll end up with something like this:

Configure the Salesforce Connected App

Anytime we want to work with the Pardot API, we first need to “authenticate” with Salesforce to receive an Access Token that can be used with the Pardot API. To do so, create a new Salesforce Connected App for Zapier. We highly recommend creating and testing this new Connected App by following the steps in our earlier blog post, Pardot API and Getting Ready with Salesforce SSO Users.

Once you have created your new Connected App, you should have a new Salesforce and Pardot User for the Zapier connection. Keep the user’s username, password, and security token handy for later.

In our example, we will be creating a Zap for a Zoom Webinar Registration. Due to the way Zoom Webinars are integrated with Zapier, you will need to create a Zap for each webinar, as well as creating automations in Pardot for each webinar. This may vary depending on which App you are using in Zapier.

Create a new Zap in Zapier

  1. Log in to your Zapier Account
  2. Create a new Zap and give it a name
  3. Find the third-party app that will trigger this Zap. For our example, we’ve chosen Zoom.
  4. Select your Trigger event. For our example, we have chosen “New Registrant”.
  5. Choose the Zoom account for your connection. If you haven’t already connected the app, now will be your chance!
  6. Next, (and this might differ based on your app), select the upcoming webinar you wish to integrate.
  7. Click “Test trigger”
    1. This often works best if you have a recent “event.” For Zoom webinars, it helps if you have at least 1 person who has already registered for the webinar via the Zoom registration page. In doing so, you will see sample fields and values, making the process a bit easier. 
  8. Finally, click “Continue” and you should have a nice clean “trigger.” Zapier will prompt you to make your first Action.

Enhance Zap to submit the Pardot Form Handler

Zapier now has a handle on prospects registering for the selected webinar, now we need to send this information to Pardot. 

In this first Action, we are going to send details about the person who registered for the Zoom webinar to a Pardot Form Handler. This allows us to create/update a Pardot prospect with the right field values.

Why are we using a Form Handler instead of API calls? 

  1. This approach greatly simplifies the integration by natively handling new prospect creation.
    1. Reduces sync errors for new prospects who have not interacted with a Pardot form yet
    2. More cost effective and efficient than using the Read API to create new prospects
    3. Ensures duplicates are not accidentally created
  2. The action that the person took will actually show up as Prospect Activity. This is good since they took real action and submitted a form.
  3. You can apply Completion Actions, which are not available in the API.

Make sure you have the Pardot Form Handler created and that you have the field names and the https URL handy.

  1. Continuing from the previous section, create a new Webhook Action by selecting “Webhooks by Zapier.”
    1. This step is important to establish who is registering and to make sure we associate the External Activity with a prospect. 
  1. For the Action Event, choose POST.
  2. Set up the action by filling in the following fields:
    1. URL: The https URL of your Pardot Form Handler
    2. Payload Type: form
    3. Data: Enter the Pardot Form Handler field name, and the values coming from the trigger setup earlier. Add new “rows” for each field you wish to populate in the Pardot Form Handler based on your trigger data available.
  3. Once you have finished setting up the Action, test the action, check that the Pardot Form Handler was called, and verify that the data is where it should be.
  4. Rename the Action to “Send Registration Info to Form Handler” so that it’s clear what this Action is accomplishing. 

Enhance Zap to get OAuth token from Salesforce

Now things start to get a bit tricky. Since we can’t leverage the Pardot app in Zapier, we need to do things manually. This is where we will use the Salesforce and Pardot User we set up with the Connected app in the first section.

  1. Create a new Webhook Action by selecting “Webhooks by Zapier”
  2. For the Action Event, choose POST
  3. Set up the action by filling in the fields:
    1. URL: https://login.salesforce.com/services/oauth2/token
    2. Payload Type: form
    3. Data -> grant_type: password
    4. Data -> client_id: Enter the Consumer Key from your Connected App
    5. Data -> client_secret: Enter the Consumer Secret from your Connected App
    6. Data -> username: Enter the Salesforce Username of the Pardot user we will use for API calls
    7. Data -> password:  Enter your Salesforce user’s password followed by the Security Token
  4. Once you’ve provided all the values above, Test and Review. A successful request should show values like access_token and instance_url for your Salesforce org.
  5. Rename this Action to “Get Salesforce OAuth Token” so that it’s clear what this Action is accomplishing. 

Enhance Zap to publish Pardot External Activity

Finally, we will send the External Activity to Pardot

  1. Create a new Webhook Action by selecting “Webhooks by Zapier”
  2. For the Action Event, choose POST
  3. Set up the action by filling in the fields:
    1. URL: https://pi.pardot.com/api/v5/external-activities
    2. Payload Type: json
    3. Data -> extension: Enter the name of the Marketing App Extension you created in Salesforce
    4. Data -> type: Enter one of the Activities you set up and associated with your Marketing App Extension in Salesforce
    5. Data -> value: Enter a unique value to identify this Activity, event IDs work great here
    6. Data -> email: Enter the email address that was used in step 3 of the “Enhance Zap to submit the Pardot Form Handler” section
    7. Headers -> Authorization: This one is a bit tricky to fill out. First, when you click in the text box, type “Bearer “ (with the space) and then select the Access Token.
    8. Headers -> Pardot-Business-Unit-Id: Enter the ID of the Pardot Business Unit that is associated with the Marketing App Extension. You can find the Pardot Business Unit ID by navigating to Salesforce Setup >Pardot Account Setup. (Detailed instructions here).
  4. Once you’ve provided all the values above, Test and Review. Check the Pardot Prospect for the new Activity record. This activity will appear between the Prospect Activities and Custom Fields section of the prospect page.
  1. Rename this Action to “Send External Activity” so that it’s clear what this Action is accomplishing. 


Now it’s time to test our Zap end-to-end. 

Activate your Zap and perform the action that you are capturing in the Zap’s Trigger (i.e. register for the Zoom webinar). After a couple of moments, check the Pardot prospect that you are testing with. You should now see all the information you passed through the Zap!


  • The Export Activity API call only works for known prospects, and it will not work if the email address is not already associated with a prospect in your Pardot Business Unit. This is why we have the form handler in our example.
  • If you have multiple Pardot Business Units, there is no intelligence of “choosing the right one.” You need to target the right one with your Zap, which assumes all prospects going through this trigger are from the same Business Unit. Proceed with caution and test rigorously when attempting more advanced solutions with business units.
  • Salesforce only allows five access tokens to be issued at a time. With high volumes of a triggering event, it is possible that Zaps may fail due to Salesforce Access tokens getting recycled before they can be used in the following actions (this is due to us manually getting an Access Token with the second Action).
  • Any time the user’s password and/or security token changes in Salesforce, each ZAP that uses it will also need to be updated.

These considerations are best addressed by writing your own code, which can properly address the edge cases, etc. For assistance with this or other Pardot External Activities, reach out to Sercante!

The post How to Implement Pardot External Activities with Zapier appeared first on The Spot For Pardot.

By |2021-10-15T18:27:46+00:00October 15th, 2021|Categories: Data Management, Integration, Pardot Business Units, Release Notes, Salesforce|

Using the Pardot Integration from Zoom App Marketplace

Integrating Pardot with Zoom webinars allows you to not only collect prospect activity in real time, but also track attendance, handle communications, and send sales new leads quickly and easily. Using the Zoom-native Pardot App simplifies sharing data between these two systems by allowing you to capture Zoom webinar registrants, attendees, and absentees within Pardot lists. 

In this post we’ll cover the pros and cons of this integration as well as walk you through the setup process for a webinar. 

At a high level, to integrate Zoom and Pardot you will need to:

  1. Install and set up the Pardot App from the Zoom App Marketplace.
  2. (Optional) Configure Custom Zoom Registration Fields to go to Pardot.
  3. Start creating Zoom webinars.
  4. Prepare your email notifications.

Considerations for Using the Pardot App from Zoom App Marketplace

Before we dig in, there are a few things to consider when using this native integration:

  • The integration works best when using the Zoom registration form. 
    • There is an option to use a Zoom Post URL (similar to how we think about Pardot Form Handlers). However, this option relies on the Thank You page of the Pardot Form having an additional hidden form that changes per webinar. This hidden form must be completed and requires JavaScript for a behind-the-scenes submission. That makes this option prone to human error and/or browser issues. 
  • Both email solutions leave something to be desired. You can choose between: 
    • Emails styled in Zoom with prospect-specific URLs to join the webinar. With this option you’ll lose out on Pardot tracking and personalization capabilities.
    • Your beautiful Pardot email templates with all the benefits of Pardot data, tracking, and personalization, but no Zoom webinar details or prospect-specific URLs to join the webinar. 
  • This process will not connect prospects with the associated Salesforce campaign. You’ll need additional automations if that’s part of your strategy. 
  • Each webinar requires its own setup and configuration. These take between 1-3 hours each, depending on how granular you get with automations. As a result, this integration is better suited for companies that have a low volume of webinars.
  • There is no mechanism to pull in questions and answers from webinar polls.

Install and Set Up the Zoom Integration App 

  1. Navigate to the Pardot App on the Zoom App Marketplace and sign into your Zoom account. 
  2. Select “Install” from the top right of the Pardot App listing page.
  3. Once installed, you’ll see a prompt to enter your Pardot credentials. If you are not redirected to this screen, click “Manage” from the left-side navigation, scroll down, and click “Configure”). Select “Use Salesforce SSO.”
    Use Salesforce SSO
  4. Next, install a very tiny managed package provided by Zoom. This package creates a connected app to allow Zoom to connect to your org. Click “Install Package” and install this for Admins only.
  1. While the package is installing, create a Salesforce and Pardot user for your Zoom integration. Having one user per integration helps in the event that you need to troubleshoot your Pardot org and/or integrations. Once the user is set up, log in as this user to authorize and approve the app.  
  2. Next, provide Zoom with the Pardot Business Unit ID. You can find the Pardot Business Unit ID by navigating to Salesforce Setup > Pardot Account Setup (you can access detailed instructions here).
    Enter credentials
  3. Select “Save”

Zoom and Pardot are now connected, and they are ready to work together!

(Optional) Configure Custom Zoom Registration Fields Sync to Pardot

Zoom automatically passes most of the common fields directly into Pardot. This includes: 

  • Email
  • First Name
  • Last Name
  • City
  • State/Province
  • Zip/Postal Code
  • Country
  • Phone
  • Job Title
  • Organization
  • Industry
  • Questions & Comments
  • Employees

You can also create new fields in Pardot to sync Purchasing Time Frame and Role in Purchase Process from Zoom. 

Depending on what information you are looking to capture in Pardot, you may decide you want to have Zoom pass more fields into the prospect record. A good example of a field you may wish to connect is “Join URL.” This field is a prospect-specific URL that will allow the prospect to join the webinar. 

To add this field, simply:

  1. Navigate to Pardot Settings > Object and Field Configuration > Prospect Fields. Select “+Add Custom Field.”
  2. Complete the required info and select “Create Custom Field.”
  3. Once created, go back to the Pardot App in the Zoom Marketplace and select the “Custom Field Mappings” tab.
  4. Map the Zoom Registration Field “webinar_join_link” to the Pardot Custom Field that you created. Click “Add.”

Your new custom field is now connected. Future registration captured by Zoom will pass the Zoom Webinar Join URL to your Pardot prospects. But please note, the prospect record will only have values from the latest registration.

Start Creating Zoom Webinars

You will need to configure the Pardot integration for every webinar you create in Zoom. 

  1. First, create three static lists in Pardot so Zoom knows where to send the data. You will need a:
    • Registration List
    • Attendee List
    • Absentee List

Make sure you use naming conventions so these lists are easy to find in Zoom and any Pardot automations. 

  1. Next, create or locate the webinar in Zoom. Select the webinar name to view details. 
  2. Select the “More” tab and then select “Configure” within the Integration section.
    create a zoom webinar
  3. Provide Zoom with the static lists you created in Pardot. All three lists are required.
    Provide zoom with pardot static lists
  4. Click Save

Now your lists will be kept current with the right prospects!

Prepare Your Zoom Webinar Email Notifications

Getting prospects to register for a webinar is only half the battle. Now we need to get them to attend! Registration and reminder emails are key here, and getting the right message delivered at the right time will make all the difference.

Both Zoom and Pardot can be used to send these emails, each having their own considerations.

Considerations for Using Zoom Email Notifications

Zoom email settings can be configured at a Zoom Account level (i.e. for your entire company) and at a webinar level. You can customize email templates only at the Account level, and you can’t have webinar-specific templates.

  • Registration emails can include the prospect-specific Join URL and are sent immediately after registration.
  • Reminder emails can include the prospect-specific Join URL and can be sent 1 hour, 1 day, and/or 1 week prior to the webinar.
  • Follow-up emails can be sent 1-7 days after the webinar ends.

Considerations for Using Pardot Email Notifications

With Pardot, create an Engagement Studio program or Automation Rules to automatically send out your registration, reminder, “thank you for attending” and “Sorry we missed you” emails. These automations should look for Prospect that join the webinar’s three static lists.

  • If you configured your integration to send the Zoom Webinar Join URL to Pardot, this value can be included in registration emails sent from Pardot. 
  • Reminder emails can also include the Zoom Webinar Join URL, however if the prospect registered for multiple webinars in close proximity, the Zoom Webinar Join URL on the Prospect’s record may not match the webinar you are reminding the prospect about!
  • Follow-up emails can be sent whenever you like. You can even choose to send a different email template to those who register and attend versus those who register and are absent.

Try the Sercante Connector for Zoom Webinars and Pardot

As mentioned above, if you have a low volume of webinars, this process may not be an issue, especially since the integration is the low-low price of free. However, if you’re hosting one webinar per week (or more), then this process is pretty daunting. 

If you need to scale up your Zoom-Pardot integration, check out the Sercante Connector for Zoom Webinars and Pardot

What other tools or webinar platforms are you looking to integrate with Pardot? Tell us in the comments!

Special thanks to Erin Duncan for contributing to this post.

The post Using the Pardot Integration from Zoom App Marketplace appeared first on The Spot For Pardot.

By |2021-09-23T16:49:58+00:00September 23rd, 2021|Categories: Email Marketing, Event Management, Events, Integration, Zoom|

Pardot Protected Campaign Member Statuses Solution

Get a solution for Protected Campaign Member Statuses in Pardot and step-by-step instructions for installation.

We go through all the effort of setting up beautiful Salesforce Campaigns, naming standards and maybe even a hierarchy. The next challenge in completing your beautiful work of campaign art is getting a hold on your Campaign Member Statuses for each campaign.

When a new Salesforce Campaign is created, many people aren’t just happy with the two default statuses of Sent and Responded. This prompts them to create what they think makes the most sense. Though as time goes on and as reporting starts to be needed, everyone making their own Campaign Member Statuses can be a nightmare that prevents you from getting meaningful and actionable intelligence. It would be really nice to take the guesswork out of status reporting and have a standard set of Campaign Member Statuses everyone uses consistently.

Jenna Molby posted a fantastic solution that enables you to automatically create the right Statuses on Campaign creation.

The automation here is good, though as you increase the number of Types the Flow could become a bit unwieldy.

Another thing that could be a problem comes later when other people might make changes to your carefully crafted structure. What happens if someone edits or even removes these statuses?

Install Protected Campaign Member Statuses

Protected Campaign Member Statuses is a free solution you can install and easily configure to solve this problem. It allows you to:

  1. Define the Campaign Member Statuses that should always be present on given Campaign Types.
  2. Restore the Protected Statuses on Active Campaigns should someone make changes.
  3. Create additional Statuses for specific reasons.
  4. Override by authorized users on a per-Campaign basis.

I don’t want the details, just let me install it

(Don’t worry. Keep reading to learn exactly what’s going on inside.)

We have an Unlocked Package you can install that sets up the application.

Get Started

Once installed, you need to define your Protected Statuses. This is done with Custom Metadata Types.

  1. Login to Salesforce Lightning, and go to Setup.
  2. Navigate to Custom Metadata Types, and click Manage Records for Protected Campaign Status.
    Pardot Protected Campaign Member Statuses
  3. To create your first ones, click New
    Pardot Protected Campaign Member Statuses
  4. Fill in the various fields.
    • Label: Used in the List of Campaign Statuses in the Setup view in step 3 above. Recommended convention:  TYPE-STATUS
    • Name: This is an API name that can be used by developers. Not required by this package. Recommended: let this autofill after you type in the Label.
    • Campaign Type: This is the actual value for the Campaign’s Type field.
    • Protected Status: This is the Status value that will become protected.
    • Is Default: Select this if this Status should be the default (please pick only 1 per Type).
    • Is Responded: Select this if this Status should be marked as Responded.
    • When complete, your screen may look something like this:
      Pardot Protected Campaign Member Statuses
  5. Click Save (or Save & New) and repeat a whole bunch.
  6. Lastly, time to set up a scheduled job to restore deleted protected statuses.
  7. Back in Setup, go to Apex Classes and click Schedule Apex.
    Pardot Protected Campaign Member Statuses
  8. Fill in the few fields.
    • Job Name: give this a nice descriptive name so you remember what it is in 3 months.
    • Apex Class: SL_ProtectedCampaignStatusJob
    • Frequency: set this to what works for you. We recommend running this daily during off-peak hours.
    • Start: today
    • End: some time in the distant future
    • Preferred Start Time: off peak hours
    • When complete, your screen may look something like this:
      Pardot Protected Campaign Member Statuses

You are good to go once you have provided your statuses. Give it a whirl by creating a new Campaign with the Type you have set up. Then take a look at the statuses already created.

Campaigns with Types not already set up will keep the default two statuses that Salesforce creates.

That’s cool. What’s behind the curtain?

To accomplish this, we leverage a few cool tools available to us:

  • Custom Metadata Types: Allows the Protected Statuses to be treated like normal Salesforce metadata and can be deployed around like any other metadata (changesets, insert devops tool here)
  • Campaign Custom Field: Has_Protected_Campaign_Member_Statuses__c is automatically checked by the solution if a Campaign is created and there are Custom Metadata Type records that specify this Campaign’s Type. It is also what allows the rest of the code to keep the statuses intact. You can clear the checkbox for this field to make changes to the statuses if you need to. However, you can’t enable protection afterwards.
  • Change Data Capture: We turn this on for CampaignMemberStatus so we can detect edits to statuses and then fix the records after-the-fact. Sadly we can’t (yet?) put any triggers on CampaignMemberStatus (which would have been ideal).
  • Triggers: yea these have been around for a while and are quite handy. We use them to kick off the automation that we’ve built when a Campaign is created. We also use them to watch for Campaign Member Status edits (through the ChangeEvents from Change Data Capture) so we can set things right afterwardsd.

If you want even more details, check out the Github project where you can see all the inner workings of what is going on.

Further Reading

Here are some resources you can use to learn more about Salesforce Campaigns and how they work in Pardot:

The post Pardot Protected Campaign Member Statuses Solution appeared first on The Spot For Pardot.

By |2021-07-16T18:27:52+00:00July 16th, 2021|Categories: Campaigns, Data Management|