Platform Events and Change Data Capture
Module 3 of 8 in the chapter Events, chapter 11 of the Integration Architect course. Each module stands on its own. Previous: The Event Bus and the Pub/Sub API · Next: Replay, Retention, Order
The question this module answers: What kinds of news go out on the event bus, and what exactly does each one carry?
Two Kinds of News
Section titled “Two Kinds of News”Most of what goes out on Salesforce’s event bus is one of two kinds. A platform event is news you design: you decide what it’s called, what’s in it, and when it goes out. A change event is news Salesforce sends for you: turn on Change Data Capture for an object, and every time one of its records is created, updated, deleted or undeleted, Salesforce publishes it.
Design the message for a business moment; turn on Change Data Capture to copy what changed.
Salesforce’s own guidance puts both at the front: “Platform events and Change Data Capture (CDC) are the preferred mechanisms for publishing record and field changes that need to be consumed by other systems” (Event-Driven Architecture (opens in a new tab), Salesforce Architects, checked 2026-11-07). There are others on the bus, Salesforce’s own standard events and real-time event monitoring, but these are the two you’ll design with.
Platform Events, in Brief
Section titled “Platform Events, in Brief”Chapter 4 built one: Steve Trucking’s Delivery Update, defined in Setup, published from a record-triggered flow (Platform Events in Flow). Three things to add here.
It has to survive on its own. The event is going to leave Salesforce, so its fields are simple types only: checkbox, date, date/time, number, text and long text (Platform Event Fields (opens in a new tab), Platform Events Developer Guide, checked 2026-11-07). No picklists, no lookups, no master-detail: a lookup means nothing outside the org.
It has a size. One event can be up to 1 MB (Common Platform Event Allocations (opens in a new tab), same guide, checked 2026-11-07). Whether you fill that box or send just an ID and let the other side come and get the rest is the design question chapters 4 and 7 took apart (what goes in the event).
New events are high-volume. You may still meet an old “standard-volume” platform event in an older org. You can’t create new ones, and Salesforce’s guide says “Standard-volume custom platform events will be retired in Summer ‘27” (Standard-Volume Platform Event Allocations (opens in a new tab), same guide, checked 2026-11-07). If you find one on your landscape, that’s a migration with a date.
Platform events can be published from a flow, from Apex, and from outside Salesforce, through the Pub/Sub API’s Publish calls (module 2) or the REST API.
When It Actually Leaves
Section titled “When It Actually Leaves”Publishing feels instant. It isn’t quite, and the gap matters.
First, there’s the event’s publish setting, from chapter 4. Publish Immediately, the default, sends the event when the flow or the code publishes it, whether or not the rest of the transaction succeeds. Publish After Commit waits until the record is saved, and doesn’t send the event at all if the save fails (chapter 4). So with Publish Immediately, Redrock can hear about a delivery that was never saved. Once an event has gone, it can’t be called back.
Second, “published” means “queued.” When Apex publishes, Salesforce’s guide says what success means: “If the isSuccess() method returns true, the publish request is queued in Salesforce and the event message is published asynchronously” (Publish Event Messages with Apex (opens in a new tab), same guide, checked 2026-11-07). If the code needs the final answer, Salesforce offers publish callbacks for that.
So the rule I’d write on the landscape: if any subscriber is going to call back to read the record, choose Publish After Commit. And treat a successful publish as “it’s on its way,” not “they have it.” Whether they have it is the return receipt’s job.
Change Data Capture: Just Turn It On
Section titled “Change Data Capture: Just Turn It On”Here’s how I teach Change Data Capture. Say another system wants to know about every change to accounts. You could build it yourself: a record-triggered flow on Account that queries the fields and publishes a platform event. It works.
Now someone adds a new field to Account. What do you have to change? The flow has to query the new field. The platform event needs a field for it. The subscriber has to read it. Every change to the object means changing three things, forever. That’s code that needs to be continually maintained.
Salesforce will do that for you. That’s Change Data Capture. In Setup, on the Change Data Capture page, you select the objects. From then on, Salesforce publishes a change event every time a record of that object is created, updated, deleted or undeleted (Change Data Capture (opens in a new tab), Change Data Capture Developer Guide, checked 2026-11-07). No flow. And when someone adds a field, the next change event carries it.
At Steve Trucking, the object is the Work Order: it’s on Salesforce’s list, as WorkOrderChangeEvent (WorkOrder (opens in a new tab), Object Reference, checked 2026-11-07). A subscriber can listen to one object’s channel, /data/WorkOrderChangeEvent, or to /data/ChangeEvents for every object selected (Subscription Channels (opens in a new tab), same guide, checked 2026-11-07).
There is a cost, though. Without an add-on, you can select up to five objects, across all channels. The add-on “removes the limit on the maximum number of entities selected,” and it adds deliveries too (Change Data Capture Allocations (opens in a new tab), same guide, checked 2026-11-07). Module 5 does the arithmetic.
What a Change Event Carries
Section titled “What a Change Event Carries”A change event has two parts (Change Event Message Structure (opens in a new tab), same guide, checked 2026-11-07).
The header, ChangeEventHeader, says what happened: which object (entityName), which records (recordIds), what kind of change (changeType: CREATE, UPDATE, DELETE or UNDELETE), who made it (commitUser), when it was committed (commitTimestamp), which transaction it was part of (transactionKey), and which fields changed (changedFields).
The body is the record’s fields. And here’s what surprises people. For an update, through the Pub/Sub API, every field is there, but “Unchanged fields have an empty value even if they have a value on the record.” To know what changed, you read changedFields in the header (Change Event Body Fields (opens in a new tab), same guide, checked 2026-11-07). So an update to a Work Order’s Status doesn’t tell the subscriber the Work Order’s partner key, unless you ask for it (below).
When I said in class you get a massive payload with “all the before and the after,” that’s the size of it, but not the content: an update carries the new values of what changed, not the old ones. If the other system needs the old value, it has to have kept it.
Three more things the subscriber has to know:
- Some fields never come. A change event doesn’t include
IsDeleted,SystemModstamp, or fields worked out from another record. A copy that needs those has to get them another way, the same warning as chapter 10. - One event can cover many records. If the same change is made to many records of one object within a second, Salesforce may send one event with all their IDs in
recordIds(Merged Change Events (opens in a new tab), same guide, checked 2026-11-07). Read every ID, not the first. - One change, possibly many events. Order and transactions are module 4.
When Salesforce Can’t Send the Whole Change
Section titled “When Salesforce Can’t Send the Whole Change”Sometimes Salesforce knows something changed but can’t send the details. It tells you anyway, with a different kind of event (Gap Events (opens in a new tab) and Overflow Events (opens in a new tab), same guide, checked 2026-11-07):
- A gap event says “this record changed, go and look.” Its
changeTypeis GAP_CREATE, GAP_UPDATE, GAP_DELETE or GAP_UNDELETE, with the record ID but no fields. It happens when the change event would be over 1 MB, after some field type changes, after an internal error, and for changes made directly in the database, such as archiving old activities. The subscriber’s answer: read the record by its ID. - An overflow event says “more changed than I could send.” One transaction that makes more than 100,000 changes gets change events for the first 100,000, then one GAP_OVERFLOW event per object for the rest, with no record IDs at all. The subscriber’s answer: a resync of that object, the way chapter 10 does it.
Neither is common. But a subscriber that ignores them has a copy that’s quietly wrong. Write the handling for both before go-live.
From a Tsunami to a Stream
Section titled “From a Tsunami to a Stream”When I first taught Change Data Capture, I’d warn the class: you’re going to get a tsunami of data. Every change to every selected object, to every subscriber. Today you can turn that into a stream.
A custom channel groups the objects one subscriber needs, apart from the others. On it, a filter says which changes to pass, written much like a SOQL condition, on the record’s fields or the header’s: only updates, say, or only when Status changes (Change Event Filters (opens in a new tab), same guide, checked 2026-11-07). And enrichment adds fields that didn’t change, so the subscriber always has them. Salesforce’s own example is exactly ours: “use enrichment when your app needs an external ID field for matching records in an external system” (Enrich Change Events with Extra Fields (opens in a new tab), same guide, checked 2026-11-07). One catch: custom channels are set up through the Metadata API or the Tooling API, not on the Setup page (Custom Channels (opens in a new tab), same guide, checked 2026-11-07). They’re a deployment, with a version in source control.
One channel, one filter: status changes only, each with the partner key.
At Steve Trucking, Snowflake keeps the status history. It doesn’t care when a crew note changes or a coordinator moves a time window. So the integration layer listens on a custom channel for Work Orders, filtered to Status changes, enriched with Partner_Delivery_Key__c, the key Snowflake matches on. Fewer events go out, and each one has what Snowflake needs. That matters twice: fewer events to process, and fewer deliveries counted against the allocation, which is module 5.
Which One
Section titled “Which One”| If the news is… | Use | Because |
|---|---|---|
| A business moment you name: a delivery running late, an order approved | A platform event | You choose its shape and when it goes, and it keeps that shape |
| “This record changed,” for a copy elsewhere | Change Data Capture | No flow to maintain; new fields come along by themselves |
| Some of the changes, to some subscribers | Change Data Capture on a custom channel, filtered and enriched | Less to send, and the key the other side needs |
At Steve Trucking, both run side by side. Redrock hears a Delivery Update, a platform event the business designed. Snowflake gets Work Order changes through Change Data Capture. Same records, two kinds of news, two subscribers.
Test knowledge. Know platform events from Change Data Capture. Platform events: you define them (an
__eobject with simple field types, up to 1 MB) and publish them from Flow, Apex or an API; Publish Immediately sends even if the transaction fails, Publish After Commit only after the save. Change Data Capture: select objects, and Salesforce publishes create, update, delete and undelete changes; an update carries the changed fields (checkchangedFieldsin the header); channels are/data/ChangeEventsor/data/<Object>ChangeEvent; custom channels can filter and enrich; gap and overflow events mean “go and look” and “resync.”
What an Architect Decides Here
Section titled “What an Architect Decides Here”- For each piece of news: a platform event or Change Data Capture, by whether you’re naming a business moment or copying what changed.
- Each platform event’s publish setting, Publish After Commit whenever a subscriber will read the record back.
- Which objects get Change Data Capture, against the five-object allowance or the add-on.
- The channels: one custom channel per subscriber that needs less, with its filter and the fields it’s enriched with, kept in source control.
- What every subscriber does with a gap event and an overflow event, written and tested before go-live.
- What the copy gets another way: the fields a change event never carries, and old values if anyone needs them.
Explore
Section titled “Explore”- Change Data Capture (opens in a new tab), Change Event Message Structure (opens in a new tab) and Change Event Body Fields (opens in a new tab): Change Data Capture Developer Guide (checked 2026-11-07)
- Gap Events (opens in a new tab), Overflow Events (opens in a new tab) and Merged Change Events (opens in a new tab): the same guide (checked 2026-11-07)
- Subscription Channels (opens in a new tab), Custom Channels (opens in a new tab), Change Event Filters (opens in a new tab) and Enrich Change Events with Extra Fields (opens in a new tab): the same guide (checked 2026-11-07)
- Change Data Capture Allocations (opens in a new tab): the same guide, the five-object allowance and the add-on (checked 2026-11-07)
- Platform Event Fields (opens in a new tab), Common Platform Event Allocations (opens in a new tab), Publish Event Messages with Apex (opens in a new tab) and Standard-Volume Platform Event Allocations (opens in a new tab): Platform Events Developer Guide (checked 2026-11-07)
- WorkOrder (opens in a new tab): Object Reference, WorkOrderChangeEvent (checked 2026-11-07)
- Event-Driven Architecture (opens in a new tab): Salesforce Architects decision guide (checked 2026-11-07)
