Not verified hands-on. This article was written from primary documentation rather than reproduced in an org, so it carries no tested-release badge. If you run it and something differs, say so in the comments and it gets tested and corrected.

Briefly: Change Data Capture is for “tell me when a record changed”, and you get no say in the payload. Platform Events are for “tell me when this business thing happened”, and you define the payload. Outbound messages are the declarative option from an earlier era, still working, still SOAP. Pick CDC when the other system wants your data, Platform Events when it wants your meaning, and do not build either until you know what happens when nobody is listening for three days.

Change Data Capture or Platform EventsWhat each one decides for you, and which job each is right for.Change Data CaptureYou choose the objects. Salesforce chooses thepayload.Create, update, delete and undelete publishautomaticallyThe header says what changed it and wherethe change came fromThe message names the fields that changedRight when the other system mirrors yourdataNothing to build on the Salesforce sidePlatform EventsYou choose the payload, and when to publish it.Published from Flow, Apex or an API callThe payload is the fields you defineOne event per business transition, not perfield changeRight when the other system reacts to yourbusinessA contract you can versionBoth ride the same event bus: stored for 72 hours, replayable by replay ID, 1 MB per message. Past 72hours the events are gone and nothing tells the subscriber its picture is wrong.
One of them decides the payload for you. That is the whole choice.

They are not three versions of the same thing

All three push something out of Salesforce when something changes, which is why they land in the same design conversation. What separates them is who decides the message.

Change Data Capture publishes a change event whenever a record is created, updated, deleted or undeleted. The message is a header plus record fields, and the header says what kind of change it was and where it came from. You choose which objects are enabled. You do not choose the shape.

Platform Events are a message you design. You define the fields, you decide when to publish, and you publish from Flow, Apex or an API call. Nothing is automatic, which is the point — the event says “Order Fulfilled”, not “these 14 fields changed on this row”.

Outbound messages are configuration: a SOAP message sent to an endpoint you nominate when a rule fires. No code, and no subscriber to build on the Salesforce side. They retry on failure, which is more than a bare callout gives you — check the current documented retry window in Help rather than trusting anyone’s memory of it, including mine.

The choice usually comes down to one question

The Change Data Capture setup page with available entities on the left and selected entities on the right
CDC is enabled per object here. Nothing about the payload is yours to choose — only which objects publish.

Does the receiving system want to mirror your data, or react to your business?

A data warehouse, a search index, a reporting database, a downstream copy of Accounts — those want to mirror. CDC is built for exactly that, and choosing Platform Events instead means writing publish logic for every object and every field you later add, forever.

An ERP that needs to know an order is ready to ship wants to react. It does not care that Description__c changed. Publishing a Platform Event at the moment the business decides the order is ready gives the receiver one clear signal, and gives you a payload that does not break when someone renames a field.

The failure I see most: CDC wired into a system that only cares about one transition, and a subscriber full of filtering logic trying to work out whether this particular update was the one that mattered. That logic belongs in Salesforce, and its output is a Platform Event.

The 72-hour window is the real design constraint

Both CDC and Platform Events are high-volume events on the same bus, and Salesforce stores them for 72 hours. Not longer. Each event carries a replay ID, and a subscriber that stores the last replay ID it processed can reconnect and pick up where it stopped. As long as it comes back inside the window.

Three days sounds generous until you map it against real outages. A subscriber that dies on Friday evening and gets attention on Monday morning is at roughly 60 hours. A long weekend puts you past it. When you go past it, the events are gone, and nothing tells the receiving system that its picture is now wrong.

So every event-based integration needs a second mechanism, and it needs designing on day one rather than after the first gap:

  • Monitor the subscriber, not just the publisher. The Salesforce side will look perfectly healthy while nobody is listening.
  • Keep a reconciliation path. A scheduled query on SystemModstamp that catches anything the stream missed is unglamorous and has saved more integrations than any amount of event design.
  • Decide what “resync” means before you need it. If the answer is “reload everything”, know how long that takes while you are calm, not while the warehouse is three days stale.

The limits worth knowing before you design the payload

The Platform Events setup page showing event allocations and a custom platform event
The allocation numbers are on this page, next to your usage. A custom event appears here once it is deployed.

From the platform event and Pub/Sub documentation:

  • 1 MB maximum per event message. A batch may hold several, and Salesforce recommends keeping a batch under 3 MB, comfortably below the 4 MB gRPC ceiling.
  • 2,000 concurrent subscribers across the org. High for most estates, and low if every integration you own opens its own connection per environment.
  • Event delivery is allocated per 24 hours, and the allocation depends on your licences. This is the one that fails quietly: publishing keeps working, and deliveries stop being counted in your favour.

Two consequences for payload design. Keep events small and specific: an event carrying an Id and a status is cheap, resilient and easy to version. And do not publish one event per field change if a single event per business transition will do, because the allocation counts messages, not usefulness.

One more piece of housekeeping: standard-volume platform events have been retired. If you inherit an org with them, that migration is already on your list whether or not anyone has written it down.

What I would choose, and when I would not use events at all

For a warehouse or a downstream mirror: CDC, with a scheduled reconciliation query, and monitoring on the subscriber.

For “system B must do something when business event X happens”: a Platform Event published at the decision point, with a payload of Ids and the few fields the receiver genuinely needs. Not the whole record. The whole record is a contract you did not mean to sign.

For a small, declarative, low-volume notification where nobody wants to own a subscriber: an outbound message is still a reasonable answer, and dismissing it because it is old costs you a build you did not need.

And the honest case for none of the above: if the receiving system can only accept a nightly file, events buy you nothing except a queue that waits for the file anyway. Batch synchronisation is not a lesser pattern. It is the right pattern when the other end is batch-shaped.

Frequently asked

Can I subscribe to CDC inside Salesforce? Yes, with an Apex trigger on the change event or a flow, and it is a useful way to react to changes made by an integration. Watch for loops: your reaction is a change, and a change publishes an event.

Does CDC fire for every field? The event tells you which fields changed, so a subscriber can ignore updates it does not care about. It still costs you a delivery to find that out, which is the argument for a Platform Event when only one transition matters.

Do events respect sharing? Subscribers see event messages, not records, so record-level access does not filter the stream the way it filters a query. Design payloads on the assumption that anyone subscribed can read every field you include.

Are events guaranteed to arrive once? Design for at-least-once and you will never be surprised. Carry a key in the payload and make the receiver’s handling idempotent. The same discipline any asynchronous integration needs.