Search Results
104 results found with an empty search
- Baking Your User Access Layer Cake
In part one of [what has become] a series, I used a layer cake metaphor to explain licenses, profiles, and permission sets. If I'm going to really embrace that metaphor ( And I am!) , then it's time to write about how to bake that cake. Personas are Recipes To torture my layer cake metaphor: Personas are the recipes for how we build out a user's permissions layer cake. Personas are not actually a technical feature of Salesforce. You can search the Setup tree all you want but—at least as of this writing— there is nothing there for "persona." Nonetheless, personas are a useful way to organize your thinking about what you need for each user. Product design—particularly software design—is often based around the personas of the different kinds of users that might interact with a product or service. Your Salesforce implementation is no different in that regard. Once you have figured out the personas that describe the different categories of work that people need to do, you know what combination of permissions they need. At their simplest, personas are one-to-one with job categories. Say you have: Executives - Mostly look at reports and dashboards. Fundraising Users - Enter opportunities and payments, update contact information and relationships, etc. Program Users - Enter program contacts, update program records, etc. (Of course, if you have many programs you could have different personas for each. But we're keeping our example simple right now.) System Administrators - Have access to the whole system and Setup. Each of these personas need their own recipes to end up with the right layers. Cross functional jobs probably constitute their own persona, but you can already see that their access will just combine the two functions that they cross. They get an additional layer of the cake. Note that Persona, the way I'm using it, is like profiles were in the bad old (and often current) days of user management in Salesforce. So you may have a bit of persona proliferation to delineate similar roles or users with the same role on different licenses, etc. Even if you end up with a lot of personas, we are still facilitating you moving to all profiles that are minimum access. You'll see that it's going to be easier to maintain several personas than it was to maintain several profiles. Your user personas tell you the recipe for the cake you're going to bake. Now into the kitchen! User Access Policies Are...The Kitchen? [ It's official: My metaphor has gotten out of hand. ] In Summer '24, Salesforce released User Access Policies . This is a handy and fully declarative Setup tool that allows you to automate granting or revoking of permission sets to users or adding users to public groups. User Access Policies are a major step toward making it easy enough for admins to get to the permissions-off-profiles future. So let's think of User Access Policies as the kitchen, including mixing bowls, layer cake pans, stand mixer, oven, etc. With access to a kitchen, you can turn a bunch of ingredients into a delicious multi-layered showstopper of a cake. With User Access Policies we can turn our list of personas into a fully functioning user management regime in short order. No more maintaining (usually somewhere outside of Salesforce) a flow chart of what to do when you are creating a new user. You turn that chart into User Access Policies and the work should be done—or at least mostly done—for you by the robots. That's the subject of my next post. I don't think it's necessary for me to actually write up a How To guide for using User Access Policies. There's a Trailhead module for that .
- Perms Are Not for Hair- Understanding User Access
Once upon a time, user permissions ("perms") were controlled by user profiles. Then in 2023, Salesforce announced, via a blog post from Cheryl Feldman , the "end of life" (EOL) of permissions on profiles. Eventually profiles will be stripped nearly bald and all permissions will be assigned by permission sets. All that will be left on profiles will be those settings or permissions that are 1:1 with a user, like the default app, default record type, page layout assignment, login hours, and a handful of other things. Everything else, including settings like Edit Reports, or object and field access will be assigned as part of a permission set (or "permset"). It's a couple years later and I'm not sure we're really any closer to that future from a technical standpoint. That blog post has been updated a few times to indicate that the EOL for permissions on profiles is not on the horizon. But it's been clear for a while that the future of user permissions is going to be one of very basic profiles and a lot of permission sets. So it's time for admins to start thinking more about their perms. It's time to start thinking about how you will eventually move your organization into the permission set-forward future. Apparently this is about to be a short series of blog posts. Today we start with the basics of understanding user access. Permissions as a Layer Cake To switch visual puns and metaphors, I like to think of permissions as a layer cake. The future of user management is all about layering on the right access for each user. User License We start with a base that everyone needs, which is the user license. (Without a license available, you're not going to be creating a new user. Whether platform users , community users, API-only integration users , or full Salesforce licenses, everyone that logs into Salesforce is doing so based on a user license.) For today's discussion, we don't need to put too much time into license type. But it's definitely there, like the bottom crust. Profile As I mentioned above, the profile is 1:1 with a user—you can't have a user without them having a profile. That makes profile the second layer of our cake. (To be honest, I usually think of profile as the first layer.) In most orgs today, Profile is the true heart of your user setup. You probably have a profile that corresponds to each of your departments. You may have more granularity than that, with regular users and power users within each department. But that's often all there is. And once you've assigned a profile, that might be it. The profile contains all the app permissions, object CRUD (create/read/update/delete), and field level security the user needs to do their job, so they don't routinely get any permission sets. If this is your org at the moment, don't feel bad. This was "the way" for a long time. As long as you have a couple of profiles, rather than everyone being a sysadmin, you're ahead of a lot of orgs. (Please do not do that!) If your org's user access is just license and profile, that's just two layers. I guess you have a user access pie. Pie is delicious, so I can't fault you. It's Salesforce's/Cheryl's plan that eventually there won't be a whole lot of substance to the profile. It can't go away—you need something to hold those 1:1 settings. It's just going to grant a whole lot fewer powers than it does today. So eventually, just having profiles is not going to be enough. Permission Sets In the layer cake future, all the power is going to come from permission sets, piled onto your base profile. Each layer has its own flavor and texture—which, in our metaphor, means that they each grant different permissions and they build on each other. When I'm planning permissions, I usually start with a "baseline" permission set that I'm planning to assign to every user. This permset is going to grant access to the shared common set of objects and fields that everyone needs to access. This means Account and Contact, for sure, plus any custom objects that are at the heart of your org's Salesforce usage. Depending on the org, not all users may need to see Opportunities. But I definitely put some of the NPSP objects in my baseline permission set as well, such as Relationships. And I put baseline system permissions in here as well, such as Run Reports, Schedule Dashboards, or Chatter Internal User . Let me be clear: this is not the only way to do this. I tend to work with smaller clients and we are prioritizing simplicity. Your needs may vary. Or you may have fewer settings and objects truly in common for all your users. There's no requirement for a single baseline permission set. I just find it simpler to work with. (And I do not want to use permission set groups, for reasons I'll explain below.) In some small/simple orgs I manage to have basically only this one baseline permset. I Don't Love Permission Set Groups I would be remiss if I didn't mention permission set groups ("PSGs", or "permsetgroups") in this discussion. But I'm only going to touch on them briefly because I don't like them and I mostly don't use them. As their name implies, permission set groups are a way to bundle a bunch of permission sets together. Then you only need to assign the PSG and the user gets the access of all the permsets inside. Permsetgroups have one nifty feature: muting permission sets. Within a permsetgroup you can create a muting permission set that turns off permissions that reside in the underlying permsets. Note that a muting permission set only applies within the permsetgroup . So if a permission set outside the group or a second permission set group grants a permission that's muted in the first one, the muting doesn't apply. To me, it's not that much less work to use muting than to make permsets with fewer permissions and then give a Super User permset to add power. And it's less confusing. The other downside that keeps me away from permission set groups is that they have to recalculate any time there is a change to one of the permission sets within them. Every so often I need to open the permissions for a few objects in tabs and make changes to each. But if those object permissions are within a permission set group, each save has to finish calculating before I can hit Save on the next. It usually takes a full minute between saves. That's very annoying. But even more frustrating is that a permission set group can fail its recalculation silently! If you happen to be on the PSG list view, there is a Status field but it's not that likely that you're going to sit there waiting to see that it shows Updated. And you don't get any email notification that your permission set change led to a failure in the permission set group recalculation. Last: it's just not that much harder to assign several permission sets than it is to assign a group. And by using only permission sets you only have one place on the user that you need to investigate when you're trying to figure out their user access picture. And there are ways to make assigning the right permission sets easy, so I think groups aren't that neccessary.
- Platform Users Usage Tips
Lately we've been talking about Salesforce platform licenses , which are a great way to bring more parts of your organization onto Salesforce without big expense. But I don't want to pretend that the Salesforce admin setting up platform users won't run into some challenges here and there. Whether you manage your permissions primarily on profiles or have moved into the " future of user access , " with almost everything provided by permission set, you'll have to think about platform users slightly differently than full users. Basic Profile Right from the get-go, when you go to set up your platform user, you'll find that you can't assign the profiles you've already been using because each user profile is tied to a user license type. So whether you're using the Standard User profile, one of the NPSP-installed profiles or a custom profile for your organization, you'll need to use a different one. (You will get a new Standard Platform User profile if you want to use that as a starting point.) If you try to create a completely new profile, you actually have to start by cloning an existing profile, which also clones the user license of that original. So you're not going to get around this. Basically you're going to have to have a different profile for any users on platform as opposed to full licenses (just listed as "Salesforce"). That's not a big deal, but it does mean you have at least one more thing to manage. And whenever you make a change that is going to affect profiles (like setting default record types or app access) you'll need to make the change for at least two profiles, not just one. (Realistically, your minimum is probably three, since you should have at the very least yourself on System Administrator and everyone else not on System Administrator.) Basic Permissions When it comes to assigning the rest of the permissions your users are going to need, I'm going to talk about this for orgs that have moved to put all permissions on permission sets. (A full discussion about moving from profiles to permission sets will be another blog post...someday.) If you're managing permissions still on profiles, then you're already managing your platform user profile differently from your other profiles. I tend to keep a single baseline permission set that will be assigned to all users. The idea here is that this single permission set grants access to all the apps, objects, fields, and abilities that every user will need to work within the organization. But since platform users can't access Opportunities or Campaigns, a baseline permission set meant for all users is going to have to leave off access to those two objects. (If you tried to assign a permset to platform users that granted access to Opportunities or Campaigns, it would error.) So right off the bat, if you have some platform users you're probably going to need to break out the true base line permissions and put additional permissions for full users into a second permset. In addition, don't forget that Platform Starter users are supposed to only access ten custom objects. So keep the object count in mind as you build up the truly baseline permission set. Other Special Permissions The other things you'll find, depending on how your baseline permission set was built, is that it might have various special permissions in it that can't be assigned to platform users. I don't have a list handy of what those might be, but various things that might be checked off under System Permissions in the permission set. There are screens and screens worth of items in there. It's actually kinda' hard to understand what some of them do. And some of them are permissions you can't give to platform users. So when you go to assign your baseline permission set to a platform user, you may find that you have to uncheck something. Maybe it's something that you can tell shouldn't have been granted to users in general, in which case you can just remove it. But this might be another area that forces you to have two baseline permission sets, one for platform users and one for full users. Access to Cases Unlike Opportunities and Campaigns, which they can't access at all, platform users can see the Case object. But you may need to jump through some additional hoops to grant them access. (Because: Salesforce.) I was working with a client recently to reduce their license cost by moving a bunch of their users to platform licenses. When I tried to assign them our basic permission set I got an error that prevented it from being assigned to platform users because it included access to Case. I'll be honest: I had a moment of panic, and started questioning whether our license strategy would work if we couldn't give Case access to a whole department. But I was sure I'd had platform users in other clients with access to Case and the documentation about platform users never mentions a restriction around Case the way it does for Opportunities and Campaigns. Luckily, this blog post showed that you can create a license-type-specific permission set that will allow access to Case for platform users. It's one more permission set to manage, but it gets the job done. Annoying. And I'm almost certain that in other client orgs I haven't had to go to this length to give platform users access to Case. 🤷🏻
- Platform Users: Cheap and Powerful
It's funny, I've written about platform events several times ( here and here and here ), but I seem to have barely mentioned platform users (only here ). Time to rectify that! Clarification Once I started writing, I realized I could be creating some confusion. So: Platform events and platform users are two totally different things , completely unrelated. They are united only by having the word "platform" in their names. What are Platform Licenses? Platform Licenses are the user licenses you can purchase if you truly do not need a user to access Sales Cloud or Service Cloud features. As their name implies, they grant access to the Salesforce platform but not to Sales Cloud nor Service Cloud. If you thought that sounded like a non-answer, because you don't even think of Sales Cloud or Service Cloud as separate from the platform, you are not alone. For reasons that I think have mainly to do with company history (and technical debt), the products that we usually think of as a generic "Salesforce license" are actually Sales Cloud licenses. These allow full access to the Salesforce platform as well as access to some things that Salesforce considers part Sales Cloud (Opportunities, Campaigns), even if we usually just consider them a standard part of the platform. Service Cloud licenses, similarly, are 99% about access to the platform, though purchasing a Service Cloud license also comes with some Service Cloud features (like Knowledge and Entitlements). Particularly in the nonprofit world, where the P10 grant of free licenses gives Sales+Service licenses, we rarely consider whether there is a difference between one "user license" and another. [I've written about making sure that when a nonprofit purchases their 11th and later licenses they should only pay for Sales Cloud licenses , because they don't need Sales+Service.] All that is to say that, other than in the context of certifications, in my experience most Salesforce professionals barely even think about Sales Cloud as a somehow different "product" than Service Cloud. We know, intellectually, that the Case object is part of Service Cloud—and are reminded of if when we have to go to Setup>Feature Settings>Service>Case Assignment Rules—but it rarely matters. Salesforce doesn't help make the distinction clear either. If you go to Setup>Company Information>User Licenses, your Sales Cloud, Service Cloud, or Sales+Service licenses all show as just "Salesforce" while your platform licenses are on a line marked "Salesforce Platform." Because of this (and to make myself part of the problem), I usually refer to Sales or Service Cloud licenses as "full licenses" to distinguish them from "platform licenses." In practice, users on platform licenses are just another user. They can log into the system, can create and edit records, view reports and dashboards, trigger the firing of automation, run screen flows, etc. Because those users don't have Sales Cloud or Service Cloud there are some standard objects they can't access (including Opportunities and Campaigns). But there are a lot more that they can access. And they can access custom objects that you have created or that are part of managed packages (such as NPSP or PMM ). To add a bit more complexity, platform licenses also come in two levels, Platform Starter and Platform Plus. Besides a difference in price, the distinction between those two is that Starter are only allowed to access ten custom objects, where Plus can access up to 110. Both of those counts are of your org's custom objects. Objects installed by managed packages do not count against this limit. (And as I noted when I wrote about stacking , it's possible to give access to more than ten objects for platform Starter users.) One last distinction to think about for platform licenses: You will need different profiles and may need different permission sets to go with platform licenses. Most of the time you can work with platform users exactly the same as other users on full licenses. But every so often you'll find some place where you need to work slightly differently for them. For example, if you have a baseline permission set that grants access to all the objects and fields your organization users have in common and it includes Campaigns, you won't be able to use that permset for platform users (because they can't access Campaigns). Usage So how do I use platform licenses with my clients? They're a way to save money! Depending on what your users need to do and how you have designed your Salesforce system, platform licenses may be a great way to get more people on Salesforce without breaking the bank. You just have to think about (and design around) the limitations. Since platform users can't access Opportunities (nor, by extension, any objects that are child to Opportunities, like the NPSP Payments object), you probably can't use platform licenses for anyone that works in fundraising and development. Since they can't access Campaigns, you will have to have platform users doing their job without using Campaign List Emails. But the many objects in the Program Management Module (PMM) come from a managed package, so they are all available to your platform users. And if you've designed a program management setup in Salesforce that just relies on Contact, Account, and a handful of custom objects, you're good to go! For example, I've worked with clients that serve students around college acceptance. They track students (contacts), schools (accounts), programs (custom object), enrollments (custom object), college entrance tests (custom object), and college applications (custom object), as well as a few other things. It's no problem for program staff to use platform licenses. Pricing As you've probably guessed, platform licenses are quite a bit cheaper than full licenses . Full Login: List price $1,980/year (Nonprofit: $495/year) Platform Starter: List price $300/year (Nonprofit: $72/year) Platform Plus: List price $1,200/year (Nonprofit: $288/year) That makes platform starter 85% off! The savings are less dramatic for nonprofits, who are already getting a steep discount off list prices. So if your nonprofit only has a few users above the P10 grant, it might not be worth the admin overhead (or, let's face it: technical debt) to support the second license type. But the cost/benefit catches up once you're paying for ten or more users that could be on platform—particularly if they could be on Starter. The Crowdsourced Pricing Guide (User Logins tab) is probably the best place to look for the full pricing details, by the way. Only Platform Users? I should note that you can't have an org entirely on platform licenses , as far as I know. You have to have at least one full license as a system administrator. This wouldn't be a concern for a nonprofit that's going to get the Power of Us license grant, of course. But for everyone else (including nonprofits that are building a second Salesforce instance) it's way cheaper to have one or two full licenses for sysadmins and then all the rest be platform users.
- NPC Platform Users?
Just after I wrote my post about using Platform licenses , I got an email from a reader asking about the idea of using platform licenses with Nonprofit Cloud (NPC). The funny thing is that I had considered whether or not to mention NPC when I was writing, but, in the end, decided that it would just add confusion and length without helping people. I'm going to leave aside the question of whether an organization should be using NPC in the first place. (I think I've written enough about that elsewhere .) The real questions are whether platform users are compatible with NPC (or any Industries solution like Public Sector Cloud, Health Cloud, Education Cloud, Manufacturing Cloud, Financial Services Cloud, etc.) and how the costs would work . By the way, I'm going to just write "NPC" for the rest of this post. But as I understand it, what I'm writing would apply to any of the industry clouds. For any platform user that was going to touch any of the NPC objects (“standard” objects...but not really ), you would have to have a permission set license (PSL) to assign to that user. When you buy "one more user" for nonprofit cloud, you actually get a license (user login) and a PSL, bundled together. I do not know if you could get an AE to sell you PSLs separately from full licenses. And if you could get them to sell one, what would they charge? It might be that they’d charge nearly as much for only a PSL as they were offering to charge for a full license + PSL. Now You See It Regardless, without a PSL assigned, even a full user can’t see the Industries objects. So any user that was going to “use Nonprofit Cloud,” in the sense of actually seeing any of the objects or fields that are part of that offering, will need a PSL. This will reduce your pool of PSLs compared to your pool of full user licenses. And keep in mind that “part of Nonprofit Cloud” also means the Industries-based program management offering, outcomes measurement, the upcoming volunteer management functions, etc. I suspect that there’s probably no technical reason you couldn't assign a PSL to a platform license—it seems about the same as assigning one to an integration user. I can't test this assumption, however, because I don't currently have any clients on Nonprofit Cloud, much less any that also have a platform user. Let me also note that currently, if you assign a PSL to an integration user, you already find yourself one short for assigning to humans. I asked about this problem at True to the Core during Dreamforce 2024 (and the same problem that applies to the Marketing User checkbox). I've been promised that a fix is coming, but not very soon. Maybe Users Don't Need to See It Of course, if you have an NPC org and some users that are going to do things that are not within the Industries objects , you should be able to use platform licenses to your heart’s content. Even if your configuration involves person accounts (due to that being a required part of NPC), platform users can handle it. (I set up a client with platform licenses and a person account setup before NPC even existed.) I don't know if platform users could see Industries components on your page layouts (like Timeline, Interaction Summaries, or R2D2s). But maybe you just wouldn't use those components . Plenty of non-Industries Salesforce instances get along just fine without those components. Or they use AppExchange options that work as well or better. (I'm looking at you, Timeline .) Money on the Line If you are a wealthy or large enough organization to be considering NPC (or any other Industries product), then you've already made the choice that most of your user licenses are quite expensive ($720/year for NPC, much more for the for-profit offerings). Trying to save money by putting some users on platform licenses seems like it might not be the right question. And, of course, I've argued more than once that small organizations are not a good fit for NPC (or other Industry clouds). So in that case it seems not really worth asking whether you can use platform licenses with NPC...
- Introducing IceTea!
Today I'm writing to introduce a cool and useful tool that my son, Arden , developed. I'm actually rather late in writing about this—Arden made this for me over a year ago. (In case the IP Police are listening, IceTea was developed long before Arden even applied for his current job. So don't click on his LinkedIn and assume it has anything to do with where he's working now that he's graduated college.) Despite too much delay, I hereby present: IceTea . What Is IceTea? IceTea is a little utility that does two things: Open a database (stored as a .sql text file in your CumulusCI repo) in Excel. Convert that Excel file back to .sql after you've made changes to the rows. What is so delicious about it? When you store a dataset using CumulusCI it takes the form of a SQL database in a text file. Though it's theoretically possible to hand-edit if you need to change a value in that table, it's rather inconvenient. And if you want to add values for blank fields (represented by ". '', " in the table), good luck getting the right place! Using IceTea, though, you can look at that same table in Excel: Now it's easy to see who needs a Title and to add Descriptions to the right people. Where can I get some? IceTea needs to be installed on your computer, not into Salesforce. Just go to IceTea's GitHub repository and follow the instructions. ** Disclaimer: Only install the IceTea software package to your computer. Do not bring iced tea or any other liquid into contact with your keyboard or any other part of your computer. Such actions usually result in undesired outcomes . [Our lawyers insisted that we write this.] What Else do I need? IceTea was developed for use with CumulusCI (or CCI, for short). You pretty much have to be using CCI for IceTea to be helpful to you. CCI is a development tool originally created by Salesforce.org to make it easier to develop NPSP and the other nonprofit packages. I'm gonna be honest and admit that I don't really know who is maintaining CCI at this point or how much love it's getting. As I've said many times: I'm not a developer . I'm not using CCI for any of its features around managing GitHub repos, automating testing, or the like. I use CCI because it has one particular superpower that I haven't been able to get anywhere else: It can automate storing and inserting a dataset into a Salesforce org, keeping relationships between records intact . That's super powerful (and probably deserves its own blog post)! By storing a dataset for a client in CCI, I can create a sandbox and then put in a set of representative data, including contacts, their accounts, opportunities (donations), and any other custom objects I need. The biggest frustration I hear from admins talking about not building in Production is that when you create a sandbox it has no data in it. It's hard to test a new flow if you don't have a record for it to fire on. And if your org is at all mature, getting data that looks like reality means filling a lot of fields and creating an interlinked set of records to represent, say, a class, the enrolled students, the dates on which the class meets, etc. Using CCI you generate a mapping of your org's custom objects and fields, download the data that's in your org (please do this from a sandbox, not production!), store it, and push it into another sandbox with all the relationships intact. For free! Working with a command line tool has been a learning curve for me, but it's incredibly helpful. How do I use IceTea? Once you have the prerequisites out of the way (a CCI repo, with a dataset file), there are just three steps (two commands): icetea in - Running this command will take your dataset.sql file (like the dark screenshot, above) and open it in an Excel worksheet. Each object will be in its own tab. Make the modifications you need. Do not mess with the header cells of the sheets, as Arden has done some special work there to store information he needs in the conversion. It's safe to reorder columns and tabs for human convenience. And the real point is to update the data. So, for example, you could take a downloaded dataset where no contacts have a Birthdate and add dates for everyone. Or take a bunch of emails and replace them with ".invalid" or the like. icetea out - This command will convert your sheet back to dataset.sql and delete the temporary Excel file. Simple and satisfying, just like a nice glass of iced tea!
- An Improved Reports/Dashboards Tab?
Every time I teach a new user about Salesforce I cringe when I get to the point of showing them the Reports tab. On the one hand reports and dashboards are one of Salesforce's great strengths . Free and out of the box you get instant ability to pull out the data in your system, slice, dice, and visually display, and more. (Unless you're trying to report on the NPC data model . But that's a different issue.) Unlike lots of other systems, Salesforce is not limited to a handful of canned reports and at the mercy of your platform provider to build new or custom reports. That's super powerful! But after giving a tour of record pages, relationships, and data entry, when I direct the user to click on the Reports tab I suddenly have a different user interface. Unlike all the other object tabs, where I can show users how to change the default list view that loads and pin their favorite, Reports always loads to Recently Viewed. Plus the navigation is via links on the left side. And there are folders to navigate... Not that any of this is particularly difficult, of course. I suspect everyone reading this blog is so used to it at this point that you barely notice. But inconsistency doesn't do anyone any favors when learning the platform. And can I just state for the record how annoying it is that there is no New button under the Reports tab carat, like there is for all object tabs? Having to click to the reports tab before clicking New Report has to be one of the biggest time wastes in all of Salesforce. Several releases ago Salesforce came out with Analytics Home . As is the company's pattern, they made a small publicity push at the time but it's basically fallen off the radar. In some recent conversations I was reminded of the page and wondered if there was cause to give it another look? Still Inconsistent The first thing you notice if you go to the Analytics tab is that, if anything, it's more different than the Reports tab is, not less! I assume part of the reason for this is due to this page combining the Reports tab and the Dashboard tab, hence the Create button, instead of a New button. That, at least, isn't such a big deal, so I can cut Salesforce some slack. (But honestly, wouldn't three buttons have been better?) Other than that, my first impression is that Analytics is not that dissimilar from the Reports tab or the Dashboards tab. Navigation is on the left, there are no customizable list views, and it basically defaults to Recently Viewed. There are some large cards that take a chunk of screen real estate. (It's debatable whether the tradeoff there saves time or clicks.) So far, this feels like "a distinction without a difference," as one of my high school teachers used to say. Slightly different interface compared to Reports (and Dashboards). "Two tabs for the price of one," I suppose. Still inconsistent with the rest of Salesforce. At best, I'd say it's debatable whether this is an upgrade. And those of you who know me should already anticipate two things I'm really disappointed by: There is still no option to start a new report from the tab header. It actually takes one more click to make a new report than it did before. (Analytics tab. Then then Create. Then New Report.) Now the Bad News But now let's get into the things you only notice if you try to use this "feature." Items Don't Load to URLs The section title kinda' says it all. When you go to a report from the Analytics tab you somehow remain at the same URL! https://yourcustomdomain.lightning.force.com/lightning/page/analytics Most of the time, this probably doesn't matter. But as soon as you want to grab a link to the report so you can send it to someone, you're out of luck. OK, not entirely out of luck. There is a new Share button if you've loaded a report from here. With that button (and one more click ) you can copy the URL for this report. But that's yet another difference from the normal interface where we've taught our users to grab the URL for sharing. By the way: The Share button doesn't give the regular report URL—it's about tthree times as long. Clicking on that special link ensures that you load the report as though you'd come from Analytics Home. This feels like a step backwards. No Chatter! Last post I wrote about using Chatter on Reports and Dashboards . Look at that last screenshot. It has no Collaborate button! As I noted in that prior post, I know Chatter's days are numbered, eventually to be replaced by Slack. But are we supposed to conclude that if you get there from the Analytics tab for some reason collaborating on reports and dashboards isn't a thing? Surely it is. So how are you supposed to give context for which report or dashboard you’re working on? And why wouldn't we want to collaborate right on the report itself? "Navigation breadcrumbs" The official Help docs on Analytics Home excitedly point out that, "Navigation breadcrumbs are activated when you open a report or dashboard." That sounds nice. But those breadcrumbs just give you a link back to Analytics Home: Home > Lightning Report It doesn't list the folder. Doesn't give the report's name. Presumably the Analytics tab is part of your app navigation in the first place! Honestly, if you can't tell whether you're in a report, a folder, or a dashboard at a glance, the navigation breadcrumbs aren't going to help orient you that much. Oh Well I don't know what else to say. I see no point in the new Analytics Home.
- Chatter on Reports and Dashboards
I bet a lot of you didn't know that you could turn on Chatter for reports and dashboards. This is one of my favorite quick little tips. You can enable it with just a couple of clicks and then you instantly gain the ability to collaborate right in context about reports ("Does this have all the columns you need?") or dashboards ("Take a look at the Dashboard of Zeros, we have some data that needs cleanup!"). Shall I give you the step-by-step instructions? Step One: Enable Feed Tracking Go to Setup>Chatter>Feed Tracking and then select the Dashboard object. Click the Enable Feed Tracking checkbox and then Save. (Repeat for the Reports object.) That's it. There was just one step. Using Chatter on Reports and Dashboards Now that you've enabled it, simply go to a report or a dashboard—you may need to refresh your page—and you'll have a button that wasn't there before: a "conversation" icon. (It's subtle, but those are two speech balloons.) Click that button and a Chatter pane opens from the right-hand side. Now you can post an update, @mention one of your colleagues, or respond to conversation right in context. This is also a great way for one of your colleagues to ask if they have questions about a report. Anyone they @mention will get a notification with a link directly to the report being asked about. It doesn't get a much easier than that! [Update 7/7/2025- Hat top to Julie Arnzen for the note that you may need to adjust your Global Publisher layout to make sure it has Post on it. Otherwise you'll get the Chatter pane but without the ability to write a post.] My Favorite Thing Truly my favorite thing about using Chatter on reports and dashboards is that it removes a lot of the back-and-forth when someone asks about something that seems obvious to them but isn't to me. Like an email that says, "The dashboard looks like it needs updating." For the person that just sent me that email, it seems obvious which dashboard they are talking about. Perhaps, as far as they're concerned, their organization has only a single dashboard, or at least only one that gets used regularly. But I don't have much confidence in my ability to be sure which dashboard that might be. So I have to write back to ask. At that point they're likely to just give me a name, not even a link to the right dashboard. Names aren't always as unique as people think. So I still have to search around to be sure I'm answering what they are actually asking. But if I get a Chatter question about a dashboard, I know exactly which one they mean. It's like an Easy Button to start the conversation. [With a conversation about a dashboard, there are plenty of opportunities for confusion about which component and which underlying report they have questions about. But at least we've narrowed the focus...] Also Useful in Other Places I think Chatter is a very cool feature—and often underutilized. If you teach your users about it (plus enable it and put it on page layouts) Chatter is a great way to collaborate within Salesforce. And just like I mentioned above, it saves a lot of time figuring out which records people are talking about. So much better than copying the URL to send an email about a record! Side Notes Two things before closing out today: Chatter might not last forever. Salesforce doesn't seem to care that much about Chatter anymore, particularly since their acquisition of Slack. In fact, Parker Harris has said, half- (or less) jokingly, that he intends to kill Chatter . As with other Salesforce retirements/deprecations, I expect this will be a very very slow death. But I wanted to acknowledge this fact. If/when Chatter is entirely replaced by Slack I have no idea how this kind of collaboration will change. And if your organization doesn't use Slack, I can't speculate what that would mean in your situation. Make Sure Email Notifications Work! In the Winter '24 release Salesforce made a change that required you to take action to ensure that notification emails about Chatter posts are sent. This flew under the radar for a lot of people, so you want to make sure that it's set properly in your org (or all of your client's orgs). If you start trying to collaborate on reports and dashboards using Chatter and the only notification people get is on the little bell in Salesforce upper-right toolbar you're going to have rather one-sided conversations!
- Thing I Learned: Flow Entry Formulas
So here's one I learned the hard way: Until a few releases ago if a field was used in a flow entry formula it would not register with the Where is this used? button. And you wouldn't be prevented from deleting that field either. If you have flow entry conditions , built one field at a time in the builder, that would register show in Where is this used? as well as prevent deletion. But put the same conditions, with the same fields, into a formula and there are no guardrails. Yikes! So...first the good news: Salesforce has fixed this . I don't know exactly in which API version the fix rolled out, but flows on the last few releases do not suffer from this problem. (As of writing we are on API version 63, with 64 rolling out very soon.) The issue, in fact, should not occur for flows that use a version somewhere in the high-high 50s or early 60s. But just because your org has been updated to Spring '25, that doesn't mean that your flows have. If you start building a new flow, it will be on the latest API version by default. But your old flows do not get updated. Even if you save them as a new version, unless you take intentional action to update their API version, flows stay on their original version. So you could have flows in your org that will suffer from this bug. How I Really Learned This Funny story. I had actually seen a thread in Salesforce MVP Slack several weeks ago that mentioned this issue. At the time, I remember thinking, "That's potentially bad." But one of the flow Product Managers replied that the issue had been fixed a few API releases ago. With that in mind, I filed it under "interesting" and moved on with my day. Then more recently I wanted to do some cleanup in one of my client orgs that's been around for a while and has, for the whole time I've worked with them, had a bunch of fields with names like zStart Date Report and zDep - OAG Client Status or other artifacts left over from their initial implementation and migration from a prior system. I confirmed a whole bunch of fields were not on any page layouts and had never been used and then I started deleting them. In the course of that work, I noticed that there were two fields on Case whose purpose was clearly duplicative: Admin Touch and Tickle Record. If you're not familiar, these names may make you chuckle. But I knew immediately that these were fields meant for a single purpose: An admin could update that field, which would count as an edit on the record, thus kicking off any record-triggered flows. I like to keep a field around on most objects to use for this purpose. In fact, "Tickle Record" is often a name I would use for such a field. Indeed, that field was built by me (and properly documented exactly for that purpose). Admin Touch was also properly documented, it had just been created before I came along. Clearly I hadn't noticed it before I made my field. But now we had both in the org and needed only one, at most. Since I was already on a field deletion kick, now was the time to clean this up. I decided I would keep the one I'd built—it was an arbitrary decision. So I deleted Admin Touch with nary a second thought. I had checked Where is this used? and it wasn't on any page layouts, nor in any reports, nor anywhere else. And the deletion went through without any hesitation. Then a few hours later I get an email from the organization's sysadmin forwarding an email she'd gotten from another user, who was getting this error: Honestly, it took me longer to read the error message than to realize what had gone wrong. I immediately remembered the Slack thread. And it had only been a few hours since I'd deleted the Admin Touch field. It was easy to undelete Admin Touch to stop the error from happening right away. (I had to undelete it and then remove "_del" from the API name of the restored field, of course!) Then I went into the flow that was mentioned and saw that, indeed, Admin Touch is mentioned in an entry formula, not in conditions. And when I checked the flow's Properties, it turns out to be on API 57. (So we know the problem was fixed somewhere after API 57...) By the way: While grabbing screenshots for this article from a sandbox, I confirmed that while the flow is on 57, Where is this used? for Admin Touch does not show the flow. But if I save a new version of the flow at 63, it shows. Empirical proof for the win! (I suppose that if I cared enough I could save the flow at 58, check Where is this used? , then try again at 59, etc... until I found the point where the bug was fixed. But I'm sorry readers, I'm not quite that dilligent!) The Takeaway: You Need to Update Your Flow API Versions I leave you with some homework: update your flows to newer API versions . Here are the steps: Working in a sandbox , of course, open the flow. Select Save As New Version. Click Show Advanced. Scroll down to API Version for Running the Flow. Select the latest version. (If you're working in a Preview sandbox you won't be able to deploy because it will be one version ahead of production. So know your versions and consider whether you have to save one version lower.) Save. Activate Test. Deploy to production. Repeat for every other flow that's on an older API version. This is probably basically busywork, of course, and I'm sorry about that. But I don't really think there's much risk in just saving as a new version, updating the API, and activating. You ought do to this in a sandbox and test the flow at the new API version before you deploy. But we both know the realities of life. Your org's metadata governance and testing requirements might be more stringent, of course, so perhaps this will be a bit of a hassle. But at least I've told you why it would be worth the effort! Full Disclosure: I haven't done this for most of my clients yet. But I intend to...eventually...
- Stack Platform Licenses
One of the best ways to save on the cost of your Salesforce licenses is to have users on Platform Starter licenses. At $25/user/month list price (and just $6/user/month for nonprofits) they're a pretty inexpensive way to get your colleagues into the system. (Remind yourself about login pricing at the Crowdsourced Salesforce.org Pricing Guide .) There are limitations on logins though platform licenses, so you have to think carefully about what those users are going to do in the system and potentially make architecture choices to account for having users log in that way. But I bet you didn't know that you could stack platform licenses. That's a neat trick I learned about relatively recently. With some careful planning, design, and documentation this could be a way to save your org money year after year. Platform License Limitations Let's start with what platform licenses are: they're a cheap way to get onto the Salesforce CRM platform , but not the standard applications (Sales Cloud or Service Cloud). Most people barely distinguish "the platform" from "Sales Cloud" in the first place. [And in the nonprofit context, where we get access to most of the Service Cloud features at the same time in our P10 grants, I think we don't really consider either Sales Cloud or Service Cloud to be distinct from just "the plaform."] But Sales Cloud is a specific app built for tracking sales deals, which is to say, Opportunities, Products, Leads, and Campaigns. (Marketing and the Campaign and Lead functionality were originally part of Sales Cloud, even if now marketing has an entire life—and cloud—of its own.) But they can access Accounts, Contacts, Reports, and Dashboards, even Cases. ( Look here for the full breakdown .) The limit we most often focus on for platform licensing (and the point of today's post) is that Starter licenses can only access ten custom objects . They access unlimited custom objects that are installed by managed packages. But if you're creating your own customizations, you'll be limited to ten of your custom objects. Platform Plus licenses can access up to 110 custom objects, which seems like it's pretty effectively "as many as you want." But Platform Plus licenses cost four times what a Platform Starter costs, so the jump from ten to 110 objects might not seem worth paying for. More on that in a moment. Nonprofit Success Pack (NPSP) NPSP is a managed package, so you can use a lot of NPSP functionality on a platform license. Relationships, the Household Account Model, and Affiliations to multiple accounts are all available using platform licensing—and those are some of my favorite features. But to the extent that NPSP is focused on nonprofit fundraising , without access to the Opportunity object your platform users couldn't do that. They could still see the NPSP rollups that summarize giving, since those show on the contact and on the account. So you have the option of putting fundraising users on full licenses and program management users on platform licenses. I've done that with some of my clients. Need More Custom Objects? But what if your program management implementation—or any other use case, including not-nonprofit ones—is architected to need more than ten custom objects? That's what I really wanted to talk about. You can "stack" platform licenses. (I can't actually point to a specific policy document to prove this, or I'd give you a link.) But I am told by more than one source that this is an officially-allowed way to work with platform licenses. If you need to give a platform user access to, say, 15 custom objects, you just have to assign them two platform starter licenses . That's still quite a bit cheaper than paying for a full license, or even a Platform Plus. Here are list prices compared: Platform Starter = $300/year x2 = $600 [Nonprofit: $144] Platform Plus = $1,200/year [Nonprofit: $288] Full License ("Sales Cloud" or "Lightning Enterprise Edition") = $1,980/year [Nonprofit: $495] So until you need your platform users to get 40 custom objects, you still save money by stacking compared to upgrading to Platform Plus. (And I guess if you're hitting 40 custom objects, 110 is not too far behind, so you'll eventually need Platform Plus? That's a lot of objects!) How to Stack But... There isn't a way to actually assign two user licenses to a single person. To stack, what you're going to actually do is assign one and leave a second unassigned for each user in this situation. That's going to look a little confusing in Company Information. Every time you open that screen it's going to look like you've got a bunch of extra licenses you shouldn't be paying for. I have suggestions on this front: Make it clear with your account executive that you are intending to use license stacking. You may need some back-and-forth on this, as some AEs also probably have never heard of this. Do your best to get the final acknowledgement/approval in an email. Save that email for future reference. Document that your organization uses license stacking so that future admins will know this is how things work. (That documentation should include that email from #1.) Carefully document who "has" two licenses, particularly in case Salesforce should ever decide to audit your account. (Might I suggest an object for tracking this...?) Be Honest One final note: Given that this is both out-of-the-ordinary and pretty rare, I don't think Salesforce is looking for it. I suspect that you're basically on the Honor System to assign one and set one aside. Be honest about it. By allowing this, Salesforce is being reasonable, even flexible. So don't ruin things for everyone by trying to pull a fast one. Really set one aside. Really document that you know that you have extra licenses but that you can't/won't assign them because they're "in use."
- How I Solved It: File Deletion Flow
I know I'm not the only one that thinks it's a pain to work with Files in Salesforce. Stories of frustration, confusion, and downright bafflement abound. The object structure for what seems like a relatively simple and convenient File uploader on the page layout is anything but simple under the hood. ContentDocument , ContentDocumentLink, ContentVersion, ContentHistory, ownership, permissions, ... The list of considerations just keeps going. I could probably try to write a post explaining it in simpler terms but, frankly, I don't think I really understand it, so I would probably just lead you astray in some way. But I recently built something that turns out to be surprisingly simple and solves a common problem with Files, so I'm going to share that with you instead. The Business Problem Lots of organizations use Files in Salesforce, usually in the ways you would pretty much expect. You're working with a record, there is some kind of file related to that record, so you upload it for easy access and reference. This could be a photo of a contact, or a signed contract, or a mail-merged letter generated from the record that you are going to send out to a constituent, or a million other things. Let me introduce you to For Pete's Sake (FPS), a great organization that works with cancer patients and their families to give them "a break from cancer," a respite experience in which they can be together as a family to bond away from the day-to-day of regular life. FPS does their program management on Salesforce. After a patient is nominated, FPS staff goes through a series of steps to "onboard" the person and their family and get them ready for the respite experience. Most of that work is done on a custom object called Onboarding. In the course of working with the onboarding record, we have various files, including online forms that the participant fills, a family photo the patient sends, and the like. A perfect use case for Files! I've been working with FPS for two years, but I think they were using Files before I came along. I'm not even certain their original Salesforce implementer taught them to do so, so much as that they may have seen the Files related list and adopted it organically. (For a while they were also separately uploading the files to Box.com, a bit of duplicative work that I'm not sure they could articulate the value of.) Several months ago I worked with FPS to regularlize some of their usage of Files and to implement some automatic document generation to replace documents they were manually creating from a Word template and then uploading to the onboarding record. So far, so good. Basic Files stuff. But with the automatic document generation, naturally, we started to find some cases where the "final" version wasn't so final. Perhaps the dates of a respite trip changed. Or perhaps some mistake in the onboarding record is noticed just before the "Final Letter" is about to go into the box being mailed to the patient. These things happen. And FPS was savvy enough to realize that generally the solution here is to just re-create the document and upload the new version, whether that's a manual process or the re-trigging of some automation. But in those cases, the incorrect file is still attached to the record. That's likely to create some confusion! When asked what was the "right" way to deal with this, I just told them, "Go ahead and click Delete on the original file." Silly me, assuming they had the same options I see. They have no delete option on the file! I delved into permissions, but that wasn't the issue. If the original file was uploaded by one person and someone else is now working on the record, they can't delete the old file—it's not a question of permissions. Files can only be deleted by the person that originally uploaded them (the file's "owner") or by someone with Modify All Data , like a system administrator. I was seeing a delete button because I have Modify All Data permisssions. I even confirmed that if I gave Modify All Data to one of the program coordinators, she then could delete. But I really don't want to give Modify All Data to people. (There's a reason we abbreviate it as MAD!) Besides the implications for data security, I really hate the user experience that we get when we have MAD, where even fields that are Read Only on the page layout show as editable. Let me note a few other things about this problem: It's not that Files (ContentDocuments) have some kind of sharing model. It's simply binary: You own the file or you don't. You have Modify All Data or you don't. Before I managed to solve the actual issue, this meant I had a workaround: Get people to tell me when a file needs deletion and I can do it as the sysadmin. Not exactly efficient or automated, but at least I can keep things clean. While it's ContentDocument that stores the file, it's ContentDocumentLink that relates the file to a record. If you delete the latter, the file is still taking up storage on Salesforce servers, if you care. (Maybe I shouldn't , but I do.) I've also learned, through much trial and [mostly] error, that the Content Whatever objects have other annoying limitations. The worst: You can't really access ContentDocumentLink in SOQL. You have to query for only a single ContentDocumentId . ( But if I already knew the Id, I wouldn't need to be querying! ) You can't really work with Content Whatever in the UI. Generally you can't add fields, there is no page layout, you can' modify the Files related list... You can't make record triggered flows on Content Whatever . (Even if you could, it's not like you could change the sharing in some useful way.) Community to the Rescue? As soon as I saw that Help article linked above I knew I was going to be in trouble. But there are some smart people in the Trailblazer Community! Maybe someone had solved this before? Further searching was only turning up more commentary on the problem, not much in the way of solutions. Eventually I posted some questions online and get traction on this Ohana Slack thread . Erik Lopez suggested that perhaps a screen flow could assign Modify All Data, allow a user to delete a file, and then revoke Modify All Data. Interesting... But the first thing I realized is that you can't actually put a screen flow onto a File. (There's no page layout nor Lightning Record Page for files.) My screen flow is going to have to go on the onboarding record. And that means the screen flow is going to have to present all the available files for the user to choose which to delete. Now we've run into a different problem. How I Solved It, v1 Thought work complete, I set about seeing what kind of screen flow I could build. Step One: spin up a sandbox just for this purpose. Besides being a general "Best Practice," this is going to have some additional benefits: I don't have to worry that I upload a bunch of files and they're going to take up storage forever. I can make a bunch of test Onboardings and put files on them without confusing users. I won't have any chance of deleting important files in production. Remember, above, that I said working with these objects in SOQL is a pain in the neck? If it's hard in SOQL, then it's not going to be easier using Get Records elements in flows. It took me a little bit of fooling around, but I eventually realized that the screen flow was going to pass in the record Id of the onboarding and I have to Get all the ContentDocumentLinks that attach files to that record . Then I'm going to show those ContentDocumentLinks in a datatable for the user to select which to delete. [And here's a surprising early win: I'm going to be able to use the standard component from Salesforce. As much as I love and appreciate the Datatable from UnofficialSF , I'm happy to be able to make this flow with standard components.] Sadly, even though my Get Records is set to "Automatically store all fields," I found out that none of those fields is the filename . Clearly the users need the name to select which is the right file to delete—the Id of the document is not going to be useful. It's not an option to add a formula field on ContentDocumentLink that spans to the file. I'll spare you the details, but suffice it to say that I tried everything I could think of to get that title to display from the ContentDocumentLink, to no avail. Eventually I admitted defeat and tried looping over the ContentDocumentLinks to get the related ContentDocuments. In the Wins column: This works. My datatable on a screen right after the loop (not shown) can show columns for the filename, owner, and creation date. Yay! But I'm executing SOQL within a loop, a rather big No No. That is not efficient and it runs a good chance of running up against governor limits . Side note: Realistically, I could have just taken the win and moved on. This screen flow is going to run only on records that have fewer than ten—often fewer than three—files attached. It will work. The extra computing power used is negligible. And the screen after the loop starts a new transaction with a new set of governor limits. But that pink element within a loop did not make me happy. How I Solved It, v2 Tip o' the hat, again to Erik Lopez who suggested that we could probably avoid the SOQL in a loop if within the loop we assigned the Title from the ContentDocumentLink to a text variable. In that context I am able to span through the relationship (ContentDocumentLink > ContentDocument > Title) and get to the title of the file. In fact, I replaced the pink element from the version above with an Assignment that sets three fields on a record variable: the ContentDocument Id (the Id of the actual file ), the Title, and the Created Date. (If two files have similar names, this might help the user delete the right one.) All the fields I need to show in my datatable on the next screen are now waiting for me. Here's the entire flow: In words it: Gets ContentDocumentLinks related to the record. Loops over them assigning variables. Adds those variables to a collection. Has a screen with a datable to select one ( only one ). Follows up with an "Are You Sure?" screen. Then deletes the selected file. Reduce, Re-use, Recycle ♻️ I realized after building it that this flow is actually 100% object agnostic . Though at the moment I'm only planning to put it on an onboarding page, the flow itself does not care what page(s) it might be put on. It accepts (actually requires ) a record Id as input. But that's just a text string. Using that Id, the flow loops over ContentDocumentLinks and finds information about the related ContentDocuments. The same screen flow can run from any object, passing in its Id, and the Get Records (screenshot above) will work without any modification. I can use this in other places within For Pete's Sake's Salesforce or even deploy it to other client orgs and use it there exactly as built. That's pretty cool and pretty rare, in my experience. Try This At Home! This is a pretty handy little flow and something you should be able to build for yourself using just this blog post. So go try it and let me know what you find! Your Org Might Be Different But before I send you off to your Flow Canvas, I want to make explicit a few of the considerations and tradeoffs in the way I have built this. You might want or need to make different choices. System Context, No Sharing I noted, above, that Erik Lopez suggested I could assign a permission set with Modify All Data, allow the user to delete the file, and then revoke the permission set. But you see that I didn't do that. Instead, I have the flow running in "System Context Without Sharing—Access All Data" a setting available in the Advanced Settings when you save a flow. This made for a simpler flow that was easier to build—I didn't need to find and assign a permission set, then revoke it at the end. Your comfort with this setup may vary. Deletes the File (ContentDocument) Directly As noted in the warning on the selection screen, my flow deletes the File (the ContentDocument), which cascade-deletes any ContentDocumentLinks sharing it to records. I could have built the flow to un-share to the record (delete the ContentDocumentLink to the record). But in For Pete's Sake's use case we are confident that the files are only attached to one record. So if we were to un-share, then the file would just be orphaned and taking up server space for no reason. I'm confident that deleting the file is the right action to take. In theory there could be a share to another record. Certainly in your org there could be shares to other records. In that case, you might need or want to delete just the ContentDocumentLink. But then you have the possibility of orphaned files that you might want to deal with. I can think of a few suggestions: Add a notification to the sysadmin that there is a file no longer shared to this record. (Note: The admin is going to have a challenge to find files with no ContentDocumentLinks. It's possible in SOQL, I think, but...) Delete the ContentDocumentLinks, leave the file orphaned, create some kind of cleanup via a scheduled flow that looks files with no ContentDocumentLinks. Again, I think this is possible, but it could have unexpected challenges. Have the screen flow check if there are other links to the file, only deleing the file if there are none. But if there are additional ContentDocumentLinks and your user is deleting this file because it needs to be updated, then you have other issues. Versioning This is a perfect segue to come back to the idea of versioning. As noted above, the Content Whatever pile of objects includes ContentVersion, which exists so that it's possible to save multiple versions of files in Salesforce. In the For Pete's Sake use case, for example, it might be that the "right" solution would be to actually update the file version , rather than deleting and re-uploading. But figuring out how to do that would be even more complicated. I decided not to even consider that path. I'd love to hear if you've ever used versions. Does Anyone Use This? As noted, I'm not sure how many orgs use versions. In addition, my gut says there are very few orgs that actually take advantage of the ability to share files to multiple records in the first place. It's an interesting idea and technical setup and I can see why Salesforce wanted to build Files that way, but it seems cumbersome to use, at best. Let me know if you think I'm wrong!
- Thing I Learned: NPSP Contact Role Triggers
Did you know that the NPSP triggers that automate opportunity contact roles (OCRs) are essentially built on the assumption that nobody will ever manually update opportunity contact roles ? I didn't know it. I knew that people would rarely do so. But I've always showed them that it could be done and left the buttons on the page to do so. I think this is a reasonable assumption, honestly, but it's a pretty big one that has some major implications, so I'm very surprised we (the nonprofit Salesforce practitioner community) have basically never talked about it. I feel like this should be one of those things we all point out regularly so that it doesn't slip through the cracks! What They Do The NPSP triggers exist to automate creation of opportunity contact roles for donors, matched donors, honorees, household members, people affiliated to the organization giving a donation, or people with a relationship to the giver. In the most concrete terms, the triggers create opportunity contact roles for the people that are in several NPSP fields: Primary Contact (on Opportunity, fieldname npsp__Primary_Contact__c) - This one's pretty easy to understand. Whoever is in the Primary Contact field will get an opportunity contact role and that role will be the one designated as Primary. Honoree Contact (on Opportunity, fieldname npsp__Honoree_Contact__c) - Whoever is in this field will get an OCR as the Honoree. [Actually, they'll get whatever role is set in NPSP Settings>Donations>Contact Roles>Honoree Opportunity Contact Role.] Notification Recipient Contact (on Opportunity, fieldname npsp__Notification_Recipient_Contact__c) - Gets the OCR set in NPSP Settings>Donations>Contact Roles>Notification Recipient Opp Contact Role. If there is an opportunity that is set up as a matched donation, then the primary contact of the matched donation gets an OCR set in NPSP Settings>Donations>Contact Roles>Matched Donor Role. And the triggers also create OCRs for people based on a few bits of logic: Household Members - Based on the settings in NPSP Settings>Donations>Contact Roles>Household Opportunity Contact Roles, members of the household that gave the donation all get OCRs. If a contact has an affiliation to the account that made a donation, then if there is a value in the Related Opportunity Contact Role field (on Affiliation, fieldname npsp__Related_Opportunity_Contact_Role__c) they will get an OCR of that role. If a contact has a relationship to the primary contact of a donation and there's a value in Related Opportunity Contact Role (on Relationship, field name npsp__Related_Opportunity_Contact_Role__c), NPSP will create an OCR of that role for the related contact. As long as you are just using those lookup fields and settings to manage opportunity contact roles, all is right with the world. The NPSP triggers will ensure that your donations will all have the OCRs as I laid them out. They're even smart and will only give any given contact a single role, based on logic for what takes priority . So far, so good. How They Do It It's how the NPSP triggers actually manage those OCRs that surprised me. Essentially, the triggers wipe out and re-create all the OCRs whenever there is a change to a donation that would warrant a new look at who should have contact roles. At first glance, you might think, "That's lazy programming. They ought to loop over the OCRs and only touch the ones they need to modify." But until the Spring '20 release Opportunity Contact Role was not a first class object, which meant there were limitations of what automations could do with them. When NPSP was being developed, therefore, the developers had to come up with workarounds. One was this compromise that NPSP wipes and re-creates all the OCRs, rather than looking at the OCRs that already exist and evaluating whether they need deletion or modification. The [rarely stated] corollary to this compromise is that NPSP assumes that nobody ever manually creates OCRs because any OCRs that have been added to an opportunity, or auto-created ones that have been modified in some way (such as to change a role), will get wiped out if there is a change that otherwise necessitates NPSP to evaluate and create OCRs. NPSP actually does have provision for organizations that want to manually add and modify OCRs. There is a checkbox on Opportunity called Disable Contact Role Automation (npsp__DisableContactRoleAutomation__c). Its help text states, "When selected, this field disables several aspects of NPSP Opportunity Contact Role automation, potentially resulting in incorrect or duplicate data. Refer to the product documentation for more details." In plain English: When you check that box on an opportunity, no OCRs will be auto-created for that opp. None. There is no in-between. If you check that box on an opportunity, even the Primary Contact will not get a contact role. If you leave it unchecked, any contact role you create using the New button, or any modification you make, is in danger of being wiped out. How We Noticed This I have a client, Modern Classrooms Project , that gets money both through fundraising and earned revenue, primarily the latter. For their earned revenue they're basically using standard Sales Cloud functionality. But on those earned revenue opportunities they use the Primary Contact field. (It's a super-handy way to immediately see who you should talk with about an opp.) When you put someone in that lookup NPSP gives them an OCR, marked Primary. Meanwhile, the sales team also adds other opportunity contact roles to the deal, keeping track of other people involved. But since contract negotiations can take time, sometimes the primary contact will change, of course. We recently realized that if you change the primary contact on the opp, the NPSP triggers wipe out all those other OCRs that the sales team has curated. Oops! An Easy Fix? Clearly, it's not that big of a deal for us to fix this. We just have to ensure (thorugh a Before Save flow) that all earned revenue opportunities check Disable Contact Role Automation . That ends the danger of losing data. If we wanted, we could leave donation opportunities to still have the NPSP OCR triggers, but we should probably, in that case, remove users' ability to make any manual OCR edits on the page. But we also have to deal with the fact that the automation around who is in the Primary Contact lookup is now disabled. Again, this isn't a huge deal, but it's not nothing either. I see two choices: 1. Build a flow to replicate NPSP's automation around Primary Contact . 2. Teach our users that there is no contact role automation, they have to create roles for everyone. (We'll probably go with the first option, since it's a lot more convenient for the users.) Implications for Your Org? Lastly, let me leave you with a "call to action": Consider your organization's use of the NPSP contact role triggers. If you have a hybrid situation, like I just described for Modern Classrooms, then you may have some work to do. If, as I think is the case for most NPSP orgs, you just want the out-of-the-box NPSP contact role functionality, then make sure that your users can't manually manage OCRs. Take the New button off the opportunity contact roles related list. And probably also Edit, while you're at it.











