How to Create a Portal User Using a Record-Triggered Flow in Salesforce

Automating portal user creation is one of the more powerful things you can do inside Salesforce — and record-triggered flows make it possible without writing a single line of Apex code. But getting it right depends on understanding exactly what's happening under the hood, where the permissions live, and what variables in your own org will shape the outcome.

What Is a Record-Triggered Flow?

A record-triggered flow is a type of Salesforce automation that fires automatically when a record is created, updated, or deleted. Unlike screen flows (which require user interaction), record-triggered flows run in the background — making them ideal for tasks like provisioning access, sending notifications, or, in this case, creating a community or Experience Cloud portal user.

When a Contact record meets certain criteria — say, a field is set to "Active" or a checkbox is checked — the flow can immediately spin up a portal user account tied to that Contact.

Why Use a Flow Instead of Apex?

Traditionally, creating portal users required Apex triggers because the Site.createExternalUser() method was the standard approach. Flows have matured significantly, and Salesforce now supports user creation through the Create Records element inside flows, provided your org meets specific prerequisites.

Key advantages of the flow approach:

  • No deployment needed — flows are built and activated entirely in the Setup UI
  • Easier maintenance — admins without coding skills can modify logic
  • Built-in error handling — flows support fault paths visually
  • Governor limit awareness — flow actions are somewhat more forgiving for admins managing complexity

The tradeoff is that flows have their own limitations around mixed DML operations, which is one of the most important variables to understand before you build.

The Mixed DML Problem — and How to Handle It ⚠️

This is where many admins get tripped up. Salesforce separates setup objects (like User) from non-setup objects (like Contact, Account). Performing DML on both in the same transaction throws a Mixed DML Exception.

Because a record-triggered flow fires in the context of the record that triggered it (a non-setup object like Contact), you cannot directly insert a User record in the same transaction.

The standard solution is to use a subflow or an invocable action that runs the User creation in a separate transaction. Common approaches include:

ApproachHow It Avoids Mixed DMLSkill Level Required
Invocable Apex methodRuns User creation outside the trigger contextIntermediate (requires Apex)
Asynchronous subflow via Platform EventFires a Platform Event; a separate flow processes User creationAdvanced
Screen Flow launched from record pageUser-initiated; separate context by designBeginner–Intermediate
Flow + @future Apex actionApex runs asynchronously after triggerIntermediate

For a fully declarative approach with no code, the Platform Event pattern is the cleanest: the record-triggered flow publishes a Platform Event, and a separate event-triggered flow subscribes to it and creates the User in a fresh transaction.

Step-by-Step: The Core Logic

Regardless of which pattern fits your org, the logical structure of the flow stays consistent.

1. Set Your Entry Conditions

Define precisely when the flow should fire. Common triggers:

  • A Contact record is created with a specific record type
  • A field like Portal_Access__c (checkbox) is set to true
  • A status field changes from "Pending" to "Approved"

Use the Entry Conditions and Run Flow settings carefully — set it to run only when the record is created or when the relevant field changes, not on every save. This prevents duplicate user creation attempts.

2. Check for an Existing User

Before creating anything, query for an existing User tied to the Contact's Id using a Get Records element. If a User already exists, route the flow to a fault path or simply exit. Skipping this check is a common source of duplicate-user errors.

3. Assign the Correct Profile and Role

Portal users require a profile associated with your Experience Cloud site. The profile must be an external profile — typically Customer Community, Customer Community Plus, or Partner Community, depending on your license type. 🔑

Your flow will need to:

  • Reference the correct Profile Id (store this in a Custom Metadata Type or Custom Setting to avoid hardcoding)
  • Optionally assign a Role if your community uses role-based visibility
  • Set IsPortalEnabled = true on the User record

4. Populate Required User Fields

At minimum, a portal User record requires:

  • FirstName, LastName
  • Email (also used as Username — must be globally unique across all Salesforce orgs)
  • Alias
  • TimeZoneSidKey, LocaleSidKey, EmailEncodingKey, LanguageLocaleKey
  • ProfileId
  • ContactId (links the User to the Contact and automatically sets AccountId)

The Username uniqueness requirement is a significant variable — if your org generates usernames from email addresses, duplicate emails across records will cause failures. Many teams append a domain suffix (e.g., [email protected]) to ensure uniqueness.

5. Handle Errors Gracefully

Always connect a Fault Path from your Create Records element. Log the error to a custom object, send an email alert to an admin, or update a status field on the Contact. Silent failures in background flows are difficult to diagnose without this.

Variables That Will Affect Your Specific Implementation

No two Salesforce orgs have identical configurations. The factors that most directly shape how this flow behaves in your environment:

  • Experience Cloud license type — Community, Partner, Customer Plus, and others each have different capabilities and profile options
  • Org sharing model — OWD settings and sharing rules interact with portal visibility in ways the flow itself doesn't control
  • Username generation strategy — how your org enforces uniqueness determines whether automation can be fully hands-off
  • Existing automation conflicts — other flows, process builders, or Apex triggers on the Contact or User object can interfere
  • Governor limits in high-volume orgs — bulk Contact imports trigger flows in bulk; testing with real data volumes matters
  • API version — some flow features behave differently across Salesforce releases, particularly around asynchronous execution

The right pattern — declarative Platform Events, Invocable Apex, or a hybrid — depends on what your org already has in place, what your team can maintain, and how often portal users will be created. Each of those is something only your setup can answer.