How to implement the concept of load balancer?

I have set up the Lead Assignment rules based on the concept of Round Robin.

Incoming Leads are rotated between each Rep. Works great.

However, I now want to balance the load. i.e. If Rep A has 4 open leads, Rep B has 6 open leads and Rep c has 20 open leads, then the next incoming lead would be assigned to the Rep with least Open leads. In this case, Rep A and Rep B will get the new leads till all three Reps have equal number of open leads. Also when a new rep joins, if each of the three existing reps have 20 open leads each, the new rep will be assigned 20 leads.

3 Answers 3


This question has been answered here: Assign leads from few queues as per round robin rule

Or if you do not have Omni-channel licensed and do not want to install an AppExchange product, you would need to use an Apex trigger on Lead (or possibly Flow if the round-robin team is small) to achieve this functionality.

A simplified example to show the concept:

(note: this code has not been production-tested or bulk tested, it likely has bugs, and does not handle randomized assignment when there are multiple Users with an equal number of assignments, it is purely to demonstrate the general concept of one way of assigning records to Users based on number owned):

// Query the userIds of the Users who you want Leads to be assigned to
// Note: I do not know which Users you want to assign Leads to, so I
// assumed it is a Role named 'Lead_Owner' 

Set<Id> leadOwners = [SELECT Id FROM User WHERE UserRole.DeveloperName = 'Lead_Owner'];

// Use aggregate query to get Users who currently own Leads, and the count
// of Leads each one owns, sorted so the users with the fewest Leads come first

List<AggregateResult> userIdWithLeadCountList = [SELECT OwnerId, COUNT(Id) leadCount FROM Lead WHERE OwnerId IN :leadOwners GROUP BY OwnerId ORDER BY COUNT(Id)];

// Convert above results into a Map

Map<String, Integer> userIdWithLeadCountMap = new Map<String, Integer>();
for (AggregateResult userIdWithLeadCount : userIdWithLeadCountList) {
    userIdWithLeadCountMap.put(userIdWithLeadCount.OwnerId, userIdWithLeadCount.leadCount);

// Loop through new Leads that need to be assigned
for (Lead newLead : Trigger.new) {
    String ownerId = [your default lead owner id goes here, perhaps stored in custom metadata];

    // Note: You would need code here and above to handle situations where
    // a user owns zero Leads, but you still want that user to be
    // assigned new leads. I have skipped that for simplicity

    // Loop through UserIds
    for (String userId : userIdWithLeadCountMap.keySet()) {

        // Check whether the currently specified owner has a fewer or equal count
        // of Leads assigned than the User Id we are looping through
        // Since we sorted by count of assigned Leads in the earlier query,
        // we can move on to the next Lead if yes
        if (userIdWithLeadCountMap.get(ownerId) <= userIdWithLeadCountMap.get(userId)) {
        } else {
            ownerId = userId;
    newLead.OwnerId = ownerId;
} // I am assuming this is a before insert trigger, so no DML update needed
  • Thanks @jamesquinn. do you have a reference to a lead load balancer algorithm. ? Commented Feb 12, 2021 at 15:53
  • 1
    @GroundToCloud I added a primitive example to my answer. I do not know of a robust algorithm available for free. There are AppExchange products for this too Commented Feb 12, 2021 at 20:42

what is leadCount in the AggregateResult query? Is it aa custom field created on lead? And the loop that you have added after the List, can we loop it on lead instead of AggregateResult like this ( Becuse if we loop on the AggregateResult, it is throwing error that Variable does not exist: OwnerId, leadCount:

    for (Lead userIdWithLeadCount : userIdWithLeadCountList) {
        userIdWithLeadCountMap.put(userIdWithLeadCount.OwnerId, userIdWithLeadCount.leadCount);

  • Hi @jamesquinn, pls check Commented Jan 30, 2023 at 5:59

A little late to the party, but I found your question when trying to find my original answer to this post in the trailblazer community here: Balanced Load assignment for lead Hope this helps you, and/or the next person looking for a similar solution!

The solution distributes Leads evenly based on "number of widgets" (1-2, 3-5, 6-10 etc.) that's selected from the pick list on the company's contact-us form, however it could be easily adapted to go off Lead Source or the number of Leads a rep currently owns or has been previously assigned. Overall, my customer's need was (based on deal size) to have incoming web-to-leads evenly distributed between 3 reps BUT also have the ability to assign the Leads to 2 completely different reps based on the number of a specific Task Type they completed the week prior. Essentially resulting in two groups: 3 that are in a "Round Robin" and the other 2 that get "Bonus Leads" based on their prior week's performance. I used two custom objects: Lead Distro/Rep (master/detail), two Process Builder flows, one Flow and two scheduled Declarative Lookup Rollup Summaries (DLRS). The Lead Distro object is the "scoreboard" that stores all the values for the Flow to use when evaluating the assignment, and the Rep object has a lookup to their SFDC User Record, their “Round Robin” number (1-3), the total number of Bonus Leads they should get, and then the number of Leads remaining that they have yet to receive: Lead Scoreboard ...and here's how everything works: Every Monday morning at 12:00am a scheduled rollup calculation (DLRS) counts the specific Task Types and saves this number to their SFDC User Record. Right after this a 2nd DLRS runs on a formula field on the Rep Object that brings down the number of Bonus Leads from the User Object and saves it to number field on Lead Distro Record "Bonus Leads Left to Assign." This change is necessary to fire a Process builder on the Rep (Rep__r) records to take the number of Bonus Leads they should get (stored on their User Record) and add it to the value of the Leads they have left to receive (column named "Number of Bonus Leads Left to Assign" in the pic). Next is the Process Builder on Lead, and all the criteria for it to evaluate if it needs to go to Lead Distro scoreboard. If it does, I update a lookup field on the Lead to the Lead Distro Record (there's only one) and under that action, set a lookup on the Lead Distro Record back to the same Lead. (Lead comes in, lookup to Lead Distro Record is set, lookup field on the Lead Distro Record is set back to the same Lead.) When the lookup field on the Lead Distro Record is set with the Lead, this fires the Autolaunched Flow. The Flow evaluates if there are Bonus Leads that need to be assigned. If yes, it grabs all the users that are NOT in the Round Robin, and then sorts it based on who has the highest number of "Number of Bonus Leads Left to Assign" at the top. (For example if Bob has 3 Bonus Leads and Jane had 1, Bob would get the next TWO incoming Leads.) After the Lead is assigned, the number left to get assigned is reduced by -1 on their Rep Record, and an Email Alert is sent out. Once all the Bonus Leads have been assigned, it proceeds with the “Round Robin” (Default Outcome in the pic below) and evaluates (again, based on ”number of widgets") who it was assigned to the previous time and who it should be assigned to now. There’s a number field for each value in the pick list, and the flow adds a +1 based on the value that the Lead has. For example if it's 1, it's changed to 2, until it equals the "Number of Reps in Round Robin" and then starts over, that way if a new person is added to the Round Robin (increasing it to a total of 4 reps) nothing has to be done and the system will assign until it reaches 4, then start over at 1.

Lead Distro Flow

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .