Real-time data is no longer a luxury; it’s a necessity for modern Salesforce-driven businesses. Whether it’s syncing records instantly, updating user interfaces without delays, or building event-driven architectures, organizations are increasingly relying on Salesforce Change Data Capture (CDC) to stay ahead.
In our previous blog on “How to Use Salesforce Change Data Capture (CDC) in LWC for Real-Time UI Sync Without SOQL,” we explored how CDC enables seamless frontend updates.
Now, taking it a step further, this blog dives into Real-Time Salesforce Data Integration Using CDC and Apex, focusing on how developers can process change events efficiently using Asynchronous Apex Triggers.
By the end of this guide, you’ll understand how to leverage CDC in Apex, avoid common pitfalls like infinite loops, and build scalable, real-time integrations without relying on traditional polling or SOQL-heavy approaches.
Understanding CDC in the Context of Apex
As discussed earlier, Change Data Capture (CDC) allows Salesforce to publish real-time change events whenever records are created, updated, deleted, or undeleted. These events can be consumed by external systems, Lightning components, or Apex triggers.
While LWC focuses on UI-level synchronization, Apex takes CDC further by enabling backend processing and integration logic, making it a powerful tool for building event-driven systems within Salesforce.
This naturally brings us to the concept of Asynchronous Apex Triggers, which are specifically designed to handle CDC events.
What Are Asynchronous Apex Triggers?
To process data asynchronously, Salesforce already offers multiple approaches such as Future Methods, Queueable Apex, and Batch Apex. However, with the Summer ’19 release, Salesforce introduced a new mechanism – Asynchronous Apex Triggers using Change Data Capture.
These triggers are fundamentally different from traditional Apex triggers:
- They always run asynchronously
- They are invoked only after the database transaction is completed
- They operate on change events instead of actual records
In simple terms, instead of reacting immediately within a transaction, CDC triggers respond after the change is committed, ensuring better performance and scalability.
Because change events are based on platform events, they share characteristics for subscription with Apex platform event triggers. Also, change event messages in triggers contain header and record fields and some additional fields not present in JSON event messages.
Syntax for Trigger:
An example is given for Contact.
trigger ContactChangeEventTrigger on ContactChangeEvent (after insert) {
}
Since it is an Event and EventTrigger , it can run the maximum batch size of 2000 (the number of items in Trigger.new)..
And, as it is a Trigger, you can’t do callouts in this either.
You don’t have control; let’s say in ContactChangeEvent you update the contact’s field, and it will again fire a new ContactChangeEvent CDC Event. Infinite Loops will be there. You can prevent infinite loops in CDC using various ways, like. Few options are given below:
- Use a flag field (checkbox).
- Process only when relevant fields are changed.
- Check ChangeEventHeader.changeOrigin.
- Compare values before updating the record.
Understanding Apex Change Event Messages
Every CDC event received in Apex contains structured data similar to an SObject, including both record fields and metadata (header information).
Field Behavior Based on Operation
- Create Operation
When a new record is created, the event includes all fields, whether they contain values or not. This also includes default and system-generated fields like CreatedDate. - Update Operation
For updates, only the modified fields contain values, while unchanged fields appear as null. System fields like LastModifiedDate are included, and LastModifiedById appears only if it has changed. - Delete Operation
When a record is deleted, all fields in the event are null, as the record no longer exists. - Undelete Operation
In case of undelete, the event includes the complete record data, similar to a create event.
Working with ChangeEventHeader
Each change event includes a header that provides metadata about the change. Each change event captured in the trigger contains also has record fields.
To obtain a header field, access the ChangeEventHeader field on the event object. For example, this code snippet gets the change event header and writes header field values to the debug log.
EventBus.ChangeEventHeader header = event.ChangeEventHeader;
String changeEntity = header.entityName;
String changeOperation = header.changeType;
List<String> changedFieldsList = header.changedFields;
Whereas,
entityName represents the SObject Name on which the action performed, and
changeType represents the Operation performed like Create, Update, Delete and Undelete.
nulledFields contains the names of fields whose values were changed to null in an update operation. Use this field in Apex change event messages to determine if a field was changed to null in an update and isn’t an unchanged field.
changedFields contains the list of record fields that were changed in an update operation.
recordIds contains the list of all record IDs that have changed.
Now, let’s have a complete example to show the process.
For example, we will be using a Contact object. So, first enable CDC for Contact Object through setup as below:
Now create a Trigger on Contact as below:
Handler class of above Trigger:
How to See Debug Logs for CDC Event Trigger
To see debugs, you have to create a new debug log with different settings, as the debug logs for CDC Event Trigger don’t show up directly in debug logs.
Follow the below settings to create new debug logs:
Setup -> debug logs -> New -> Select options as below in image -> Save.
Now, you can see debug logs for the CDC event Trigger.
The debugs for Update Case will look like below.
For the Create Case as below.
No Data Found.