Introducing: User-aware Record Type Picker for Flows

Update September 26: install links updated to latest version

Next week is the year’s big Main Event: Dreamforce. For some of us, that means packing our things and scrambling to fill our session schedules, make meetup plans, and find the perfect dinner spot. For others, like me, an sense of impending FOMO.

Fortunately, the announcements made at Dreamforce, and the Winter 23 release just a few weeks after, will be for everyone, whether you make it in to San Francisco or not. If you’ve reviewed the release notes or scoped out your preview sandbox, one item you may notice is that the Dynamic Fields feature for Screen Flows will be Generally Available, and with that, picklist fields will be Record Type-aware. This means you can simply place a record variable’s picklist field on a screen, and if you’ve set the Record Type for that record, it will correctly display only the picklist values that are active for that Record Type. However, that Record Type must be set on the record variable before the Flow arrives on that Screen with the picklist. So, then: what options do we have today for letting a user select a Record Type?

Today’s Options for RecordType Selection in Flows

  • You could build a Choice for each Record Type. That might work, but what if different users have a different permissions to different Record Types. Sounds like a pretty hairy mess to try to get right, and to maintain moving forward. Not a great option.
  • You could do a Record Choice Set or a Collection Choice Set based on the RecordType object. Of course! Perhaps by setting the Screen Flow to run in User Mode, which respects a user’s access to records, we’ll only get the Record Types that the user has permissions for. If you’ve tried this, you’ll quickly learn that the RecordType object, which holds all each object’s Record Types, is not limited by the user’s permissions. If a user has read access to an object, they’ll have access to every RecordType for that object, even if they don’t have permission to create a record for that Record Type.
  • The closest I could find is the GetRecordTypeInfo action in the UnofficialSF Flow Action Pack. Its a nifty action! But its a bit incomplete, as it requires you to pair it with another screen component, it won’t give you the Record Type Descriptions, and the Record Type information is provided in separate text collections, making it challenging to be able to use the selected option downstream in the Flow.

🎉 Welcome to the team, Record Type Picker 🎉

The Record Type Picker is an open-source, free-to-use component that can be used in Screen Flows to give users selectable choices of Record Types, automatically filtered to just the Record Types that the running user has access to!

Three display types

Visual Picker, Radio Group, Picklist, each with optional Show or Hide Descriptions

Introducing: User-aware Record Type Picker for Flows

Optional Auto-Next Navigation on Select

Auto navigate on selection works best with the Visual Picker on a screen that doesn’t have any other inputs and has the footer and/or Next button hidden. When the user clicks on a selection, the Flow will automatically navigate to the next screen. It is also recommended to provide a “Previous” button on the next screen so that the user has a chance change their selection if they’ve made a mistake.

Easy configuration with a Custom Property Editor that has a Preview mode

Bonus Invocable Action

The package also comes bundled with an Invocable Action to get a Collection of RecordTypes available to the running user, in case you’d prefer to use other screen components like Collection Choices or Data Table

Install with Ease

This component does not depend on any other packages, and can be installed with an unlocked, namespaced package using the links below. The namespace means you don’t have to worry about conflicts with anything you’ve already got in your org, and being unlocked gives you the confidence that what you see in the source repo is what you get in the package.

Package version last updated: September 26 2022


There are a handful of features that I’d like to add, but its at the point now that it should be pretty useful for anyone that needs this kind of thing. Take a look, and please add any issues or feature requests to the Issues log in the GitHub repo!

Find The Object Type Of Any Id Value Using Flows

If you’ve been in the Salesforce ecosystem for long enough, you’ll eventually find yourself working with Record IDs that could be multiple types of objects, and you need to build a report or automation that needs to know what kind of object it is. A common example of this might be a task or activity report grouped by the Type of object each Task is related to. It usually involves adding a Formula(Text) field to the Activity object that translates the record Id in the Related To field on Task/Activity to the name of the Type of Object it is:

That kind of formula gives you a field on the Activity object that will tell you what kind of object it is related to! You can imagine all of the nifty reports this could enable, or Flow-based automation you could build that may be specific to Activities that are related to a particular kind of object.

For many years, it was really the best we could do without writing Apex code. In this post, we will walk through the limitations of this approach, and how to build a better version of this in a Record-Triggered Flow.

A better approach with Flows

With today’s automation tools, and Flow Builder in particular, we can account for any object, without any hardcoding, and without a single line of Apex. The Flow itself is simple: just two elements in a Record-Triggered Flow. So if you’re short on time and want to skip the explanations, jump on ahead to “Let’s Build”, and be on your way. But I think its helpful to know the how and the way, so let’s dive in.

Secret Sauce Ingredient 1: Key Prefix

Record ID values are 15 or 18 digit values that uniquely identify Salesforce records. We won’t go into everything that goes into constructing them, except for one crucial bit of information: the first three characters of every ID identifies the object type of that ID! This is called the Key Prefix. Each object – standard or custom – has a unique 3 character Key Prefix and *every record* in that object starts with those three characters. That’s why the formula above takes the first three characters of the ID LEFT(WhatId,3) and then uses the CASE() function to translate that to an object name.

There are some important things to know about the Key Prefix:

  • Standard Salesforce Objects (objects that don’t have a suffix like __c at the end) all each have the same key prefix in every org in every environment across all of Salesforce. Account is always 001, Opportunity is always 006, etc
  • Custom Objects are not guaranteed to be the same across orgs. Even though you may find some of your custom objects are the same between Production and Sandbox, this is not guaranteed and should not be relied upon.

Given this information, have you caught the limitations of the formula approach yet? There’s two huge red flags:

  • It requires you to hardcode the 3 digit key prefix to object translations! If you build this formula field in Sandbox (which you should definitely be doing!) to include a Custom Object, there is no guarantee that the same object will have the same key prefix when you move it to production, leaving you scratching your head, then needing to make a change directly in Production (which you should definitely NOT be doing!)
  • It requires you to explicitly write out each object you want to translate from key prefix into an object name. This means writing out a /massive/ formula to account for all your objects, or lots of maintenance when someone inevitably asks why it doesn’t work for their favorite custom object that wasn’t included.

There is a better way. Enter Flows, and Secret Sauce Ingredient 2.

Secret Sauce Ingredient 2: EntityDefinition

When building automation in Flow Builder, we all know you can retrieve a record, or collections of records, from every day objects like Account and your Custom Objects, but did you know there are a whole host of system objects you can retrieve records from using a simple Get element? One of these objects is what is going to help us today: EntityDefinition. This object contains metadata and configuration information about each of the Standard and Custom Objects in your org. Each object has a record in this EntityDefinition object. Information like Label, API Name, Plural Label, and more.

And – you guessed it – EntityDefinition has a field with each object’s Key Prefix.

Let’s build!

Now that we’ve got our two ingredients, let’s build a better alternative to that formula above. Let’s take one moment to ask ourselves what we need first:

We want a field on Activity that contains the name of the Object Type for the record it has in its WhatId field (the label for the WhatId field is “Related To”).

Add a Text Field to Task

Instead of a formula field, we’re going to add a regular Text field to the Activity object, and we’re going to call it something like “Related To Type” (that label is my preference, but whatever makes sense to you and your team)

Add a Record-Triggered Flow on Task

Entry Criteria

Next we’re going to build some automation to populate this field. We’ll add a Record-Triggered Flow on the Activity Object to do this. Since an existing Task could be updated to change which record is in the Related To field, we’ll want this Flow to run when records are Created and Updated

And we’ll want to configure Entry Criteria so we’re only running this Flow when we need to, and not when we don’t. We can use the (new as of Summer 22 release) Entry Criteria Formula feature to do this.

In short, this Entry Criteria formula will ensure this Flow only runs if its a newly created Task record that has a WhatId value, or if its an update on an existing Task and this update includes a change to the WhatId value, which are the scenarios we’ll need to set or change our Related To Type field.

(ISNEW() && NOT(ISBLANK({!$Record.WhatId})))
 || ISCHANGED({!$Record.WhatId})

Lastly for the Start Configuration, don’t forget to take advantage of our ability to run this as a Fast Field Update, since all we are doing is setting a value in a field on the same object that triggered the flow.

Get the Related EntityDefinition

Without further ado, let’s use our secret sauce ingredients to build this Flow. The Flow has our $Record variable with the WhatId, and the EntityDefinition object is what has the link we need between the KeyPrefix from that $Record.WhatId and the Object’s name.

So we want a Get on EntityDefinition, and we’ll add filter conditions to match the KeyPrefix against a Formula Resource that returns the first 3 characters of $Record.WhatId field

Formula Resource (named relatedToKeyPrefix):


GOTCHA ALERT: There are a handful of standard, system objects listed in EntityDefinition that have no KeyPrefix value. They cannot be associated with Tasks, so we don’t really need to worry about needing to match on them. But, we do want to clear our field if a task gets its related to field cleared to be empty, we want to avoid accidentally matching on one of these “empty KeyPrefix” objects. Its a simple condition we need to add to the Get:

KeyPrefix Does Not Equal {!$GlobalConstant.EmptyString}

Next, in the Flow Builder after the Get, we’ll add an Update element that sets the Related To Type field on our Task record using the result of this Get! It really is that easy. The field from the EntityDefinition that we’ll use here is MasterLabel.

Back in the Flow Builder Canvas, our resulting flow is just two elements!

Now, you’re going to build a Flow Test for this before deploying to production, aren’t you?

⚠ Consider Existing Data ⚠

One difference from the formula approach, and consideration you’ll have to account for with this approach, is your existing data. With a formula field, you don’t have to make any data changes- its just a formula that is evaluated anytime someone or something looks at the record. With this approach, once the Record-Triggered Flow is in place, all records *moving forward* will have your new field populated, but your existing records won’t. This means you’ll need to backfill them, or tweak the entry criteria and run a one-time “backfill” update. Use whichever data tool you’re most comfortable using to do this.

Take it further

Add a Related To API Name

The object’s Label was useful for human-readable outputs like the reports we discussed in the beginning, but you may find a lot of use cases where its better to have a unique-and-still-human-readable value, which is what the API name is designed to be. So, add a Related To Type API Name text field to the Activity object, and simply add it alongside the Update element we already have for the Related To Type field.

Ultimate Picklist Approach

If you’re really clever, and you have a stable set of objects, you could instead use a picklist. If you have a picklist with values that equate to your object labels and api names, then your Flow just needs to update it with the EntityDefinition’s QualifiedApiName value, and then you get the best of both worlds in one field. Reports and Record Views show the label (and can even be translatable!), while can manage it using api name.

Decision Branching

This becomes very powerful if you’ve got different actions you’ll need to take based on different objects, because you can simply add Outcomes to the decision for each object type, and configure its path with Object Type-specific actions accordingly.

Flow Use Case: Create a filtered opportunity list view based on account team membership with Data Table and the new In Operator

The Winter ’23 release brings with it some very nice additions to flows. I set out to try out the new features with a use case that was impossible to do before without resorting to custom functionality
Use Case: Display all open opportunities for a selected user who is on the account team.
Problem statement: Since both opportunities and account team members are related to account, this cannot be done with standard reports. You cannot create a report type with one parent and two related objects.
I was able to accomplish this task using a flow combining some new features and some old favorites from UnofficialSF

Winter ’23 new features used
IN Operator
Data Table (beta)

UnofficialSF components
Quick Lookup flow screen component
Extract Strings from Collection flow action (part of Collection Processors)

The flow starts by displaying a user lookup for the selection. I had to use this custom lookup screen component since the standard one does not support a custom lookup field to a user record.

The selected UserId is then used to get all account team members for where the user is on the team

The next steps will be to get a collection of account Ids that can be used to get the open opportunities. For this I used the handy Extract Strings from Collection action instead of looping through the account team members and adding to a collection.

Now comes the fun part. I can use the new IN Operator to get all open opportunities where the opportunity’s account is in the account ID collection

I wanted to filter the account to get only the accounts that had open opportunities so I used another Extract Strings from Collection using the account Ids from the open opps. The dedupe function of the action ensures each account will only appear once in the resulting list (it is set to true by default)

Now that I had only the accounts of open opportunities, I wanted to filter my original account team members collection to only members from these accounts.

Alternatively you can use another get records IN, but this will consume another DML which can be avoided.

The next step was to prepare two more formula fields so I could display a link to the opportunity account name and the account name for the team member

Time to see the new Data Table (beta) in action
This is the open opportunities table

And the Account team table

Here is the completed flow

I added the flow to a Lightning app page and here is how the finished flow works

So simple and yet so powerful. I’m excited for all the new possibilities these new features bring to flow and looking forward to exploring more use cases.

Summer ’22: External Services Updates

Check out some of the changes and enhancements to External Services in the Summer ’22 release!

Call External Services Registrations Natively from Apex

Now you can access External Services registered actions directly from Apex to tap into reusable functionality when writing Apex code. Previously, actions created through External Services were exposed exclusively for invocation through Flow or Einstein Bots.

Check out the Summer ’22 Release Readiness Live demo (starts at minute ~3:20) and Developers’ Blog for a simple walkthrough of how to use this functionality.

Make sure to check out the official Salesforce Help Docs: Invoke External Service Callouts Using Apex for more details!

Salesforce Developer Console

Update an Existing Schema Connected to Flow

If a registration is in use by a flow, now you can update it with a new, compatible API specification version. Previously, you couldn’t update a registered schema that was in use by a flow. If the new schema version isn’t compatible, the edit workflow notifies you which operations and schema objects are in use by which flows and by which Apex classes. With this information, you know which existing references are incompatible so that you can remove them before saving your updated registration.

For details about supported and non-supported changes, see the official Salesforce Help Docs: Appendix 1: Schema Update Considerations.

External Services: Edit Screen

Register More APIs

Now you can register an external service without manually editing the schema before registration to conform to the 80-character limit for derived operation and object developer names. This enables you to register more APIs with less friction!

Additional Details

For additional details, make sure to review the Summer 22′ Release Notes and keep the feedback coming in the External Services Trailblazer Community!

Progress Bar component for flow screens

Salesforce Labs has published a new flow screen component that has 6 different indicator types to let users know where they are in your Flow-based process. In the spirit of Salesforce Labs, they are also allowing access to the source code. Here are the installation and configuration instructions

Check it out

Undeleting Records with Flow

Created by Yumi Ibrahimzade


You can perform insert, update and delete operations in Salesforce Flow. Most of the time, they are enough but what if you want to undelete records from the recycle bin? There isn’t undelete records operation in Flow. However, you can achieve this using this Invocable Apex Action.

See this post for the main discussion of this new Flow capability.


Production or Developer Edition



recordIds – Enter a text collection of record Ids to undelete.


This Invocable Apex Action undeletes the records from the Recycle Bin. If the record is permanently deleted, which means that it is not in the Recycle Bin anymore, you cannot undelete it.


Add an Action element from the Toolbox and search for FlowUndeleteRecords. Pass the text collection of the record Ids to the input parameter called recordIds. Even if you want to pass a single record Id, you still need to create a text collection and pass it as the input value.

undelete records action and parameters

Read this post to learn how to find the deleted record Ids and see an example of undeleting records using this Invocable Apex Action.


From Tamar Erlich – Submit an orchestration from a button

Currently there are two ways you can launch a flow orchestration: using a record trigger, or auto launch from Apex, But what if I want to be able to launch an orchestration from a button and mimic the good old “Submit for Approval” button?
I looked at alternative ways to start orchestrations, and this is what I found:
1. Launching an orchestration from a URL button was not user friendly as the user was presented with a blank auto launched flow screen and was not redirected back to the record when finished even if the the return URL was part of the button definition. Overall, while this may work, the user experience was not smooth
2. Trying to include the submit flow as an interactive step assigned to the current user, resulted in a warning when saving the flow and an error during execution saying that no assigned user was found

I ended up with the following solution that worked well and gave a smooth user experience:

1. An action button to launch the submit flow on the record page
2. A submit screen flow that will update a field on the record to indicate the record was submitted and who the approver is
3. An orchestration that will listen to the field updated by the submit flow and will run the approval flow, routing to the approver that was updated on the record by the submit flow
4. The approval flow will update the record again with the final approval status

Here is an illustration of the overall process:

Both the submit and approve flows are very simple and only have one screen followed by an update records step

Submit Flow

Launch the submit flow from an action button added to the page layout

Action Button
Approval Flow

The flow orchestration only has one stage and one step

Orchestration Flow

It starts when the record’s approval status is updated to submitted

And routes the approval to the username that was updated on the record by the submit flow

Here is a short video demonstrating the complete process

Some notes about the flows:

1. The submit flow clears any previous approval status and rejection notes
2. The approval flow only displays rejection notes if the user selects to reject, using a visibility rule
3. In both flows, I’m using a record input variable and this saves having a get records element in the flow as the whole record gets passed in from the button or from the orchestration step

Possible enhancements:

1. The approval request flow can include a message with approval details to the approval request flow by using a display text with merge fields from the record and related records information
2. The submit flow can select the approver automatically by using criteria from the record or an approval matrix stored in custom metadata
3. The submit flow can also be used to recall or not allow to submit an approval by displaying another screen based on the approval status

Launching an orchestration from a button opens up a lot of possibilities, please share if you come up with other use cases.

Flow Orchestration Use Case – approve user provisioning

I was eager to test the new flow orchestrator and found a use case to try. When a user submits a case to be provisioned as a partner user, we need to process two manager approvals and then provision the contact and the user under the partner account. I built an orchestration to complete the approvals and then provision the user

I used the tutorials provided here by Alex to build this. The overall design uses three flows that share data using input and output variables.

My starting conditions were based on case creation

The manager approval is routed to the approving manager lookup field from the case

The supervisor approval is routed to a specified username

My approval flow is very simple and includes just one screen. It outputs the approval, and some user data from the case, that will be consumed by the provisioning flow. I used some interesting formulas to parse the supplied Web Name from the case to a first name and a last name, and since only variables can be designated for output, I’m assigning my formulas as the default value of the output variable

Here is how the approval request screen looks to the approving manager

Next, I created an autolaunched flow that evaluates both approvals and outputs the special “isOrchestrationConditionMet” boolean value that tells the next step to start. This flow also updated the final approval status on the case record.

Then my provisioning flow will start and show as a work item to the case owner

Here is how the provisioning screen looks to the user. The first name, last name, email, and account name, are populated from the approval flow and case record data.

In this screen I’m using the Quick Lookup flow screen component to dynamically filter the user role list based on the selected partner account

And after the provisioning is complete, the flow shows the success scree

I used some special formulas to set the alias, email, nickname, and username for the new user.
To avoid a mixed DML error, I used the Commit Transaction action between creating the contact and creating the user.

When the orchestration completed, I was able to view all the completed stages, and steps in the flow orchestration instance history

Overall, building this orchestration was fun and easy. I can see how powerful this tool can be for handling complex processes. I would like to be able send an approval request to non Salesforce users, that can approve by replying to the email, or by going to the work item component publicly exposed on a community page.
I’m looking forward to seeing how this tool will evolve and to all the enhancements that will be made.

From Yumi Ibrahimzade: Using Flow to Mass Delete Records from List View

Yumi Ibrahimzade from the blog Salesforce Time has written a post explaining how to use flow to add a mass delete button to a list view. Pay special attention to the second solution that avoids performing DML inside a loop by using a custom action that can be found in the collection actions here on UnofficialSF

Check it out

From SFDCPanther: Rich Text Area component for screen flow

Amit Singh from the blog has written a post explaining how to create a LWC that will enable a Rich Text Area component in flow screens
Check it out