Count Activities against an Opportunity

Counting Activities logged against an Opportunity

Whenever I get a request for a new Trigger I usually hit Google first to see whether some developer has kindly shared a similar challenge and code solution.

On this occasion I was asked to display a count of all activities logged against an Opportunity record. This should answer the question of "how much work did we do for this?".

I found this first example of a class which would perform roll up summary type triggers for Open Activities across Account, Lead, Contact, and Opportunity and started looking at the structure.

After a bit more searching though I found another example Trigger which seemed closer to my requirements:

With a little modificiation this is what I came up with:

Trigger to count how many calls have been made relating to an Opportunity


1. Create a custom field on the Opportunity with Field Name Activity_Count. You can change the label field to be more meaningful though like “Completed calls” but Field API name has to be this.

2. Create the trigger TaskUpdateOpportunity

trigger TaskUpdateOpportunity on Task (after delete, after insert, after undelete, after update) {

//This trigger counts calls made against an Opportunity

Set<ID> oppIds = new Set<ID>();

//We only care about tasks linked to opportunities.

String prefix = OpportunityActivityCount.oppPrefix;

//Add any opportunity ids coming from the new data

if ( != null) {

for (Task t : {

if (t.WhatId != null && String.valueOf(t.whatId).startsWith(prefix) ) {





//Also add any opportunity ids coming from the old data (deletes, moving an activity from one opportunity to another)

if (Trigger.old != null) {

for (Task t : Trigger.old) {

if (t.WhatId != null && String.valueOf(t.whatId).startsWith(prefix) ) {





if (oppIds.size() > 0)



3. Create an Apex Class called OpportunityActivityCount


public with sharing class OpportunityActivityCount {

public static Boolean didRun = false;
public static String oppPrefix = Opportunity.sObjectType.getDescribe().getKeyPrefix();

* Takes a set of opportunity IDs, queries those opportunities, and updates the activity count if appropriate
public static void updateOpportunityCounts(Set<ID> oppIds) {

if (didRun == false) { //We only want this operation to run once per transaction.
didRun = true;

//Query all the opportunites, including the tasks child relationships
List<Opportunity> opps = [SELECT ID, activity_count__c, (SELECT ID FROM Tasks where Type='Call' AND Status='Completed'), (SELECT ID FROM Events) FROM Opportunity WHERE ID IN :oppIds];
List<Opportunity> updateOpps = new List<Opportunity>();

for (Opportunity o : opps) {
Integer count = o.tasks.size() +;

if (o.activity_count__c != count) {
o.activity_count__c = count;
updateOpps.add(o); //we're only doing updates to opps that have need to modify the others

//Update the appropriate opportunities
try {
update updateOpps;
} catch (Exception e) {
//This is controversial. Anything could happen when updating the opportunity..validation rule, security, etc. The key is we don't
//want the event update to we put a try catch around the opp update to make sure we don't stop that from happening.



  1. Hi Iain- I just came across your blog a few days ago and have learned a ton...thanks for doing such a great job!

    I've been looking for a solution for the rollup of activities on opportunities for a while and this seems perfect. When I copied the code into my instance (after creating the Activity_Count__c field), however, I get an error message that reads "Error: Compile Error: Variable does not exist: OpportunityActivityCount.oppPrefix at line 7 column 17" Do you know why this might be?

    1. Hi Koz

      Many thanks for your comment. Have you created both the Trigger and the Apex Class in your ORG?

      The OpportunityActivityCount.oppPrefix is set within the Class so if you've only created the Trigger when it runs it won't be able to find that variable.

      Let me know if creating the class and re-running the code does the job and many thanks for visiting my blog.


    2. Thanks, Iain! That did it- I really should have caught that. I'm trying to teach myself Apex and your content has been very helpful! One other issue with this trigger is that my Activity Count field updates when users click the New Task button or Log A Call button and log completed activities. However, when users go to Log A Call to log a completed activity AND create a follow-up task on the same screen, the Activity Count field does not update. If I go back to the completed activity record and make a trivial change to the comment field (or update any other field), the Activity Count updates to the correct count. Any idea what else I might be doing incorrectly?

      Thanks again for all of this!

    3. Hi Koz

      Thank you for your follow up question. In this example I was only counting completed activities - with a small change you'll be able to count Open ones as well.

      I would recommend going back to the source trigger that I adapted for my purposes to look at the counting of open Tasks:

      but if you wanted to adapt this trigger just amend the SOQL statement slightly to include Open and Complete status items:

      SELECT ID, activity_count__c, (SELECT ID FROM Tasks where Type='Call' AND Status='Completed')

      Good luck


Post a Comment