The "Last Activity Date" limitation with Shared Activities
The LastActivityDate field on the Contact object drives re-engagement campaigns, lead scoring and pipeline reviews for sales, marketing and operations teams. Turn on the "Allow Users to Relate Multiple Contacts to Tasks and Events" setting, better known as Shared Activities, and the field stops being reliable. It reflects activity for the primary contact on a Task or Event and ignores every secondary contact.
Why Shared Activities breaks Last Activity Date
Shared Activities lets one Task or Event record relate to several Contacts. The junction objects hold those relationships: TaskRelation for Tasks, EventRelation for Events. One contact is designated the primary through the WhoId field, and the rest are stored as secondary relations.
Salesforce only updates the standard LastActivityDate when the activity is linked to that primary contact. Secondary contacts on the same Task or Event never have theirs updated, which leaves the reporting built on the field incomplete.
Salesforce documents the limitation, and it shows up in reporting in a few ways:
- Re-engagement campaigns: marketing might exclude contacts who were on a recent activity as a secondary contact.
- Sales follow-up: reps might overlook contacts whose
LastActivityDatelooks stale and miss a timely follow-up. - Lead scoring: contacts may score lower because their engagement looks less recent than it is.
- Account activity tracking: an account's overall engagement can be misreported when the recent activity involved secondary contacts.
Building a solution that covers every related contact
To get around this, aggregate the activity dates from TaskRelation and EventRelation yourself so every associated contact is counted. That means custom rollup fields plus one formula field to consolidate them.
Step 1: create custom rollup date fields
Create two custom Date fields on the Contact object to hold the latest Task and Event dates.
Last_Task_Date__c: the most recent activity date from Tasks associated with the Contact.Last_Event_Date__c: the most recent activity date from Events associated with the Contact.
Note: this example assumes a tool like Rollup Helper from the AppExchange for the rollups. The same principles work with Apex triggers or other automation if you prefer.
Rollup configuration for Last_Task_Date__c:
- Rollup Object (Parent):
Contact - Source Object (Child):
TaskRelation - Rollup Type:
MAX - Field to Aggregate:
Task:ActivityDate - Filter Criteria:
IsWhat = false AND Task:Status = 'Completed'(keeps it to completed tasks related to contacts) - Result Field:
Last_Task_Date__c
Rollup configuration for Last_Event_Date__c:
- Rollup Object (Parent):
Contact - Source Object (Child):
EventRelation - Rollup Type:
MAX - Field to Aggregate:
Event:ActivityDate(orEvent:EndDateTime, depending on how you define event activity) - Filter Criteria:
IsWhat = false AND Event:IsPast = true(keeps it to events related to contacts that have already happened) - Result Field:
Last_Event_Date__c
A few things to watch with the rollups:
- Recalculation: most rollup tools recalculate in real time or let you schedule it. Run a manual recalculation straight after setup to backfill existing records.
- Testing: always test the configuration in a sandbox before it goes to production.
- Permissions: check that
Last_Task_Date__candLast_Event_Date__care visible to the profiles and permission sets that need them.
Step 2: consolidate with a formula field
With Last_Task_Date__c and Last_Event_Date__c populated, create a formula field that picks the most recent activity date across tasks and events.
Create a new Formula field of type Date on the
Contactobject namedLast_Activity_Date_All__c.Use the following formula:
IF( AND(NOT(ISBLANK(Last_Task_Date__c)), NOT(ISBLANK(Last_Event_Date__c))), IF(Last_Task_Date__c >= Last_Event_Date__c, Last_Task_Date__c, Last_Event_Date__c ), IF(NOT(ISBLANK(Last_Task_Date__c)), Last_Task_Date__c, IF(NOT(ISBLANK(Last_Event_Date__c)), Last_Event_Date__c, NULL ) ) )
The formula returns the later of the two dates when both are populated, whichever one has a value when only one does, and NULL when neither does, which keeps a zero date off contacts with no recorded activity.
Step 3: report on the consolidated field
Swap the standard LastActivityDate for Last_Activity_Date_All__c in your reports, list views and dashboards, and the engagement picture starts matching what actually happened.
Example reports:
- Contacts without recent activity: filter a Contact report where
Last_Activity_Date_All__cis older than 30, 60 or 90 days. - Activity recency by owner: group a Contact report by
OwnerIdand addLast_Activity_Date_All__cwith aMAXaggregation. - Account engagement overview: filter contacts by
AccountIdand sort byLast_Activity_Date_All__cin descending order. - Contacts never contacted: filter where
Last_Activity_Date_All__cis blank.
Leave a Comment