Welcome to another “Automate This!” In this live-streamed video series, we cover all things automation, from use cases and best practices to showcasing solutions built by Awesome Admin Trailblazers like you. With automation, you can remove manual tasks, drive efficiency, and eliminate friction and redundancy. In this episode, see how Anne Powell uses screen flows to allow new Experience Cloud portal users to self-register instead of using the standard self-registration component or Apex.
Why use Flow to automate self-registration for portal users?
Allowing guest users to self-register on your Experience Cloud portal can be an incredibly powerful, efficient, and time-saving tool. It also helps you as an admin. You no longer have to go through the process of manually creating a new account, contact, and user record for each customer or partner that wants to access the portal. Plus, it makes it much easier for portal users to gain access quickly.
While you can use the standard self-registration tool the Experience Cloud Administration settings provide, both the standard and customizable version only allow you to gather limited information on the user. Typically, if you wanted more, you would have to do it through Apex coding, which has its pros and cons but is not easily configurable by just any admin.
That got me thinking. What if we could do this through clicks, not code? What if we could automate self-registration, gather more information from users, and expand self-registration functionality past the creation of account, contact, and user records?
That’s why we do it through Flow.
Self-registration using a screen flow
Self-registration via Flow can actually be done with either a screen flowor a record-triggered flow. For this particular use case, I’ll show you a solution using a screen flow. If you want to use a record-triggered flow or a different kind altogether, the main elements of the screen flow should lead you in the right direction as far as how to do it. Just note that each kind of flow has its own complexities that come with it.
The main elements of the self-registration flow contain the following pieces.
Gather user information
Check for an existing user record
Check for available licenses
Create the user’s unique username and nickname
Create the account, contact, and user records
Once you have these main components, you can expand as much as you want. For example, creating campaign member records for specific campaigns if they work in a particular type of role; requiring a user to input certain information before they’re ready to sign up; or including other members in an account if they sign up with more than one person.
But to start us off, I’ll just expand my use case a little bit by collecting both the user and company information. The first thing I do is go into the flow’s Version Properties and set it to run in System Context Without Sharing—Access All Data. Guest users won’t have a profile to control which objects and fields they can access. So, setting it to System Context Without Sharing will allow them to access what they need to when creating the account, contact, and user records, as well as any checks that need to happen prior.
Gather user information
The first element I create in the flow is the screen where new users input their information for record creation. In this particular example, I gather some basic contact and company information, but you can always make it more or less complex depending on your needs. Note: You always need their first name, last name, and email in the very least. If you aren’t gathering their Company or equivalent Account information, you’ll need to create an Account Name formula later on when creating the Account record to input something in that required Name field.
When creating records later on, I have to make sure to map any required fields and follow any system or object validation rules. This means that I have to validate user input to match validation rules and requirements on any Screen element that gathers user input. Some commonly missed system validation rules are character limits.
Check for existing user
Once I have the new user’s email, I need to check whether it already has a user record associated with it inside my org.
To do that, I start with a Get Records element called Get Useron the User object with a filter to only obtain the first record whose email matches the email inputed by the user. I choose the IDand IsActivefields to store in the record and let Salesforce do the rest, since those are the only fields I need to do my check.
Using a Decisionelement called Existing User?, I create a New Useroutcome that checks whether the User IDfrom the Get Userelement is null,which means it did not find any records that matched the email address provided. I rename the Default Outcometo Existing User because if the Get Userelement does return a record, it will not be null and go down the default path.
If the flow goes down the Existing Userpath, I check whether the found user is an active user or not using a Decision element called Active User?. The Inactive Useroutcome checks if the Get User element’s Activefield is equal to False, which means the found record is not active. I rename the Default Outcometo Active User because if the Active field from the Get Userelement is equal to True instead, it will go down the default path.
If the flow goes down the Inactive Userpath, it will use an Update Recordselement nameed Reactivate User using Specify conditions to identify records, and set fields individuallyon the Userobject. I add a filter Id equalsthe User IDfrom theGet Userelement, and I set the IsActivefield to True, which will reactivate the portal user and send them a reset password email automatically.
I highly recommend adding a Screen element after the Update Records element with display textthat lets the user know they have been reactivated—and to check their email for the password reset, to use the forgot password tool, or to try logging in with their old password. Otherwise, add an End element to stop the flow from moving forward. Once they reset their password, they’re able to log in using their previous account and no duplicate records are created!
If the flow goes down the Active Useroutcome on the Active User?Decision element, a Screen element with display textlets the user know their user record has been found, and to try logging in again or using the forgot password tool which I recommend doing as well. After that, I use an Endelement to stop the flow right there.
Perform a license check
If the flow goes down the New Useroutcome in the Existing User?Decision element, I need to make sure I have enough licenses in my org to actually create a new portal user. First, I create a Get Recordselement called Get Licenses on the User Licenseobject with a filter to get the first record that has the Nameof the licenses I want to use, which can be whichever portal license you want to use (Partner or Customer). I choose the ID, TotalLicenses, and UsedLicensesfields and let Salesforce do the rest to store only the information I need from this record.
I use a Decision element called Licenses Available? to actually conduct the license check with Available outcome that checks whether the Used Licenses field from the Get Licenses element is less than the Total Licenses field from the same element. I rename the Default Outcome to Unavailable since if the Used Licenses are greater than or equal to the Total Licenses in the org, that would mean there aren’t any free licenses to give out.
If the flow goes down the Unavailabledefault outcome in the Licenses Available?element, a Screen element with display textlets the user know that the system cannot create a new user at this time and to contact support for more assistance. I then use an Endelement to stop the flow there and prevent any unnecessary records from being created or potential errors from happening.
Find a unique username and nickname
Once I confirm that this is a new portal user and I have enough licenses available to create them, I have to figure out how to give them a unique username and nickname. Salesforce requires users to have a unique nickname within their own org and a unique username across all Salesforce orgs. When creating a new user the standard way, you’re able to check if the username or nickname you inputted is truly unique and valid, but we aren’t able to do that with Flow. The next best thing we can do is create a naming convention that’s as unique as possible using formulas.
The first two (2) formulas we need to create are the Base Username and Base Nickname text formulas. Their actual formulas and breakdowns are:
for_BaseUsername (Text Formula)
LOWER(LEFT(SUBSTITUTE(LEFT({!First_Name}, 1) + "." + {!Last_Name}, " ", ""), [Insert Character Limit]) + "@[Input Unique Domain Name Here]")
The first half, which is specific to the user, is simply taking the user’s first name initial and last name with a period in between.
The LOWERfunction is there to ensure that the entire username will be lowercase, but this is not required.
The first LEFTfunction is to ensure that the first initial, period, and last name combination remains within 60 characters. The maximum character limit for the Username field in Salesforce is 80 characters, meaning my formula needs to adhere to that limit. I don’t want to shorten my unique domain name, so I count how many characters are within my domain name, subtract it from 80, then use that as my character limit for the first half of the formula.
For example, if I use “@automatethiswithanne.com” as my domain name which is 25 characters, my character limit for the first half of the formula would be 55 characters. To be safe, I would make it 50characters, rounding down just a bit.
The SUBSTITUTEfunction is to ensure that if the user included a space as part of their first or last name, such as “Daniel Christopher”, it will be removed from the formula altogether to prevent errors from occurring.
The second LEFTfunction is to get the first character of their first name to start the username off. From there, we add a period and the last name.
The second half and most important bit of the formula would be the + "@[Input Unique Domain Name Here]". All Salesforce usernames are required to be in email format but aren’t required to be an actual email domain. So, I use that to my advantage and put "@automatethiswithanne.com", replacing the [Input Unique Domain Name Here]bit.
This domain can be whatever you want, but make it especially unique to your own org that the chances of it being taken by someone else are extremely low. If you have a company domain name, you can use that here as well, as long as any employees with a company email are inside that org and not other orgs.
This formula follows the same pattern and reason of the first half of the for_BaseUsernameformula. The only difference is there’s no period in between the first initial and last name, and there’s a character limit of 40 characters which is the limit for the Nickname field. Nicknames also do not require domain names, so that’s been excluded here.
Now that I have my base formulas made, I create a Get Recordselement called Get Matching Usernames and Nicknames on the Userobject once again. However, this time I’m getting all the records that have a username that ends with the for_BaseUsername formula OR a nickname that ends with the for_BaseNickname formula. I choose the ID, Username, and Nicknamefields and let Salesforce do the rest, since that’s the only data I need to store. If there are any usernames or nicknames that match our new user’s base username or nickname, this will find it.
I create a Loop on the collection that the Get Matching Usernames and Nicknameselement creates to check for username and nickname availability with each record it finds.
Next, I use a Decisionelement called Username Availability.The Username Unavailableoutcome checks whether the current item in the loop’s Username field ends withthe for_BaseUsernameformula. If it does, that means if the current record in the Get Matching Usernames and Nicknameshas already used the initial username, we would otherwise assign to the new user. I rename the Default Outcometo Username Available since if it doesn’t end with the formula, the for_BaseUsernameformula is still unique.
At this point, I create a new Number Variable called var_Username Counter with a default value of zero (0) and zero (0) decimal placesfor use in the next element. This is going to be my Username Counter, which I will explain next.
If the flow goes down the Username Unavailableoutcome, it will go through an Assignmentelement called Username Counter that will add one (1) to the var_UsernameCounter. This is for use in the formula that will be the new user’s final unique username.
Once it goes through that for the username, I repeat the process for the nickname, creating a Decisioncalled Nickname Availability with the Nickname Unavailableoutcome and the Nickname Available Default Outcome, a Number Variablecalled var_NicknameCounter, and an Assignment element called Nickname Counter. The only difference is that I am replacing “username” with “nickname.”
Why not combine the username and nickname checks together? This is just an added step to foolproof the self-registration flow. Typically, the username and nickname go hand in hand, but just in case, I separate the Decisions within the Find Username and Nickname Loop. It doesn’t matter which Decision goes first, though.
The Username Counter and Nickname Counterelements are crucial in finding a truly unique username as they will determine the formula for the final username and nickname, which are:
This is largely similar to the base username and nickname formulas, and will function the same as well if that base formula is unique. The only difference is the IFfunction found here, which will add whatever number the counter variables are equal to at the beginning of the username or nickname if it’s greater than zero (0).
Here’s an example of what this Find Username and Nickname Loopdoes. If there’s an existing user in the org by the name of Anne Powell, their username would be “a.powell@automatethiswithanne.com” and their nickname would be “apowell”. If there’s a new user that wants to sign up by the name of Alice Powell, their base username would be “a.powell@automatethiswithanne.com” as well and their nickname would be “apowell”, too. That would result in an error since they’re not unique. Now, if we used the counter and the final username and nickname formulas, Alice’s final username would be “1a.powell@automatethiswithanne.com” and their nickname would be “1apowell”, which would be unique!
Create the user
Now that we have our unique username and nickname, it’s time to create new user records! For any records I’m about to create, regardless of the object, I have to make sure to map any required fields.
I use a Create Recordselement called Create Account on the Accountobject and map any required fields on the object, such as the Namefield. I also make sure to set the OwnerIdfield to the User ID of someone who has a Rolewithin the org. If I don’t do this, the flow will get an error, since Account Owners of portal users are required to have a role and system administrators do not have a role assigned by default. The Account Owner in this flow can be anyone you want as long as they have a role assigned to them on their user record.
I use a Create Recordselement called Create Contact on the Contactobject next, making sure to map any required fields. The main field I want to set here is the AccountIdfield with the value as the AccountIdfrom the Create Accountelement I just created. If I don’t set this properly, I’ll get an error when trying to create the user record, as it will create a standard account record to be associated with or none at all. It would then not be able to associate the proper Account Owner to the portal user’s account record.
Before creating the user record, I first need to use a Get Recordselement called Get Portal Profile on the Profileobject that will get the first record whose Nameis equal to the profile name of the one I want to assign to new portal users. I only want to store the IDfield and let Salesforce do the rest, since it’s the only field I’ll use.
It’s best practice to use a Get Records element instead of just using profile ID manually because the profile ID provided may not exist in production (for example, it’s mistyped or the ID provided does not match the profile ID).
The final and biggest step is to create the actual user! To do this, I use a Create Recordselement called Create User on the Userobject. There are several required fields on the User object, including:
Alias: I create a text formula (for_Alias) for this which is:
Locale(LocaleSidKey): This corresponds to language and dialect.
Language(LanguageLocaleKey): This corresponds to language and dialect.
Email Encoding(EmailEncodingKey): This corresponds to email encoding and can typically be set to UTF-8.
TimeZone(TimeZoneSidKey): This corresponds to their time zone.
Currency (CurrencyIsoCode): This is only required if you have multiple currencies enabled.
ProfileId: Use the ProfileIDfrom the Get Portal Profileelement.
IsActive: This should always be True.
ContactId: Use the ContactIdfrom the Create Contactelement.
After the user record has been created, I use a Screenelement called Confirmation Screen with display textthat notifies the user of successful creation and to check their email to complete their registration. Sometimes, the email may also go to their spam folder, so be sure to include that as a note as well.
Debug the self-registration flow
As best practice, always debug any flows created to ensure they work properly and as intended. There are a few special notes to consider when debugging self-registration flows.
Every time you debug the flow and it runs through the entire process, you’re creating a new User, Contact, and Account record that cannot be deleted. You can deactivate it, though.
You would need to append your email each time you want to run through the process entirely since the user check matches via email. For example, if I successfully created a user with the “radianncecreative@gmail.com” email, then I would need to do “radianncecreative+1@gmail.com” to make it different and still receive the test email.
You cannot debug the flow as a guest user who doesn’t have a profile, so you cannot know how this would work for a new user trying to sign up. The only way to test this would be to activate it and publish the flow to the portal for true testing.
Grant guest user access to the flow
Once the flow is Activeand you’re ready to use it on the portal, you need to navigate to All Flows in Setupand select Edit Access on the self-registration flow’s dropdown. Enable Override default behavior and restrict access to enabled profiles or permission sets and add any profiles that need access to this flow to the Enabled Profilescolumn. This should include the System Administratorprofile or whichever profile you use at the minimum for testing purposes. Then, click Save.
This allows you the option to grant the portal guest profile access to the flow, but it doesn’t automatically add it. To ensure access, navigate to the desired portal’s Builder, open the Settings, and in the Generaltab, under Guest User Profile, select the hyperlinked profile.
In the portal’s special guest profile, click to Edit the Enabled Flow Accesstab, move the self-registration flow into the Enabled Flowscolumn, and click Save. Now, portal guest users can access and use the self-registration flow even if they’re not a Flow user!
Distribute the flow
The last step in configuring self-registration is to set up the portal and distribute the flow!
In the desired portal’s Builder, select which page you want the self-registration flow to be on. This can either be a new custom page or an existing one, such as the standard Registerpage that comes with the initial site creation. If you use a custom page, make sure to set the Page Accessto Public within its Propertiesso that guest users can access it while unauthenticated.
On the desired page, add a Flow Componentand select the self-registration flow. To make it look a bit more branded, you can also add some rich text to display your company logo.
Since we’re using the standard Registerpage, check the box to Override the default theme layout for this page in its properties to a new theme that removes the header and allows the component to be distributed better with a different Content Layout.
Navigate to the Login page next and click into the Login Form. The Self Register URLshould point to whatever URL the page that houses the self-registration flow is, which can be found within the page’s properties.
Once satisfied with how it looks, make sure to Publish the portal site so far. If you’ve already published the site with the pages holding the self-registration flow before, even if they didn’t have the flow previously, you don’t have to publish it again.
Moving to the portal’s Administration page, go to the Login & Registration tab under the Login Page Setupsection. Set the Login Page Typeto Experience Builder Page and select the page that should be the login page. If you want to use the standard login page already on the portal, select login.
Next, go to the Registration Page Configuration section and enable the Allow customers and partners to self-register. Select Experience Builder Page as the Registration Page Typeand choose the proper page that houses the self-registration flow. Note that the magnifying glass will only display pages that have been published.
Leave the Profile and Accountfields blank since the flow will be handling this process, and click Save.
Lastly, access the Emails tab in Administrationand ensure the Send welcome email checkbox is enabled besides Welcome New Member. This will ensure the new user gets the password reset email when they’re first created so they can actually access the account.
Once that’s saved, the self-registration flow is done! You can expand this flow as much as you want, and I’m sure it can be optimized much more. Consider it a living, breathing template that you’re now a part of.
New portal users can go to your portal site and register all by themselves without the help of a Salesforce Admin. You’ve saved yourself and any new users a whole lot of time and effort. Way to flow!
Welcome to another “How I Solved It.” In this series, we do a deep dive into a specific business problem and share how one Awesome Admin chose to solve it. Once you learn how they solved their specific problem, you’ll be inspired to try their solution yourself! Watch how Deanne Walters uses Flow to create […]
Welcome to another “How I Solved It.” In this series, we do a deep dive into a specific business problem and share how one Awesome Admin chose to solve it. Once you learn how they solved their specific problem, you’ll be inspired to try their solution yourself! Watch how Dee Ervin searched unsearchable field data […]
Welcome to another “Automate This!” In this live-streamed video series, we cover all things automation, from use cases and best practices to showcasing solutions built by #AwesomeAdmin Trailblazers like you. With automation, you can remove manual tasks, drive efficiency, and eliminate friction and redundancy. In this episode, let’s see how Michelle Hansen uses reactive screen […]