Search Results
78 items found for ""
- A State Processing Engine
This is my third post about platform events. Last time I shared a few things I've learned about this tool. Now I want to share some great advice I got from my friend Chris Pifer about how to work with platform events. The trick is to allow the platform event to break processing into individual asynchronous bites but not lose track of the state of the work. Use Case I'm working with CollegeSpring , who runs college preparation classes for schools all over the country. They need to bring in records from their learning management system (LMS), called Buzz. Once CollegeSpring sets up the LMS for the partner school, the students (and teachers) mainly are tracked in the LMS—that's the system of record for their names, school Ids, and which classes they're in. The LMS has thousands of records: students (contacts) are enrolled (junction object) in classes (custom object) that are connected to pro grams (custom object) that are related to schools (accounts). We can get a spreadsheet out of Buzz with a row for every student and teacher, indicating their enrollment. But when we get the spreadsheet again a day or a week later we want to figure out, in Salesforce, whether the student exists (create them if not) and their enrollment is already recorded (create it if not, update it if changed). Particularly at the beginning of the semester, students might come and go or move around from class to class. Simple in Theory Thought about singly, a row of the export from the LMS is quite simple: Student Name (and unique LMS Id) LMS Enrollment Id Enrollment Status Class LMS Id Program LMS Id (tied to school Account) A flow to check if the student, class, and/or program exists and then create or update as required isn't that hard to conceptualize. The problem is that this flow might hit limits when it runs, particularly if you're inserting a lot of records at a time, as we intend to do. So from the start I wanted to set this up so that processing would be asynchronous and would run for one record at a time in its own transaction. That's where platform events are my friend. Platform events also gave me the option of partially processing the import record as it goes through its steps. That has three benefits: If a later step fails the earlier parts that were successful don't get rolled back . In other words, I can save partially processed records in that partial state. Later, I can fix whatever caused them to fail, and then restart processing. When re-running the flow (ie. reprocessing the record) it doesn't have to redo work. In any given processing step I have just two or three SOQL or DML operations (pink flow elements). A Complicated Flow? The actual flow, once built, looks a lot more complicated than it really is. But that's because I've put in a bunch of fault paths and logging. I almost don't want to show you a screenshot for fear I make it seem scary. But here you go: Actually Not Complicated I promise you, here's all the flow is really doing (illustrated in LucidChart because flow isn't really built for screenshots): In words instead of image: A platform event is published, which kicks off the flow. The flow looks up the import holding object (called a BuzzDataUpload), where all the data about the import is living. (I didn't put data on the platform event, it all lives on the BuzzDataUpload.) A decision checks if all the related objects have already been found and their lookup fields filled. (It checks the state of the record.) If so, set the BuzzDataUpload's processing status as "✅ Complete" and we are done. If the Account lookup is empty (meaning the import object hasn't yet been matched to an account) do a Get Records to find the account, update the BuzzDataUpload record with the Id of that account and set its processing status to "⏳ Processing," publish a new platform event. (Go back to Start.) [If no account was found, update the import record with a processing status of "⛔️ Processing Error." Do not publish another platform event.] If the Account was filled but the Contact lookup is not filled, upsert a contact, update the BuzzDataUpload record with the Id of that contact, publish a new platform event. (Go back to Start.) If the Account and Contact lookups are filled, but not the Enrollment, upsert an enrollment, update the BuzzDataUpload record with the Id of that enrollment, publish a new platform event. (Go back to Start.) Etcetera until the BuzzDataUpload has been fully processed. All the Bells and Whistles My final flow has a lot more elements on the canvas in order to include a bunch of refinements, including things like: Counting the number of platform events that have fired, as a check on how many times the record has run through processing Inserting FlowLog records at various places to help with debugging Lookups for record types before creating records (like enrollments) Decision elements to check if the field(s) we are about to use to look for records are outside of expected values, such as the Role field Fault Paths on just about every Get Records or Create Records step to log if there is some kind of error A Processing Notes field that the flow updates when it has an error (like in step 4d, above) The real use case has five fields that eventually have to link the BuzzDataUpload to records of other objects, so two more full branches of the flow. But none of that changes the heart of the flow. It's simple in concept, but in reality covered in frills and decoration. What to do with ⛔️ Processing Error ? It might seem scary that I've got a branch of that flow that might mark a BuzzDataUpload with "⛔️ Processing Error." But that's the fun of the State Machine. With that field value we know that BuzzDataUpload needs reprocessing. (And the Processing Notes field tells us where processing ended.) That leaves just two things we need: A way to fix whatever problem happened the first time A way to send the record to be reprocessed Fixing the Problem Let's take the case of 4d in the example above. If there was no account found based on the values in the import holding object, we don't want to create an account. The account should definitely already exist in Salesforce! (It's one of our partner schools. We have an opportunity that's closed won, details of our contract, several people that are our main points of communication with the school. If we don't have those things, that seems bad...) The records we're importing from the learning management system include the LMS Id of the school as well as the account name. I want my flow to match on the unique Id, so there is no chance of confusion if school names are similar, mispelled, or whatever. But if we haven't entered the LMS's unique Id for the school into Salesforce, then that Get Records step is going to fail. I want that to happen! Now the flow just marks the import object as follows: Processing Status: ⛔️ Processing Error Processing Notes: "No Account found with LMS Id that matches this import record." When a human sees that processing note it's pretty obvious what needs fixing: We have not taken the LMS's program Id (created when the program was set up for the school) and associated it to the partner school's account record in Salesforce. [Hopefully we don't get to this point very often. We have an audit report to watch for partner schools that should have a program this year but don't. And we have another report for programs for this year that are active but don't have an LMS Id. But if neither of those audit reports caught the problem or if it wasn't fixed before we imported the LMS data, then the processing of the LMS data for each student and teacher at the school is going to error.] So once we see a record with the note "No Account found with LMS Id that matches this import record." we just have to add an LMS Id to the right account. Next time that record is processed, it shouldn't have any problem. Sending it to Reprocess Reprocessing a BuzzDataUpload record is as easy as checking a box. Whoever is working with the BuzzDataUpload record can check that box on a single record. Or they can use a list view to bulk inline edit the Reprocess box to checked. Or they could do it in even larger numbers at a time through Apsona . Once the box is checked, there's a record-triggered flow that publishes a platform event (and unchecks the box). Publication of that platform event kicks off the flow above. And we're back to the beginning, a very good place to start.. The State's the Thing Each time the platform event is published it causes that one BuzzDataUpload record's state to be checked, where the state is represented by all the lookup fields to the other records thats should exist when processing is complete. If one or more are not filled, the record needs another turn through the flow. If they're all filled, then we are done: The Single-Record Workaround Last post I mentioned that if platform events are published in batches they also get processed in batches, which can result in errors. I promised a workaround. (Credit to Andrew Russo for teaching me this one.) Originally I had a record-triggered flow that ran on any insert or update of a BuzzDataUpload record and published a platform event to kick off processing of that record. Since the inserts/updates were happening in bulk, processing was in bulk as well and I was finding weird errors. (Like my upsert of the contact erroring because there was already a contact with the unique LMS Id, which clearly was what the upsert was supposed to avoid!) Andrew's workaround was to put publishing of the platform event onto a scheduled path, where you can set the Batch Size to one . Adding a scheduled path to my flow also meant that I needed to have two flows, rather than just one. On Create On Update (when Reprocess is changed to be true.) (There's no way to combine those two flows because you can't make flow entry criteria that will pick up a new record and pick up a change to Reprocess "Only when a record is updated to meet the condition requirements," which is what you need in order to have a scheduled path.) But those flows are otherwise identical: On the immediate path, the BuzzDataUpload record is set to Processing Status "⏳ Processing" and Processing Note "Waiting to publish platform event." After the zero minute pause (which, in practice, seems to take at least one minute) the platform event is published (in a batch size of one). This does mean that insert or reprocessing of records waits for at least one minute. But the productivity gain over records erroring is worth way more than that!
- What I've Learned about Platform Events
Platform Events are a great tool to add to the admin's toolkit, but they take a moment to wrap your head around. And for those of us that are declarative-only, their strong scent of "developery-ness" adds to the wariness. But once you break them down, they can be pretty handy! Back in October 2023, six years after first encountering the idea of platform events (on Trailhead), I rediscovered them and then wrote about them . Since then I've learned some things, sometimes the hard way. Definition Before you go back and read that earlier post (which you should, but maybe after you finish this one !), here's the quick download on platform events: They're a tool "to connect business processes in Salesforce and external apps through the exchange of real-time event data." That second clause reminds us that platform events are generally used for integrations . But they don't have to be an integration to an external system, they can connect processes within Salesforce , which is what I'm interested in. Platform events can have fields, like records do. So you can use them to transmit information between the processes you're connecting. (More on that later.) But unlike records, platform events do not persist anywhere. They get "published" to any processes that are listening ("subscribed") and then they disappear, leaving little or no trace behind. Platform events go out more-or-less instantly from your process that publishes them. However, the publishing is technically asynchronous. Because platform event processing is asynchronous, any processes that are kicked off by a platform event are outside of the transaction that published the event, so those processes get their own set of Salesforce limits. Limitations and Learnings I hadn't picked up on all of those initially, so that's why I wanted to share with you. [This one actually isn't new to the discussion at all, but it's worth repeating:] Platform events do not persist. If you want to see that an event fired, you're going to have to take some measure of your own, like have a platform event-fired flow create a Chatter post, or a Task, or a log record. (I create log records using My FlowLog Object .) Otherwise, platform events are like something shouted: If you heard it, great. If not, the sound is gone. Platform event-triggered flows can't call subflows. I don't really know why not, but they can't. (Mostly this is a minor annoyance, since you could rebuild the functionality of what would have been the subflow within your PE-triggered flow.) I am told* that if you have a batch process that publishes platform events in a batch, flow will also process those events in a batch, not singly. (Which was how I understood it to work.) Apparently in a platform event-triggered Apex class you can set a batch size for processing. But in flow you cannot. So when I built a process that fired a platform event every time a record of my holding object was created and then bulk imported into that object (using Apsona ) I didn't realize that my platform event processing flow would take things in batches since the events were fired in batches. [There's a workaround that I'll write about in my next post.] That lead to errors and to me being very confused by those errors.. * Intentional passive voice there. I can't find documentation to point to. I certainly experienced this, so I believe it to be true. And while the person that explained this probably wouldn't mind if I mentioned them, I am going to let this be my own writing and take personal responsibility if I've gotten it wrong. You can build a platform event-triggered flow to run in system context (it runs as the Default Workflow User) or as the user that triggered the publishing of the platform event. But either way, as I understand the note here , "if a flow interview creates or updates records, system fields like CreatedById and LastModifiedById reference the user who published the event message." I found that both a little surprising but also quite useful. It means record creation/processing is less anonymous than it might otherwise have been. I am also told that it's possible (though extremely rare) for a platform event to be missed by the subscribing process. This, in combination with the fact that platform events don't persist anywhere, means that you probably want to avoid storing data on the platform event that wouldn't otherwise be reproducible. For example, I was recently working on a process by which a user will import thousands of records from an outside system. The records go onto a holding object that has, say ten fields. The holding object records are then processed by a flow into several related records, based on the values in those fields. (Similar to how the NPSP Data Importer works to take in a row of person, account, and donation data and turn that into contact, accounts, opportunities, and campaigns.) I asked some questions on MVP Office Hours and, at one point, someone suggested that perhaps instead of uploading into the holding object, I should just upload as platform events directly, with fields on the platform event for all the data, like I have on the holding object right now. I didn't even realize that it was possible to directly upload platform events (directly publish them)! But even if I had known that, a few things would worry me about that approach: If the platform event were missed, it would be like it had never happened and we would have no way to know. Even if this is a one in a billion case, it worries me. If the flow picks up the publishing of the event, but then errors, I would have no way to see the data that needs reprocessing or how far it got before failing. We would have to go back to the spreadsheet that was being uploaded and figure out which ones didn't process properly. That seems burdensome. It would be very challenging to build, test, and debug the processing of the platform event into the related records because I couldn't see what was going on. (Maybe that's just me. I need to see the process as it moves step-by-step.) Note also the distinction in platform events between Publish Immediately and Publish After Commit . It's a subtle difference that I'm not sure I entirely understand. But "immediately" means that your publishing action (such as a Create Records within a flow) always publishes, even if the flow proceeds to fail and roll back the transaction. That could mean that an event fired referencing a record that proceeded never to have existed. So make that choice carefully when defining the platform event or you could run into trouble later on. More to Come My next post is going to be a full description of what I recently built using platform events. Watch this space!
- "Why do you hate NPC?"
I bet some of you have been wondering why I hate new Nonprofit Cloud (NPC). I'm not sure anyone has ever asked me directly with exactly this wording of the question, but I've definitely had people ask me a question in the same genre. No doubt I've written pretty harshly about NPC, directly, in the Emperor's New Clouds , and less directly, in posts on extension objects , person accounts , and even Salesforce's business strategy . I tend to be pretty transparent about what I think. But I don't hate Nonprofit Cloud. I mostly don't care about it. I don't think it's a product/service/offering that is going to affect my business or the day-to-day operations of my clients, small nonprofits. A Car Analogy I'm reaching for a car analogy to make this clear: I have about as much interest in Nonprofit Cloud as I have in Maclarens. That is to say, very little. For my whole life, my family has owned relatively practical and affordable vehicles. Toyota Camrys, Honda Civics and Accords... Not the absolute cheapest on the market, for sure, but not much in the way of vehicular splurges. [Sure, there has been some fun in the mix. My first car was a sweet 1967 Olds 442 convertible that my uncle loaned me long-term. And I bought a Celica convertible in my twenties that I drove until taking my mom's hand-me-down beige 1998 Toyota Camry in 2006 to fit two kids. I drove that one until 2022 (and my children are still driving it). Two years ago I bought a Polestar 2 electric vehicle. That was pricey, but I paid the extra for the sake of the environment.] To go back to the analogy: The cars I drove are ones most Americans would be pretty familiar with. If I think about "the car market," I'm thinking about regular vehicles. I may hate the fact that Americans drive large trucks and SUVs, paying extra and keeping fuel economy down. And I don't love that when I go to purchase a car there are fewer sedan options and fewer good fuel economy options than there should be. But that is the extent of how much I think about "the car market." When my son brings up things like Maclarens, Bentleys, even Porsches, I don't have any interest. Luxury and super luxury cars just aren't something I think about. I'd probably feel differently about Maclarens if there was some kind of program subsidizing them for low income car buyers. ( Then I'd be incensed that people were being handed a car that was going to bankrupt them in fuel and maintenance costs.) How I Feel About NPC How I feel about luxury cars is how I feel about NPC: It just isn't relevant to me. When I think and talk about "the Salesforce ecosystem" or "the Salesforce platform" I'm considering the features and functions that most organizations use. Anything behind the Industries barrier is too niche or too expensive for any of my clients and for the majority of other admins and users out there. You Can Feel How You Want I've also gotten pushback from consultants that are working with NPC. They let me know I'm too harsh or too negative and that they're using it with their clients. That's fine. To be clear, those are two very different assertions: If I'm too harsh or too negative, I'm open to hearing the ways in which my analysis of the features or functions is wrong. For the most part, other consultants have not pushed back on those things. In fact, they pretty much all tell me I'm spot on. And of course there are consultants using Nonprofit Cloud for their clients. But those are much larger clients than I have, larger than 90% of the market. I've said repeatedly that this might be viable for large organizations. I don't think I've heard from anyone that they're implementing for a small or medium client and finding that it makes sense. They may be doing it, but they're having to build workarounds and figure things out in all the ways that I've pointed at. Can it be done? I'm sure it can. Will it be expensive? Yes. Will the client be happy and use the system long term, recommending it to their peers? Only time will tell.
- Barrier to Entry
Once upon a time it was relatively easy for a small nonprofit to self-implement Salesforce. It's how I got started , and many other nonprofit Salesforce professionals as well. We were working at a small organization, we needed CRM, and "this Salesforce thing" seemed like it could work for us. We spun up a trial org, applied to the Power of Us program , spent some time playing in Setup, possibly spent a couple thousand dollars on a "quick start" with a consulting partner, and we were off and running. The quick start consulting engagement was optional, but, at least in our case, it gave us a boost and some confidence that I was getting things right. Once Trailhead launched in 2014 it became even easier to self implement because that is one amazing free (and fun!) learning resource . Naturally, success on the platform varies. And the quality or scope of an in-house DIY implementation is going to be a lot different than you would get from a big partner project. But for basic fundraising tracking needs and an upgrade from spreadsheets, the Nonprofit Success Pack (NPSP) is pretty great for the needs of thousands of organizations. And as your in-house person grows their skills, it's easy to grow your Salesforce to support more and more of the business needs. ⚠️ Self Implementation: Would Not Recommend ⚠️ But in 2024 I don't think I would recommend that a nonprofit self-implement Salesforce. It's become much more challenging than it used to be. I won't say it's impossible because I believe that a motivated person nonprofit staffer with some level of technical comfort (not yet "expertise," but a willingness to try things, learn, and dive in) could do this on her own. With time to devote to the project, engagement with Trailhead and the help documentation, and a willingness to engage with the community and ask questions, a newcomer could implement a credible NPSP setup for their organization. Of course, the organization would have to allow that staff member to devote time and energy to the implementation. It's the amount of time required that has gone up significantly. Full Disclosure (if you didn't already know): I make my living implementing and supporting Salesforce for small nonprofits. Clearly that means I have a bias toward someone hiring a consultant for an implementation rather than doing it themself. So take my comments/opinions here with that in mind. But I'll give the reasons for my thoughts and let you decide. That Was Then What I remember of our Quick Start in late 2012/early 2013: We got 40 hours of consultant time for a prepackaged implementation with minimal customization. The "quick" part meant that customization was limited, but we also got something of a discount, or at least a fixed price. I remember it costing $5,000 or $6,000. (40 hours at $150/hr sounds about right.) That was 12 years ago and inflation is real. But I don't think too many consultancies are offering a basic implementation even for the inflation-adjusted equivalent of about $8,000. The Salesforce platform has evolved, of course, with more powerful automation through Flow and new products and services that organizations may need advice about. An organization probably has more acute questions when starting their Salesforce journey, as I'll talk about below. And it's just a different landscape with nonprofits served by the Industries vertical within Salesforce rather than a nominally-independent Salesforce.org. All that is to say that I am clear-eyed about how organizations will relate differently to their implementation partner than they might have back then. A small org that just "wants to start using Salesforce" may actually need more time from their consulting partner than would have been needed in 2012. or have a lot more to figure out on their own then they would have back then. This is Now If you're thinking about implementing Salesforce at a small nonprofit today: You have to choose between Nonprofit Success Pack and Nonprofit Cloud. As I've written , NPC isn't appropriate for small nonprofits. But should a small nonprofit choose NPC, I really don't think self-implementing it is viable. The data model is too complicated, the initial setup steps are too numeous and finicky, and the documentation is not complete. Members of the nonprofit Salesforce community are working on this, as is Salesforce itself, one assumes, but I have doubts that it will ever be possible to self-implement NPC. You also, at this very early stage in considering your implementation, will start getting calls from Account Executives, or AEs. ( Spoiler Alert: AEs are Salespeople .) Because of the way sales incentives are structured at Salesforce, you're going to get a lot of pressure to buy things like Unlimited Edition, Experience Cloud, Premier Support, and more. You don't get to convert a trial org into your real instance. You can get a trial and play with it, but when you get your real instance it will be essentially a clean org, perhaps with NPSP installed, but only the package, none of the extras that were part of the trial, including record types, sales processes, page layouts, metadata records for NPSP features (like reciprocal relationships settings), and more. The Salesforce platform and ecosystem has also grown in the last decade. So it's just the case that there are more decisions to be made, more features to consider, and more rabbit holes in the Setup Tree to explore than there were in 2012. I Just Went Through This Hours Though I do a lot more ongoing support and add-on builds, every so often I get to do an implementation from scratch for a new Salesforce org. I just got to the end of one of those projects, in fact. So let me give a transparent view into that recent implementation. (Other than not telling you who the client was, because that feels weird.) To begin with, I estimated the project at around 60 hours . With the benefit of hindsight, that might have been a little low, and I'll probably estimate a little extra padding next time because I strongly prefer to overestimate and come in under. (Then again, these are estimates, so...🤷🏻.) As of the time of this writing, I'm six or seven hours over where I estimated. Plus I want to provide at least a bit of cushion for post-implementation support. As a businessman I have to decide what to do. But bottom line: This implementation went very smoothly, was not very complicated, and was for fundraising only. So sixty hours is just about the bare minimum I can imagine a new implementation requiring. I work quite quickly and have a lot of experience navigating Salesforce's back end. Consider what it would take for an internal employee doing this as a self-implementation and learning Salesforce as they go. Would that take them twice as long? Three times? More? If this is an employee suddenly adding Salesforce to other job responsibilities it might not entail additional line item costs to the organization, but there is definitely a cost for that person to take on the project. Costs Speaking of costs, I do projects like this as a time-and-materials project after giving my best attempt at an estimate. I feel this shares the risk equally between me and the client. Of course, some consultants might do this implementation for a fixed fee. And others might have a lower (or higher) hourly rate. I was charging $176.80/hour for this implementation. (Full Transparency: My rate is $221/hour for Salesforce work. I give nonprofits a 20% discount, hence $176.80. In 2025 my base rate will increase to $230.) So this fairly simple and smooth implementation will be about $11,000. Other Considerations Because I've been doing this for a few years, I have some tools that allowed me to speed things up. Using Copado Essentials makes planning, testing, and executing deployments much faster when I build in sandboxes. (And we always do that , right!?!) Copado ain't free , however. I also have a bunch of metadata saved that used to allow me to customize on top of the NPSP Trial. I couldn't use it the way I did in the past, but that stored metadata gave me a bit of a speed boost in getting the org looking the way I want it. I was able to push that metadata into the client's production org using Salesforce DX. I also built and stored a test and training dataset using Cumulus CI . No Salesforce newbie is going to have access to any of that, even if they have budget to spend. I think it's also fair to point out that I try to put more thought and effort to design and user experience than some other consultants might. So I suppose some time could be saved there. Your Mileage May Vary I'll end where I began: Salesforce is a powerful platform and NPSP is awesome for tons of organizations. But it's just not that easy to implement on-the-cheap anymore. You might be able to do it entirely in-house by a self-taught staff member. A small organization doesn't need a large consultancy. A small organization may not even need a small consultancy or even an independent consultant like me. The Salesforce community is vast and full of smart, talented, experience people, you might be able to get one of them to help you for free. (Though please be careful going this route. I have made far too much of my living cleaning up the mess someone left behind implementing for a nonprofit without understanding the business needs of nonprofits or the architecture of NPSP.) But my experience in the last few years has lead me to believe that someone is going to have to spend at least 60+ hours working directly on a new implementation , from discussions with stakeholders, scoping, and training to architecting and hands-on-keyboard setup and configuration.
- Give Lively Can Use Free API Integration User
It's almost two years now since Salesforce gave us all a gift by allowing five free API-access only integration users (and more cheap) , which contains costs and improves security and audit-ability. But there are plenty of vendors out there that haven't gotten around to updating their packages to explicitly support this. Give Lively , one of my top recommendations to clients, is one of those vendors. But supported or not, you definitely can use free integration users for Give Lively and save some money. You just have to figure it out for yourself. (Or just follow the instructions I'm going to give below.) Meet Give Lively Give Lively is a donation processing platform that's free. (Like a beer, not like a puppy!) That means you can set up your account and start taking donations without any contract cost. Give Lively charges processing fees that vary depending on the transaction type. (Those fees are imposed by the transaction processing networks.) But Give Lively itself is funded by philanthropy and does not charge any fees of its own, nor do they charge for integration to Salesforce. Donors have the opportunity to cover the transaction fees, transparently offered as an option on the Give Lively form. And forms can also ask donors to give an additional gift to Give Lively at the time of donation. As I recall, these are also options you can turn off for your forms. And, perhaps most importantly for you, it's very easy to set up a new Give Lively account and get it connected so that donation data flows to your Salesforce instance. But their documentation indicates that "The Give Lively integration does not currently support the new Salesforce Integration user license type. At this time we recommend utilizing a standard Salesforce user license." Let's Try It Anyway At some point I either hadn't read that, or it wasn't in the documentation yet, or I just decided to ignore it. I think probably I was excited to save a client a paid license and just went about trying it out before Give Lively had even assimilated that Salesforce had released the free users. So I don't think there was documentation saying it couldn't be done, I just had to figure out what to do. There are plenty of examples of apps out there that insist that to work with their tool you need a system administrator profile. Some dip their toe in good security practice and say you don't need a sysadmin profile but that you need permissions to view any object or field and change any setting in the app. While I'll concede this might be required for certain bits of functionality in some apps, it has to be rare. Saying "you need to be a sysadmin" is just being lazy. If you tell people they can only use your app as a sysadmin then you don't have to put as much thought into what missing permissions could get in the way. Give Lively's integration is a good example of this. At its heart, if you think about it, the Give Lively integration just needs to be able to insert an opportunity, contact, and/or campaign. That's eminently possible for non-admin users. ( Please assure me that your fundraising users are not on a sysadmin profile! ) When you log into the back end of Give Lively and work with the Salesforce integration setup, you can see that they've built a tool that will automatically apply permission sets to the sync user. The ability to actually do that requires an admin-type permission. But first of all, that tool is kinda' optional. We could manually grant permission sets. And anyway, you can grant the permissions that tool needs without granting all the other permissions of sysadmin. So at some point Give Lively saying they don't support free integration users is just them being unwilling to work on updating their package. I get it—we're all busy and bandwidth and funds are limited—but if you don't want to change the package, you could still change the documentation. I know there are other integrations out there that require a sysadmin profile because the integration actually checks that the profile of the integration user is System Administrator. (I'm looking side-eye at you, Classy .) That's truly lazy, as I'm sure the user could work with individually granted permissions. But they've hard-coded a profile name and they're not bothering to fix that. I would say that's unconscionable, particularly from a company that is charging a hefty fee to use their platform and an additional fee for the Salesforce integration. (Again, looking hard at you, Classy.) Spoiler Alert: Not Even That Hard So if we ignore Give Lively saying we can't use a free API integration user we just have to figure out the right permissions to grant that user and this is going to work. Fortunately the Give Lively app isn't hard coded to look for a full Salesforce license. (I'm pretty sure you could not have Give Lively log in as a Platform User license because those can't be granted access to Campaigns.) Step 1: Build a Custom Permission Set The Give Lively package installation (which I'm already assuming you've installed) comes with a couple of permission sets for granting users access to the fields from Give Lively. One is called "Give Lively Integration User" and is meant to be granted to an integration user. But since that one is limited to the license type Salesforce (a full license) instead of having nothing in that field, it won't be available to a free API user. So we're going to have to make our own permission set. At the top of Give Lively's documentation they list the permissions you need to include in this set. Make your new permission set. My name and description are only suggestions: Name : Give Lively Integration Perms Description : Additional permissions required for the GL integration user according to documentation at https://www.givelively.org/resources/salesforce-integration-set-up Allows GL to use a free integration user profile despite what their documentation says. And include the following things within this permission set: Permission Set Overview> Object Settings> Contacts Grant access to any record types used in your org. View All and Modify All Edit access to the field give_lively__User_ID__c Permission Set Overview> Object Settings> Campaigns Grant access to any record types used in your org. View All and Modify All Edit access on all of the fields from the Give Lively package. I count six fields: give_lively__Event_End_Date_Time__c give_lively__Event_Start_Date_Time__c give_lively__Campaign_Id__c give_lively__Campaign_URL__c give_lively__Event_Id__c give_lively__Text_Code__c Permission Set Overview> Object Settings> Opportunities Grant access to any record types used in your org. View All and Modify All Edit access on all of the fields from the Give Lively package. I count 17 fields: give_lively__Anonymous_to_Public__c give_lively__Campaign_Id__c give_lively__Client_Application_Name__c give_lively__Donation_Id__c give_lively__Event_Id__c give_lively__Subscription_Id__c give_lively__Net_Amount__c give_lively__Page_Slug__c give_lively__Page_Type__c give_lively__Page_Url__c give_lively__Payment_Platform_Transaction_Fee__c give_lively__Referrer_Url__c give_lively__Text_Code_Used__c give_lively__Transaction_Fee_Covered_By_Donor__c give_lively__Utm_Source__c give_lively__Widget_Type__c give_lively__Widget_Url__c Permission Set Overview> Object Settings> Accounts View All and Modify All Permission Set Overview>System Permissions View All Data Modify All Data API Enabled Assign Permission Sets Download AppExchange Packages Manage Profiles and Permission Sets Password Never Expires Note: On the objects View All and Modify All may be overkill. And View All Data and Modify All data overall may also be overkill. I have not experimented. But based on Give Lively's instructions, I granted those to see if I could get it to work. (Since they kinda' expect that you'll use a full system administrator, I figured this wasn't much different.) Step 2: Create the User, First as a Full User Next you are going to create a user for your Give Lively to log in as, something like First Name : Give Lively Last Name : Integration Set the email to somewhere you are going to be able to get the password creation message, though possibly not your email directly, it can be a group mailbox. Give the user a full Salesforce license and, for the sake of simplicity right now, a System Administrator profile. [This is not required. You could create this user directly as an API Only if you wanted. I tend to create integrations as user as a full user first. By creating a full user it's nice and easy to ensure that I am able to log in as that user and that it has the permissions I expect. Then I change the user license, profile, and permission sets after I've got it set.] Make sure you set Marketing User = TRUE. Step 3: Set Up the New User Password Get the password creation email and log in as Give Lively Integration. Make sure you know the password. (Consider saving it in a password manager or secure place your colleagues could access it, if needed in the future.) Step 4: Log Out of Salesforce Now make sure that you are fully logged out of Salesforce. If you are still logged in with a cookie, then the next step when you work in the back end of Give Lively may immediately log in as real you, not Give Lively Integration. Step 5: Connect Give Lively To Salesforce Log in to your Give Lively account and get to the place for setting up the integration. [According to this page , " click the 'Get Integrated' button and proceed through prompts."] When you log in, use the Give Lively Integration User —make sure not to log in as Real You! When the login is successful you'll see buttons for applying the Give Lively permission sets to the user. Go ahead and do this. You'll also see a Sync Now button. Might as well test that! In the Advanced Settings tab you can make choices about how you want Give Lively to deal with the data that goes to Salesforce. In particular, this is where you set the record type of opportunities it will create (you don't want it to just use the default record type for the profile it's logged in to—that might not be the right one) and the campaign (if any) that it will put those opportunities on. Step 6: See The Data Flow to Salesforce I now put a real donation into Give Lively to make sure that the data is flowing. If you're still testing Give Lively in your sandbox, they give you a fake credit card number you can use. But when testing the final setup I just make a donation of a few bucks to my client. Then I know it's really working in a real setting. Log back into Salesforce as Real You. Then look for the contact that the donation was made under. You should see the opportunity in their related list. Check that everything looks right. In particular, check that the opportunity was created by the Give Lively Integration user. Depending on your Give Lively settings, it might take a few minutes for the opportunity to sync. You can also speed things up with the Sync Now button in Give Lively. Step 7: Modify the Salesforce User If you've never created an API-only integration user before, you can use my instructions . But assuming you're in a position to set up one of those users, we're going to just modify the user we created in step 2. Edit the user: Switch the User License to Salesforce Integration . When you make this switch you'll get a pop-up warning you that any assigned permission sets or permission set groups will be unassigned. That's OK. We're going to set things back right in a moment. Set the profile to Minimum Access - API Only Integrations . [You could use Salesforce API Only Integrations if it shows up in your org. I don't think there's a functional difference.] Make sure you leave Marketing User checked. Now we've got a user that has access to basically nothing. So we have to assign permissions. Grant this user the Permission Set License Salesforce API Integration . (This is a step you always need to do for an API integration license user, it's not specific to Give Lively.) Now assign permission sets that grant access to the objects and fields the user will need. In this case, what really matters is your permission set Give Lively Integration Perms that was created in Step 1 . But for convenience you can grant the other standard permission sets for users in your org. And for safety's sake, I've been granting Give Lively Additional Permissions that is installed by GiveLively. (Though I found out the hard way that this alone isn't enough for the integration to work, which is why we built our custom one.) Step 8: Test Again in the Back End of Give Lively Now that you've modified the user, I recommend going into the back end of Give Lively and confirming that it still validates. Note that the Apply Permission Sets button will not work for the integration user. This is OK, just ignore the red error. Step 9: Send a Donation Through I don't consider it fully reliable until I've put a real donation through using a real credit card. Within the sync timing, it should show up in Salesforce. Yay! That's All! By following this relatively simple set of instructions you've just integrated Give Lively to Salesforce using a free API Only integration user instead of a full user license. Give yourself a gold star! 🌟 You've just saved your organization $500/year!
- The Future of NPSP
I regularly hear people claim that NPSP is "on its way out," or "already dead," or "Salesforce is going to stop supporting it." None of those things are true. Could they become true soon, quickly, or without any notice? Yes, they could. But Salesforce could also decide at any moment to stop developing, kill, or completely change Nonprofit Cloud. Right now I don't think they are going to. But my point is that they could . Salesforce is a giant corporate capitalist enterprise. It fundamentally exists only to make money. If it isn't making money on nonprofits, or through the Industries model, or whatever, it will change what it is doing. And Salesforce is run by people, who can change their mind, or their business vision, or, for that matter, can change jobs. So if the people in leadership were to decide they didn't want to be in the nonprofit market at all, the company could exit it on a dime. If those people decided that the nonprofit price point should double, there is nothing tangible to stop that from happening. (And for the sake of future-proofing this article, I should probably also note that Salesforce could change the names of these and other products at any time.) Where was I...? Oh, right. Don't Listen to the Fear The Nonprofit Success Pack (NPSP) is not going anywhere. It's stable. It works very well for what it does. Thousands of organizations have it installed and use it every single day. Even if Salesforce wanted to kill it quickly, they could not. There would be a very long tail of organizations still using the product. Besides, Salesforce has repeatedly said that they intend to continue to support NPSP. Sure, we could decide not to believe them. But so far I see no reason to be quite that cynical. Those of you who know me know that I'm plenty cynical. I'm just not that cynical. I'm sticking, for now, with "Trust, but verify." Support for NPSP will continue, even though further development of it as a product will not. NPSP is Like Cars Let's face it, development of NPSP stopped a long time ago. Long before New Nonprofit Cloud was dreamed up. There haven't been significant new features in the core NPSP offering since Enhanced Recurring Donations, Customizable Rollups, and Engagement Plans and Levels, all of which are more than six years in the past. And some of those were just upgrades to existing functionality in the first place. But just because there hasn't been much development doesn't mean NPSP is somehow outdated. I would argue that development of NPSP slowed and basically stopped because it reached the point that it was meeting the truly common and shared needs of nonprofits. NPSP takes Salesforce, reconfigures the B2B data model to make it work for tracking individual constituents and their households ("B2C," in the lingo), gives us relationship tracking between people, relationships tracking to multiple organizations, and powerful flexible donation rollups. That's basically the common set of CRM needs for nonprofits. Everything else that Salesforce.org used to publish was for a subset of the market—for good reasons! The Program Management Module only works for the program model of certain kinds of organizations. Outbound Funds is great, but only if your organization needs to track...well...outbound funds. Etcetera. And I think this is OK. NPSP reached the point where it was doing what we needed and Salesforce.org realized that when they made new "products" it made sense for them to be optional add-ons, not additional bloat of the core product. Here's my analogy: What's fundamentally changed about cars in more than half a century? Basically they're boxes with four wheels that burn gas to move people around. We invented automatic gearboxes, seatbelts, brigher headlights, cruise control, fancy radar for lane keeping and collision avoidance, and backup cameras. But my great-great-grandparents would have no trouble recognizing today's cars and even taking them out for a spin. Even electric cars are just not that fundamentally different. [I can say this with confidence: I own one. It's great. But when you get down to it, it's just a car.] So I think the future for NPSP looks a lot like the last decade or so: It works great. It's stable. It runs on a state-of-the-art platform that you can customize to the nth degree. There are a zillion organizations (and people) using it. And there is an amazing community of practitioners that work with it and welcome new people to its use, teaching, coaching, and training them. I still think NPSP is the right choice for 95% of nonprofit organizations that are thinking about implementing Salesforce at this moment. And those that are already on NPSP should not be expecting to migrate off any time soon. On a Wild Ride Does any of this mean that the future for NPSP won't be a bit of a ride? No, of course not! Just as two years ago Salesforce pulled the rug out from under all of us by announcing that NPSP would be replaced with NPC, which would be an entirely new system and migration would require a complete org swap, there could be surprises in store for all of us. I'm just trying to remind you that this was always the case. This is where I believe in the power of the Salesforce Community, particularly the Nonprofit Community. We are scrappy, and determined, and smart. If NPSP stops looking viable, then we'll come up with alternatives, whether it's re-creating the core functions through a community-supported free alternative, or building tools, templates, and workbooks for migration. If we come up with some Must Have feature that NPSP lacks and Salesforce is never going to provide, we'll build it and find a way to release it through Open Source Commons, or UnofficialSF, or somewhere else.
- Bifurcating the Market
With the move to the new Nonprofit Cloud (NPC) Salesforce has made a very intentional decision that they want to divide the market for nonprofits using Salesforce into two distinct segements: large organizations and everyone else. (Side note: when I say "nonprofits," I generally mean "nonprofits and educational institutions." But that's too long to write every time.) Large Organizations For large organizations, NPC and EdCloud might be a good solutions (or might be so someday ). I think I've been clear in my prior blog posts like The Emperor's New Clouds , Extension Objects: There's Nothing to Like , and others, that I don't think the new clouds are All That. But let me assume that Salesforce will manage to fix (or paper over) the problems that I've pointed out. Clearly they're making investments in roadmap for the new clouds. So let me give the benefit of the doubt that eventually the new products will be desirable for organizations planning to adopt Salesforce and that orgs already on Salesforce will eventually see features of the new clouds that are compelling enough for them to want to migrate. (Reminder: If you're currently on Salesforce but want to adopt the new clouds, this is a complete re-implementation .) But barring changes that I can't imagine (and nobody I've talked to can see), the new clouds will still only be appropriate for large nonprofits . When I say "large nonprofits" or "large organizations" I mean universities, national or international nonprofits, foundations, large museums, and the like; organizations that can support a team of multiple Salesforce professionals, including developers, plus probably have cash for a lot of partner/consultant support as well. I really mean large organizations . The data model, back end setup, and feature set of Nonprofit Cloud and Education Cloud are just too complicated for even medium-sized organization to work with. So I say that these clouds might be useful for larger organizations because they can use their greater resources to take advantage of the technology in ways that others can't and to build a lot of customizations, workarounds, tools, training, and documentation that make the extra complexity of the products bearable. And let me be transparent: I don't work with large organizations and I don't have a lot of experience with what kind of setups they have. So I am giving this analysis from an outsider perspective. Given that the large organizations have so many more resources than smaller ones, I think it's probably appropriate (to some extent) that they spend more money and effort on their Salesforce org. They have needs around scale and complexity that would always result in more expensive implementations. Plus, from my perspective, large organizations have (or should have ) the resources and expertise (or can hire/contract it) to caveat emptor. (That means "Buyer beware.") Everyone Else Then there is everyone else that might want to use Salesforce in a nonprofit context. This means small and medium nonprofits. This probably means you , dear reader, or the majority of your clients. I can't say this more strongly: The Nonprofit Success Pack (NPSP) is the right solution for you . (I suppose that comes with a small asterisk. If you're too small, Salesforce itself might not be right yet. Perhaps you should just stay on spreadsheets for a little longer. And there are plenty of organizations that need neither NPSP nor NPC because they should use plain Sales Cloud or Service Cloud or a completely custom other configuration. ) "We're going to become the Red Cross of [insert niche here]!" I know that medium sized nonprofits often think they're going to become large ones someday. Certainly that's the hope of many a founder and CEO/ED of these orgs. It feels like my duty to point out the improbability of this. And anyway, until you are large—really large!—NPC is not a good fit for you. Not today and not, in my estimation, for at least five years (and probably longer). So, yes, plan your system with the future in mind, design for scale, and leave room for growth. But build a system that works for your org as it is today. Don't saddle yourself with overbuilt and extra expensive. If you have a system that doesn't work for your org today you're going to struggle with adoption in the first place. The Nonprofit Success Pack (NPSP) works great. It's easy for users to understand, has many features you and your users will appreciate, and can handle quite a lot of volume. If you really truly do get large someday, such that either you're hitting the limits of what NPSP can handle at very large scale or else just that you have grown to the point that you think you meet the criteria I laid out, above, for using NPC, then and only then would it make sense to go with NPC. Choosing NPC while you are small or medium sized because you hear all the hype from Salesforce about the "innovation" and "exciting roadmap" is not going to serve you well. As I did last week , I'm going to reach for a vehicular analogy: Buying NPC today is like buying a school bus when you have your first child because you're planning to have lots of kids. You'll spend years driving an enormous vehicle that's practically empty. And by the time you've gotten to that giant brood, we'll probably all be wearing personal jetpacks anyway. (One can hope!)
- Reading Salesforce URLs
It seems likely that few people reading my blog wouldn't already know about Salesforce URLs, but just in case, let's talk fundamentals today . Whenever you're viewing a page of Salesforce, from the Home page, to a record page, to any part of setup, the URL is a link directly to the thing you're doing. This holds true in all Salesforce environments: production, sandboxes, developer orgs, Trailhead playgrounds, or scratch orgs. URLs are also pretty important in terms of your location in Setup as well. I try not to assume that things are going to work if I work from a Setup URL in Setup because that just feels dicey. But I often will email the link directly to a field definition or an email template. And note that even this official workaround from Salesforce talks about manipulating the URL to go to a place within Setup. Now that you know, you can copy that any URL and email it to someone so they can go straight to the page you were just viewing. (Once they've logged in, of course.) Most of the time I recommend using Chatter as a way to direct someone somewhere within Salesforce. But that isn't always convenient. If you're on a Zoom call, for example, and want everyone to take a look at a dashboard, it's way faster to go there, copy the URL, and put that in the Zoom chat than it would be to @mention each of them from a Chatter post on the dashboard. And when writing documentation, it's really convenient to be able to include links to things like particular list views. The Id's the Thing... The main reason I wanted to mention URLs, though, was to talk about grabbing record Ids. Because if you ever need to get the Id of a particular record, the URL is often your fastest bestest way to do so. There are other options, from a formula field that puts the Id on the page layout, to including it in a report, or a SOQL query or the like. But if we're talking about grabbing the Ids of just a handful of records, it's hard to beat the simplicity of grabbing them from the URL. Load this: https://d4t000000drczua0-dev-ed.lightning.force.com/lightning/r/Contact/0034T0000027laiQAA/view Select: https://d4t000000drczua0-dev-ed.lightning.force.com/lightning/r/Contact/ 0034T0000027laiQAA /view Copy. Reading the Code While we're at it, Salesforce URLs are a bit more complicated than they used to be, but they're not heard to interpret. In some ways, in Lightning Experience this has gotten both clearer and more obscure. But since we basically all use Lightning now, let's start there. Here is a Lightning URL, for example: https:// d4t000000drczua0-dev-ed .lightning.force.com /lightning /r /Account /0014T0000027laiQAA /view [Note: I have added spaces for readability where none would normally exist.] Read in chunks you can actually figure out quite a lot about where you are from this URL. https:// just indicates to your browser that we are viewing a webpage of a secure connection. Then comes the name of the actual org I'm logged into. This is a developer edition org. You probably spend most of your time in an org with a custom MyDomain that's similar to the name of your organization. .lightning.force.com is, of course, the domain for Salesforce itself. /lightning indicates that you're in Lightning Experience. /r I'm not really sure what that's for. [Update: A couple people wrote to me indicating that they belive it's for "record."] /Account indicates—surprise!—that we're viewing an Account record. /0014T0000027laiQAA is the 18 digit unique record Id of the account we're viewing. And /view indicates that we're in View mode, not Edit. Remember how I said this is both clearer and more obscure than in classic. Here's the same record in Classic: https://d4t000000drczua0-dev-ed.my.salesforce.com/0014T0000027lai On the on hand, this is much shorter. At a glance you learn a bit less about where you are. On the other hand, I kinda' miss this Classic format because if I needed to grab the Id it was quicker and easier to do so. It's easier to select the tail end of the URL than the part in the middle, as above, particularly since browsers generally truncate the URL. So you aren't even seeing the record Id until you start working within the address bar. 15 or 18? Did you notice that the Lightning URL shows the 18-digit version of the Id, but Classic URLs show the 15-digit version? The two versions are completely interchangeable as far as Salesforce is concerned. It's just that the 18-digit version is case in sensitive. When using the 15-digit version case matters. So a program that's not case sensitive could consider two records the same that are not. And you know what's not case sensitive? Microsoft Excel. So when working in Excel to do anything with Salesforce data, you're best off using the 18-digit Id. With a record identifier that's 15 characters long it's not very likely that you'd have two that got confused. But it's not impossible either... Working with URLs Interestingly, Salesforce doesn't really care if you keep using the Classic URL format. This is nice because it means you can do less work to go from just having a record Id into getting to the record in question. You can just delete everything after the first slash, paste a record Id after the slash and hit return. Salesforce will load the record, having redirected/translated from your Classic format into the Lightning format. So if you already have https://d4t000000drczua0-dev-ed.lightning.force.com/ And you paste a report's record id (00O4T000001wNWv) on the end, you'll wind up at https://d4t000000drczua0-dev-ed.lightning.force.com/lightning/r/Report/00O4T000001wNWvUAM/view Which, conveniently, is the report itself! I've also found that most of the time you can also just paste a different Id in the middle of that Lightning format and Salesforce will figure it out. This is a "your mileage may vary" situation. But if I'm on an account page: https://d4t000000drczua0-dev-ed.lightning.force.com/lightning/r/Account/0014T0000027laiQAA/view and I just double-click on the Id: https://d4t000000drczua0-dev-ed.lightning.force.com/lightning/r/Account/ 0014T0000027laiQAA /view and paste the Id of a contact —even just a 15 digit version—and don't edit the "/Account/" portion: https://d4t000000drczua0-dev-ed.lightning.force.com/lightning/r/Account/ 0039V00012vl0v /view When I hit Return, Salesforce will happily load the contact page and reconfigure the URL appropriately: https://d4t000000drczua0-dev-ed.lightning.force.com/lightning/r/Contact/0034T0000027laiQAA/view So that's nice.
- Id Key Prefixes
Did you know that when you're looking at the Id of a record—any record—on the platform, the first three digits tell you what object it's a record of ? For many of you, this is old news. If you've been around the ecosystem for a while, you've probably read about it (like on this blog , or this help article ), or been told about it. But I feel like this bit of Salesforce esoterica doesn't get discussed as often as it should and, therefore, that newbies don't learn about it consistently. This is useful information that every Salesforce admin should know. Last post we looked at how to break down a Salesforce URL. But today we're focusing just on the record Id that's in the URL (or anywhere else you might encounter record Ids, like in a spreadsheet). If I see 0014T000002xyUn, I know that this is an account. How do I know? Because it begins with 001. All account Ids begin with 001. (That tells you something about Salesforce and its history too, right? Accounts are the basis for the data model. All contacts must be related to an account. All opportunities are child to an account...) What we've noticed is that the object is identified with a prefix, known as the Key Prefix , within the record Id. All Accounts begin with 001. Contacts begin with 003. Users begin with 005. Opportunities begin with 006. Leads begin with 00Q. (Fun to speculate: I assume the Q is from "qualification.") Reports begin with 00O (that's zero zero letter O). If you want the truly complete list, let me direct you to Daniel Ballinger's list on Fish of Prey . Isn't it interesting that Account is 001 and user doesn't come along until 005? I assume that means that Parker built out the data model before bringing in the concept of logged in users interacting with the data. And what happened to 004...? Your custom objects get assigned a key prefix as well. They usually start with a lowercase a. (Maybe they always start with a lowercase a?) [Updated with a side note: Phil W pointed out to me that Id prefixes for custom objects can vary from org to org because of what might already have been in use before. If you install managed packages in a different order in two orgs, the custom objects for those packages could vary. This would apply even to the objects of NPSP, since it's theoretically possible that your org had some custom object using one of the prefixes before NPSP was installed in your instance. So don't make assumptions and don't hard code. ] Flows on Tasks Have you ever wanted to kick off automation, for example, "when someone creates a task related to an opportunity (via the Related To field)"? I get that kind of request all the time because someone wants to do something automatically if anyone has put a note on a grant, or a note on a partnership discussion. But while this seems simple at first glance, you quickly realize this isn't going to work because that Related To field (known by its API name, WhatId) can look up to just about any standard or custom object, it's not just a lookup to opportunity. But if you know about key prefixes, you can make a task that checks the first three digits of the value in WhatId to figure out if it's on an opportunity. Easy peasy! Decoding Errors The other place I find key prefixes useful is when trying to interpret an error, either in the UI or a flow error email. If the error message isn't very helpful—And, let's face it, that's more often than not!—it becomes a treasure hunt to figure it out. You have to understand the full context, such as what user was unable to do what thing, when/how they were doing it, etc. But often the error isn't directly related to what the user was doing, and instead has to do with other records that are updated because of what that user was doing, and the user doesn't have sufficient permissions to create/update/delete that other record. The Id in the error message might let you know what didn't seem obvious. For example, I see that I ages ago I had a question in my email about this: ERROR: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY: insufficient access rights on cross-reference id: 0014S000003rlts Immediately upon looking at it, I know that this has something to do with permissions regarding Account. Maybe the integration, in this case, was trying to update a contact or an opportunity, but it's account permissions that got in the way. Now I know where to start. Or this one: npsp.TDTM_Opportunity: execution of AfterInsert\n\ncaused by: System.DmlException: Insert failed. First exception on row 0; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: a2A000005Lthc A little sleuthing and I was able to figure out that a2A is the NPSP Data Import Batch object (npsp__DataImportBatch__c). Combined with knowledge that this error came from GiveLively (a donation platform), that might still leave a lot of troubleshooting to work on, but I already know a lot more than the original message conveyed! One Last Trick You can use the three digit prefix to go to the tab for the object it indicates. This won't work in all cases, since some objects, standard or custom, don't have a tab. But if you know the prefix for an object, or are looking for the object based on an error message, you can make a quick link to the tab with the prefix. For example https://yourdomain.lightning.force.com/006 will take you right to the Opportunities tab. Swap the 6 for a 3 and you can jump to the Contacts tab. Etc...
- Thing I Learned: Enabling Files Upload in Mobile
If you've tried it at all, you've probably noticed that the Salesforce mobile app acts significantly differently than interacting with the platform through a browser. I have to admit that I've only used the mobile app infrequently and, as far as I can tell, few of my clients have used it at all. So I don't pay it much attention. There are some Salesforce admins out there, like Terry Cole , that have put a lot more thought into the mobile app and a lot more encouragement for their users to adopt it than I have. But recently I had a client, Carol, that adopted the mobile app for herself. The main thing she wanted to do was upload a photo someone had texted to her to that person's Salesforce record. Seems like it should be [relatively] easy, right? So Many Actions Have you ever been working in the page layout editor and wondered about all the actions that show up in the "Salesforce Mobile and Lightning Experience Actions" section? Half of those, I'm not even sure what they really do, or if they work. And others are irrelevant clutter in this context, such as Submit for Approval , when there is no approval process for the object I'm working on. Plus there are the redundant ones, like New Payment , that replicate the function you could just get using the New button on the Payments related list. You may have tested this and noticed that lots of these don't actually show up for users (or you) because they relate to features that aren't enabled, or the like. Well I don't know about you, but that kind of clutter drives me crazy. It becomes hard to ensure that I've ordered the buttons in a useful way, not to mention that I haven't left on one or more that will confuse people So the first thing I do when I'm editing a page layout is to remove everything but the handful I actually want to display to users. So here's the button setup for a custom object called Onboarding: I removed a whole bunch that never get used and I've ordered the remainder in a way that generally makes sense for users: Cancellation Checklist (This is a regularly used custom quick action that had been built before I worked with them.) Change Owner (Onboarding owners are the people in charge of the record.) Then we have three buttons that actually show together in the Activity feed, not the button bar: Email , New Task , and Log a Call Printable View is rarely used, so I put it toward the end of the list. Change Record Type probably shouldn't even be here, as this object has no record types. (Since it doesn't display, I've never noticed that I ought to remove it.) Clone might sometimes be useful. Edit is often needed and I usually put it first of second. (I'm just noticing that it's in the wrong place now! But I think users in this org tend to click on the pencil icons instead of the Edit button anyway.) Post doesn't show up with the other actions, it displays in the Chatter publisher. And finally we put Delete last on the list because it should be the least frequently used. (Often it will end up under a carat if there are a lot of buttons on the page.) Here's what those result in when you're actually on a page: Better for Users than Admins Quick side note here: The final button order looks pretty good for users . (Though, as noted, I think Edit should be third and I'll probably make that change when I finish writing this post.) But the order in the page layout editor as an admin is confusing, particularly due to those actions that don't display in the button bar (like Post) or, like Change Record Type, don't display at all because there are no record types. On my best days, I'll reorder everything so that those ones are grouped at the beginning or end, or take them out of the layout entirely to reduce clutter. But other times (like, apparently, in this case...), since I know which ones display in their own places, I just leave them where they fall. What can I say? Sometimes I'm lazy. 🤷🏻 No New Button on the Files Related List in Mobile What my user, Carol, found was that even though she has no trouble uploading files to Onboardings in a browser using the Add File button in the related list, she wasn't able to figure out how to do it on mobile. The related list looked like this: Notice that there's no New or Upload button. When she asked me about it, I was confused too. How I Solved It It turns out that this is one of those situations that cleaning up the clutter created its own problem! The Files button that you probably see all the time in the page layout editor but doesn't show up when you view the page is actually what enables mobile uploads! So I had to edit the onboarding page layout to have these options in the Salesforce Mobile and Lightning Experience Actions section: See how I've added File second in the list? Here's an Onboarding record in a browser now: File does not appear there. But if you pull up that same onboarding on your phone: File is right there after Cancellation Checklist. So now it's possible to attach a photo from your phone to an Onboarding record. What seems like "clutter" can sometimes serve a purpose.
- Whiz-Bang at What Cost?
If you're like me, you're probably drowning in all the announcements from Dreamforce 2024 about generative AI (genAI) features under the Einstein and Agentforce branding. And you're probably asking yourself, as I am: "How much is this stuff going to cost?" These genAI features are going to be far from free. You're going to need the right kind of licensing and you're going to consume credits. Licensing The picture on licensing cost is starting to come into focus. Any user that is going to actually use genAI will need to have a proper license. Using genAI means sending a prompt to a generative pretrained transformer (GPT) and getting back results in the form of text, created or rewritten. Users that aren't the requester or the direct recipient of the AI answer should not need an AI license. Licensing your users starts with two options: Einstein 1 Edition This is a rebranding of Unlimited Edition, with Einstein for Sales/Service bundled (see below), Data Cloud (presumably with more credits than the free allocation), and some other things. ( You might recall how I feel about UE. ) With nonprofit discount these licenses are $3,600/user/year (down from list price of $6,000). So to summarize, my understanding is that if you're on Einstein 1 Edition then you pay for genAI features for all users, whether they send prompts to EinsteinGPT or not. Einstein for Sales (or Einstein for Service) This is an add-on license (probably a Feature License) that can be assigned to a user to enable genAI tools. It's my understanding that you can buy these add-ons only for the users that need them , which will save a lot of money. You're not going to need GPT for every person in your org, since some people will not send prompts. Your AE will probably imply that you should get one for everyone, but you should not . ( Spoiler Alert: AEs are Salespeople. ) The Einstein for Sales/Service add-on is $900/user/year at list price. As of this writing, I have not yet seen a nonprofit discount price. Since Einstein 1 Edition for nonprofits, above, comes to 40% off list price, I expect the nonprofit discount for Einstein for Sales/Service will probably be similar (so perhaps $540/year). [PS - I don't think there's really a huge distinction between the Sales or Service versions, they're naming that's meant to parallel the licensing naming. ( Don't buy both Sales and Service if you're a nonprofit!) ] Even if you economize as much as possible, it's looking like a minimum of more than $500/year to get AI features, for just a single user. Valid testing, let alone usage, is going to require at least the admin and one business user. That could become a significant additional annual cost to your "free" nonprofit software. By the way, with all the announcements leading up to and during Dreamforce, I'm writing this without a clear understanding of whether "Agentforce" replaces the "Einstein for" branding or if Agentforce represents something entirely new. GenAI Credits Once you've got the licensing in place, you're going to consume "credits." This is where I really can't help much with specifics. I'm not sure anyone can yet. First of all, I've asked around and have yet to understand which actions will actually consume a credit, or whether certain actions consume multiple credits at a time. If you read carefully in the nonprofit pricing guide PDF , you might have noticed that Nonprofit Cloud Einstein 1 Sales entitles you to "All features in Unlimited Edition plus Einstein for Sales (25K AI requests per user per month)..." I think that implies that 25K requests per month is also the allocation you'd get if you bought Einstein for Sales on its own. (But don't quote me on this.) Twenty five thousand AI requests per person per month sounds like it could be quite a lot. But is it? If the idea is to individually personalize fundraising emails to your entire list, that could soak them up pretty quickly if your list is large. It seems like it should cost a minimum of one credit per person on the list, since you would be asking EinsteinGPT to personalize to that potential donor. But at least you know exactly how many people are on your email list and how many email appeals you want to send. The other commonly-discussed use for GPT is for something like a customer service chatbot. A university might want to have a registrar's chatbot that can answer students' questions about course add/drop, or a comptroller's chatbot to help them make sure their student account is paid. Estimating credits for those use cases seems a lot less straightforward to me. I would assume a credit is consumed with each response in the chat. (Surely it's not just one credit per conversation.) Deploy that chatbot where a lot of people might use it (kinda' the point!) and you could start soaking up credits fast . We got at least one pricing clue in a September 12 press release from Salesforce. It's a rather long read for a press release, but at the very bottom you find, "Agentforce pricing starts at $2 per conversation; standard volume discounts apply." In some ways that generates more questions than it answers. Are "conversations" the same as the "requests" I was quoting numbers for above? Do you have to buy some bundle of conversations up front, or is it entirely based on usage? Does building and testing in a sandbox come free or still cost per conversations? What, if any, licensing is required to access Agentforce for Sales and Service? How will you know if you're going to get a huge bill? Plus doing a lot of this this might also require that you consume some (or many) Data Cloud credits at the same time...? Data Cloud Which reminds me: I've heard several references to possibly "requiring" Data Cloud in order to use Einstein genAI features. I have little to no understanding of what that actually means or whether you would need to have something beyond the free Data Cloud that every org is entitled to. I can see why this would be required if you wanted to combine your Salesforce data with data in other systems (email marketing, web click tracking) before you send it to EinsteinGPT. But I don't know if Data Cloud would somehow be required if you only want to use Salesforce data. If you have to purchase Data Cloud beyond the free allocation, my understanding is that it starts at $100,000/year! (Plus the cost of implementing, of course, which you're surely going to need a large consultancy for.) Nobody Knows 🤷🏻 Let me be fair to Salesforce here, though: I don't think they know how consumption-based pricing is going to work either. Their costs to provide these services to customers are consumption-based, because that's how cloud computing services are priced, whether genAI or elastic web storage. So they have to balance a massive uncertainty in how much their costs could balloon if people adopt these features. They're trying to offer the fancy new features that they think people want while figuring out the cost, pricing, and revenue models all at the same time. It certainly seems like the wave of the future for Salesforce costs will be more consumption-based and less fixed-price license based. But the actual outlines of that pricing are still pretty hazy.
- Freebie's Dreamforce Tips
I'll be presenting at Dreamforce in a couple of weeks, which I'm very excited about. [I hope I'll get to meet you there! If you're a reader, please say Hi. I'll even give you some stickers!] If you have never been to Dreamforce, it's quite...something. Over forty thousand of your closest friends, in packs of Trailblazer hoodies , taking over the streets of San Francisco . I should say it's probably not worth the cost for most people compared to going to Dreamin' events . (In fact, I should probably write a whole post about that!) But Dreamforce is something to see. I think everyone in the Salesforce ecosystem should experience the Mother of All Salesforce Events at least once. I mean, I got to see U2 at my first Dreamforce. It's not all conference rooms and PowerPoint. So if you're going to Dreamforce this year, or thinking about it for the future, here are my top tips for surviving and thriving. Comfortable Shoes 👟 I'm kidding here. Yes, you should wear comfortable shoes. You're going to spend all day on your feet. But this piece of advice has been given in a million blog posts, podcasts, and Trailblazer Community posts already. It was just a joke for me to throw it in. This post is not meant to be a rehash of what's been written before. Shorten Your Lanyard 🏷️ I've been on the record many times as a fan of name tags. And your Dreamforce badge is truly required to get into any space of the conference, so you're going to be wearing it all the time. Make your name visible by shortening the lanyard. I usually tie a small knot in the lanyard, which raises the badge closer to my chest than my stomach. If you're wearing a hoodie, you can put the lanyard around the hood, instead of just on your neck. If you have a collar, put it outside that. But I still think tying a knot is the best way to go. The benefit here is that even when you're sitting down, other people can see your name easily . Trust me—you'll appreciate it when you can remind yourself of the name you didn't quite catch over the noise. Skip the Marketing Sessions - And Too Many Are Marketing Sessions There's just no way around it, if a Salesforce employee is delivering the session, it's almost certainly going to be marketing. Lots of blah blah blah about the hot new thing and how it will change everything. (Last year and this year: Generative AI.) In my opinion, these are total wastes of time. This applies—perhaps especially applies —to the keynotes. (Yes, all the keynotes. Marc Benioff puts on a good show, but the main keynote is nothing more than an advertisement for new "features" that you probably won't ever use.) And anyway, you're going to hear about the main marketing push ad nauseum in a million other places. The main keynote doesn't have any other sessions happening at the same time, but there are plenty of other things to do with your time. As for the rest of the keynotes, I say look for sessions where you can learn real skills or meet real people instead. The other kinds of sessions I find tiresome are those where a partner presents with their customer about a big implementation. You can usually spot these with titles like "How the Food Relief Society Served Ten Million Meals" or "Quilts for Cats's Digital Transformation." The partner is there to market their company, sharing the stage with a customer that just spent tens or hundreds of thousands of dollars on a project. Salesforce gave the session a stage based on a recommendation by the sales team, with a marketing goal, not an educational one. With an implementation that big, the partner could never present all the nuances. The resulting presentation is too-simplistic and lacking in detail, leaving admins with little they can take back and use for themselves. But that isn't the goal of the session. The partner (and Salesforce) want executives at potential customers to be wowed so they'll do their own big implementation. As a hands-on-keyboard practitioner, I find these about as useful as the demos in the main keynote. Those demos are cool, but all I can think as I watch them is, "How many millions did this take to implement? And how much would it cost in annual licensing to support that org in real life?" Find the Right Sessions 🔍 So what sessions are worth adding to your agenda? Look for three categories: Anything presented by members of the community. These are going to be practical How To kinds of sessions, with real demos. (I'm biased, of course, since this covers my own session.) Community Cove events. These are also usually created/hosted by community members, though sometimes organized by Salesforce itself (members of the Trailblazer Community team). They're more informal, less "session" and more networking and discussion. Sessions run by Product Managers. This is the major exception to my rule, above, about sessions run by Salesforce employees. The product managers are actually building features, so these are chances to learn from the maker, see the roadmap for feature upgrades, and ask questions. Dreamforce has relatively few of these sessions, as they're more a focus at TDX. But read the Agenda Builder carefully and you'll find some. A special session worth mentioning here is True to the Core , which also features product managers, through it's actually facilitated/moderated by Parker Harris and senior technical leadership. This is the biggest, most public, place for admins to ask technical questions and advocate for feature improvements and interface upgrades. Network Network Network 🛜 The real reason to attend Dreamforce is to meet and hang out with people from the community. Sessions are interesting, of course, but the real value is in the people. When you're stuck on how to build something later these are the people you'll be able to ask. So introduce yourself to people in lines, sitting next to you in breakout rooms, and at meals. You never know when you'll run into someone you recognize from Ohana Slack or threads on the Trailblazer Community. Now you can pal around for a bit and turn a virtual contact into a real life friend. Pro tip for particularly for introverts: Find yourself a "Conference Buddy." The crowds are going to be overwhelming. But if you can find one person and connect with them for a bit, you'll be reenergized. Watch the online communities for events for newbies, including the Bacon Breakfast , the annual walk across the Golden Gate Bridge, and others. Definitely go to the First Timers meetup . These are great places to meet people who are also looking for a friend. Do the Quest—it’s fun! 🏅 Salesforce has significantly cut back on the massive swag load of previous years. But they still build in some kind of "quest" with good prizes like shirts, hoodies, and plushies. You usually have to attend a session or two of particular kinds, do a Trailhead module, and meet with some of the sponsors. It's not that hard. Check the Events app for the requirements and what the prizes are. There's usually also a paper handbook available at the information booths. Even if you have no interest in the prizes themselves, the quest can be fun. Plus it's something to do with people as you get to know each other. I have great memories from speed-running the TDX quest in 2023 with the Four M's (me, Monica, Misty, and Melissa). Besides the silliness of getting the prizes as quickly as possible, we had fun at the "escape room" and some of the other goofy games. Plus sometimes you might actually learn something, discover new products, features, or apps that you didn't know about, or even meet a product manager or find an exhibit booth you woud never have come across. Feed the Circular Economy ♺ Even if you don't care about the quest prizes and swag from exhibitors, you probably have someone in your life you can bring things back for. So take the good swag. Maybe you don't need yet another re-usable bag, or phone battery, or even hoodie. But your coworkers might appreciate them. (Or your family.) If you aren't into "stuff," that's fine. But you can be judicious. Only take the good stuff. Socks don't take up a lot of space. Plushies are bulky, but you'd be surprised how much people love them—even people that don't know the Salesforce characters. Stickers take no space at all. And yes, I'm aware of the environmental consequences and the waste swag can represent. But a few fewer stickers or pens taken from Dreamforce are not going to save the world. And if they'll bring joy to someone, that's got value. Your company sent you all the way to Dreamforce, you can share swag with coworkers as a sign of your appreciation. Or save the haul to bring with you to a user group or Dreamin' event. There are plenty of people that are involved in the ecosystem that don't make it to the big events or don't get their hands on a piece of swag they were hoping for. The more you give away, the more you build friendships in the ecosystem and spread the fun. Eat 🍴 For my last piece of advice, I'm turning to the practical: Don't forget to eat. Your Dreamforce registration comes with lunches. You need fuel to keep going. So make the time to eat. Bonus points if you manage to eat with one of your new friends. But even if you just need some time to sit quietly by yourself, get those healthy calories in when you can. And this applies doubly to dinners, in my experience. Lunch is at least served for everyone on the Dreamforce campus. (It might not be the perfect food you wanted, or the options might run out, but it's pretty good, relatively healthy, and will keep you going.) But dinner is on your own. You might manage to get food at one or another party, if you attend them. But I've learned not to count on that. Sometimes the food is insufficient. Or it's all gone by the time you arrive. Don't compound the exhaustion and the jet lag by also not having dinner. Grab a few people and head to a restaurant when the long day of sessions ends. Don't be shy: You can be certain that any group you announce a dinner plan to will have at least two or three people that want to eat with you! I also like to swing by Trader Joe's and grab some supplies to keep in my hotel room, both for breakfast and to keep some snacks with me during the day.