Determining Contacts Who are Partner Portal Users
If your organization has a community or portal built on Experience Cloud with authenticated portal users, keeping track of which Contacts in your Salesforce org have been granted external User licenses is not exactly straightforward.
There is no out-of-the-box “Is Portal/Community User?” indicator field on the Contact record to see from a list view or report which Contacts have external User licenses. This is exactly what many organizations need, though, so let’s look at how to build one using a custom field and a simple flow.
For simplicity, this article will work through the business relationship case of a Partner Community portal, but the same concepts apply if your org uses a Customer Community; the only differences will be the name of the User profile given to the external users and the labels of the quick action buttons on the Contact record page to enable/disable their User record.
The Problem with Portal Users’ Contact Records
To understand the gap, let’s first review the process for enabling community/portal users:
Every user who will authenticate into your Experience Cloud site must first be entered as a Contact record in your org. The Contact record must also be related to an Account record.
The order of operations dictates that the Account record must first be enabled as a Partner Account, and then the Contacts related to that Account can be enabled as Partner Users. Enabling the Account and Contact as Partner Accounts and Users is done through quick action buttons on the respective record pages.
For more information about creating Experience Cloud users, see this Salesforce help article.
When an Account is enabled as a Partner Account, a checkbox field called “isPartner” is set to true which allows list view filtering and reporting on Accounts that are enabled for the community —wonderful!
However, as we’ll see next, the same type of indicator does not (yet) exist on Contacts. There is this idea and this other idea on the IdeaExchange that have both been marked “Delivered”, but community members believe that the functionality is still missing.
Once a Contact is enabled as a Partner User (by clicking the “Enable Partner User” button on their Contact record page), a User record is created for that Contact with a specific external User profile — the profile that corresponds to the type of Experience Cloud licenses in your org. In the case of a Partner Community, the profile is “Partner Community User”.
As always, it is recommended to clone this standard profile and customize it for your org. Then assign this cloned profile during the Partner User enablement from Contact records.
So, after enabling Partner Accounts and Contacts we will have a list of Users who have the cloned Partner Community User profile. One very helpful field that is unique to the User record page for Partner Users is a Contact lookup field which links to the User’s Contact record, and this will be integral to our later flow. We can easily run reports or list views on the User object to get a list of Partner Community Users by checking for either the profile or the presence of a Contact in that lookup field.
What if we want to see the list of Contact records who are Partner Users from a Contacts list view or report, though? This should be an easy ask since Contacts are clearly related to their Community User record via the Contact lookup field on the User detail page. However, as with all lookup fields, the relationship only goes in one direction, from the User to the Contact.
Yes, each individual Contact record has quick action buttons that will tell us the state of portal enablement, assuming they have been added to the page layout. If the “View Partner User”, “Disable Partner User”, and “Log in to Experience as User” buttons are present, instead of the “Enable as Partner User” button, then the Contact has already been set up as a Portal User.
However, needing to look at Contact record pages one by one to determine this information is not scalable.
The Solution with Custom Contact Fields and Flow
Enter two custom fields and a simple flow. More specifically:
- A custom User lookup field on the Contact object
- A custom formula checkbox field on the Contact object (optional)
- A record-triggered flow that fires when a User is created and the ContactId field is not null
First, create a custom User lookup field on the Contact object. I like to name this Portal_User__c. This will be set by our flow with the User ID of this Contact’s external User record.
Additionally, there is an option to create a formula field on the Contact object with a checkbox return type. This checkbox will be true if the User record referenced by Portal_User__c is active and false if either there is no related User or the User is inactive. This field is not required for the solution, but aids visibility into the status of the related Portal User.
In our simple flow, the Portal_User__c field will be populated with the User ID of the external User record when the User record is created. If the User is later deactivated the Contact record will still have the User ID in the Portal_User__c lookup field, so the presence of an ID in the Portal_User__c field does not necessarily mean that the Contact is an active external user. Using this checkbox as an indicator of the active status of the external User record is a simple and impactful addition.
Let’s name this formula checkbox: Is_Active_Portal_User__c
The formula is simple: Portal_User__r.IsActive
You may be wondering why not create another solution with flow that just clears the Portal_User__c lookup field if the User record is deactivated. Well, that is a design decision that is up to your organization. I prefer not to clear the lookup field since it may still be helpful to have a link to the User record even after it has been deactivated.
Now let’s build the flow. Create a Record-Triggered Flow optimized for Actions and Related Records. Trigger the flow when a User record is created with entry criteria of “ContactId is not null”.
As we learned above, when a Partner User record is created, the ContactId field is filled in with the Contact ID of the related Contact record, so setting this entry criteria uniquely targets external User records that are created and not all User records.
A quirk of Data Manipulation Language (DML) operations in Salesforce is that certain objects cannot be updated in the same transaction. Users and Contacts fall into this category of conflicting objects, so in order to update a Contact record upon creation of a User record, we have to add a slight time delay to our flow in order to separate the transactions. Add a scheduled path to the start element to run 1 minute after the User is created.
The “Run Immediately” path will not have any connected elements.
Connect an “Update Records” element to the “Run 1 Minute After User is Created” path. For “How to Find Records to Update and Set Their Values” select “Specify conditions to identify records, and set fields individually”.
Update Contact records where Id = Record > ContactId. This means: find the Contact record that is referenced by this User’s ContactId field, i.e. the Contact from which this external User was created. For “Set Field Values for the Contact Records” we are only setting our custom Portal_User__c lookup field: Portal_User__c = Record > UserId
That’s it! Here’s the entire flow:
Save this. Then give your flow a clear name and helpful description, and activate. Now anytime a Contact record is enabled as a Partner User, the creation of the Partner User record will trigger this flow and after a 1-minute time delay, the User Id will be copied back to the custom Portal_User__c lookup field on the Contact record.
Since this flow only runs when new external Users are created, if you already have active Portal Users and you’d like to back-fill this Portal_User__c lookup field on the Contacts for those Users, then I suggest performing a data export and then doing an update through your favorite data loading tool.
Export all Users with the ContactId filled in, exporting:
UserId
ContactId
then update Contact records mapping the UserId to the Portal_User__c field.
List views and reports could be created off this Portal_User__c lookup field as it is, but remember that this field will be populated regardless of the active status of the User. If you decided to also create the formula checkbox field Is_Active_Portal_User__c then this checkbox can be used to generate list views and reports of the current list of Contacts who have active community portal User credentials.
What are some of your favorite simple but effective uses for flow to build out gaps in current platform offerings? Tell me about them on the Salesforce Trailblazer Community, @Lindsey Hewett.