Headshot of Anne Powell next to text that says, "Automate This! — Allow New Experience Cloud Users to Register with Flow."

Automate This! — Allow New Experience Cloud Portal Users to Self-Register with Flow

By

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 flow or 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

An overview of the self-registration flow.

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.

The flow’s version properties which runs in System Context Without Sharing—Access All Data.

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.

A sample screen component gathering the new user’s information.

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 User on the User object with a filter to only obtain the first record whose email matches the email inputed by the user. I choose the ID and IsActive fields to store in the record and let Salesforce do the rest, since those are the only fields I need to do my check.

A Get Records element on the User object to find a matching user with same email.

Using a Decision element called Existing User?, I create a New User outcome that checks whether the User ID from the Get User element is null, which means it did not find any records that matched the email address provided. I rename the Default Outcome to Existing User because if the Get User element does return a record, it will not be null and go down the default path.

A Decision element with a New User outcome that checks if the Get User record’s User ID Is Null.

If the flow goes down the Existing User path, I check whether the found user is an active user or not using a Decision element called Active User?. The Inactive User outcome checks if the Get User element’s Active field is equal to False, which means the found record is not active. I rename the Default Outcome to Active User because if the Active field from the Get User element is equal to True instead, it will go down the default path.

A Decision element with an Inactive User outcome that checks if the Get User record’s Active field is equal to False.

If the flow goes down the Inactive User path, it will use an Update Records element nameed Reactivate User using Specify conditions to identify records, and set fields individually on the User object. I add a filter Id equals the User IDfrom the Get User element, and I set the IsActive field to True, which will reactivate the portal user and send them a reset password email automatically.

An Update Records element that updates the IsActive field to True on the Get User record.

I highly recommend adding a Screen element after the Update Records element with display text that 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 User outcome 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 End element to stop the flow right there.

Perform a license check

If the flow goes down the New User outcome 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 Records element called Get Licenses on the User License object with a filter to get the first record that has the Name of 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 UsedLicenses fields and let Salesforce do the rest to store only the information I need from this record.

A Get Records element on the User License object filtered by its Name.

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.

A Decision element to check if the used licenses are less than the total used licenses.

If the flow goes down the Unavailable default outcome in the Licenses Available? element, a Screen element with display text lets 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 End element 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 LOWER function is there to ensure that the entire username will be lowercase, but this is not required.

The first LEFT function 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 50 characters, rounding down just a bit.

The SUBSTITUTE function 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 LEFT function 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.

As an example, this formula built out could be:

LOWER(LEFT(SUBSTITUTE(LEFT({!First_Name}, 1) + "." + {!Last_Name}, " ", ""), 50) + "@automatethiswithanne.com")

Now, if I were to sign up as Anne Powell, my for_BaseUsername would be a.powell@automatethiswithanne.com.

  • for_BaseNickname (Text Formula)
LOWER(LEFT(SUBSTITUTE(LEFT({!First_Name}, 1) + {!Last_Name}, " ", ""), 40))

This formula follows the same pattern and reason of the first half of the for_BaseUsername formula. 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 Records element called Get Matching Usernames and Nicknames on the User object 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 Nickname fields 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.

A Get Records element that finds all records with usernames or nicknames ending with the base username and nickname formulas.

I create a Loop on the collection that the Get Matching Usernames and Nicknames element creates to check for username and nickname availability with each record it finds.

A Loop element on the Get Matching Usernames and Nicknames collection.

Next, I use a Decision element called Username Availability. The Username Unavailable outcome checks whether the current item in the loop’s Username field ends with the for_BaseUsername formula. If it does, that means if the current record in the Get Matching Usernames and Nicknames has already used the initial username, we would otherwise assign to the new user. I rename the Default Outcome to Username Available since if it doesn’t end with the formula, the for_BaseUsername formula is still unique.

A Decision element that checks if the current item in the loop’s Username ends with the base username formula.

At this point, I create a new Number Variable called var_Username Counter with a default value of zero (0) and zero (0) decimal places for use in the next element. This is going to be my Username Counter, which I will explain next.

A number variable with a default value of zero and zero decimal places.

If the flow goes down the Username Unavailable outcome, it will go through an Assignment element 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.

An Assignment element that adds one to the username counter variable.

Once it goes through that for the username, I repeat the process for the nickname, creating a Decision called Nickname Availability with the Nickname Unavailable outcome 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.”

A Decision element that checks if the current item in the loop’s Nickname ends with the base nickname formula.

A number variable with a default value of zero and zero decimal places.

An Assignment element that adds one to the nickname counter variable.

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 Counter elements are crucial in finding a truly unique username as they will determine the formula for the final username and nickname, which are:

  • for_Username
LOWER(IF({!var_UsernameCounter} > 0, TEXT({!var_UsernameCounter}), "") + LEFT({!First_Name}, 1) + "." + {!Last_Name}, " ", ""), [Insert Character Limit]) + "@[Input Unique Domain Name Here]")
  • for_Nickname
LOWER(LEFT(IF({!var_NicknameCounter} > 0, TEXT({!var_NicknameCounter}), "") + SUBSTITUTE(LEFT({!First_Name}, 1) + {!Last_Name}, " ", ""), 40))

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 IF function 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 Loop does. 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 Records element called Create Account on the Account object and map any required fields on the object, such as the Name field. I also make sure to set the OwnerId field to the User ID of someone who has a Role within 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.

A Create Records element on the Account object.

I use a Create Records element called Create Contact on the Contact object next, making sure to map any required fields. The main field I want to set here is the AccountId field with the value as the AccountId from the Create Account element 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.

A Create Records element on the Contact object.

Before creating the user record, I first need to use a Get Records element called Get Portal Profile on the Profile object that will get the first record whose Name is equal to the profile name of the one I want to assign to new portal users. I only want to store the ID field 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).

A Get Records element on the Profile object with a filter on the name.

The final and biggest step is to create the actual user! To do this, I use a Create Records element called Create User on the User object. There are several required fields on the User object, including:

  • Alias: I create a text formula (for_Alias) for this which is:
LOWER(LEFT(SUBSTITUTE(LEFT({!First_Name}, 1) + {!Last_Name}, " ", ""), 7))
  • Username: Use the for_Username formula.
  • Nickname: Use the for_Nickname formula.
  • Email: Use the information they provided.
  • First Name: Use the information they provided.
  • Last Name: Use the information they provided.
  • 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.
  • Time Zone (TimeZoneSidKey): This corresponds to their time zone.
  • Currency (CurrencyIsoCode): This is only required if you have multiple currencies enabled.
  • ProfileId: Use the ProfileID from the Get Portal Profile element.
  • IsActive: This should always be True.
  • ContactId: Use the ContactId from the Create Contact element.

A Create Records element on the User object.

After the user record has been created, I use a Screen element called Confirmation Screen with display text that 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 Active and you’re ready to use it on the portal, you need to navigate to All Flows in Setup and 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 Profiles column. This should include the System Administrator profile or whichever profile you use at the minimum for testing purposes. Then, click Save.

Edit flow access page with “Override default behavior and restrict access to enabled profiles or permission sets” enabled for the System Administrator profile.

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 General tab, under Guest User Profile, select the hyperlinked profile.

Experience Cloud Builder General Settings page.

In the portal’s special guest profile, click to Edit the Enabled Flow Access tab, move the self-registration flow into the Enabled Flows column, and click Save. Now, portal guest users can access and use the self-registration flow even if they’re not a Flow user!

Enabled Flow Access tab on a profile page.

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 Register page that comes with the initial site creation. If you use a custom page, make sure to set the Page Access to Public within its Properties so that guest users can access it while unauthenticated.

An Experience Cloud Builder page’s properties with page access set to Public.

On the desired page, add a Flow Component and 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.

An Experience Cloud builder page with a Flow component housing the self-registration flow.

Since we’re using the standard Register page, 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.

An Experience Cloud Builder page’s properties with a custom theme layout and different content layout.

Navigate to the Login page next and click into the Login Form. The Self Register URL should point to whatever URL the page that houses the self-registration flow is, which can be found within the page’s properties.

An Experience Cloud Login Form component.

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 Setup section. Set the Login Page Type to 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 Type and 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 Account fields blank since the flow will be handling this process, and click Save.

The Login & Registration tab of an Experience Cloud portal site.

Lastly, access the Emails tab in Administration and 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.

The Emails page of an Experience Cloud portal site with “Send welcome email” checked.

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!

Resources

Want to see more good stuff? Subscribe to our channel!

SUBSCRIBE TODAY
How I Solved It with Jennifer Lee and Dee Ervin

Search Unsearchable Field Data Types | How I Solved It

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 […]

READ MORE
Automate This! Enhance Screen Flows with Reactive Components

Automate This! — Enhance Screen Flows with Reactive Components

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 […]

READ MORE