[object Object]

Three event mechanisms with overlapping names and very different jobs. Pick the wrong one and you spend a quarter retrofitting around governor limits or paying for events you don’t need.

This is the decision tree we use on every integration design review.

The three things, distinguished

  • Platform Events: custom, schema you design, fired by your code or flows. Used for application-level signals. “Order placed”, “Approval requested”.
  • Change Data Capture (CDC): Salesforce-fired, fixed schema per object, sends you the delta of every record change. Used for replication.
  • Pub/Sub API: gRPC-based delivery transport for both of the above. Replaces the older CometD streaming API. Used to consume either event type from outside Salesforce.

People conflate them because the Pub/Sub API delivers both. The API is the pipe. CDC and Platform Events are the water.

Decision question 1: who fires it?

If your business logic fires the event, you want a Platform Event. The schema is yours, the payload is what you put in it, you control when it fires.

If “any change to this record” should fire the event automatically and you don’t want to write code for that, you want CDC. You don’t get to shape the payload — you get a generic change envelope with old and new field values.

Decision question 2: replication or notification?

CDC is built for replication. Its design assumptions:

  • Ordered per record (within a 24-hour window).
  • Replayable up to 72 hours by replayId.
  • Includes change type (CREATE, UPDATE, DELETE, UNDELETE).
  • Captures the diff, not just the trigger.

Platform Events are built for notification. Their design assumptions:

  • High volume, low ceremony.
  • You decide what’s in them; deltas are your job.
  • Replay supported but not the primary use case.
  • Subscribers expect business meaning, not data sync semantics.

If your downstream system needs to maintain a mirror of Salesforce data, CDC is correct. If your downstream needs to react to a business event, Platform Events.

Decision question 3: volume and licensing

This is where projects go off the rails. As of 2026 pricing:

  • CDC events have a daily cap based on org edition. Unlimited Edition gets 5M+ free; most orgs get 250K and pay for overages.
  • Platform Events are licensed per published event with separate Hi-Volume and Standard-Volume buckets. Hi-Volume is cheaper per event but capped at certain delivery guarantees.

Run the math BEFORE the design. If you’re replicating an object that sees 2M updates a day and your org has a 250K cap, CDC will silently drop. Either upgrade or use a different pattern (batch extract via Bulk API 2.0 on a window — see Bulk API vs REST vs SOAP).

Decision question 4: ordering guarantees

CDC guarantees order per record within a 24-hour window. Platform Events guarantee order per partition (since the 2024 Pub/Sub move). If you need cross-record order — “all updates to all opportunities in the order they happened” — neither gives it to you out of the box. Use a Sequence__c field on a custom Platform Event and have subscribers sort.

Code: publishing a Platform Event from Apex

public class OrderEventPublisher {
  public static void publishPlaced(Order__c order, List<OrderLine__c> lines) {
    OrderPlaced__e event = new OrderPlaced__e(
      OrderId__c = order.Id,
      AccountId__c = order.AccountId__c,
      TotalAmount__c = order.TotalAmount__c,
      LineCount__c = lines.size(),
      OccurredAt__c = Datetime.now(),
      IdempotencyKey__c = order.Id + ':' + order.SystemModstamp.getTime()
    );
    Database.SaveResult sr = EventBus.publish(event);
    if (!sr.isSuccess()) {
      // Don't swallow this. Quarantine for retry.
      OrderEventQuarantine__c q = new OrderEventQuarantine__c(
        OrderId__c = order.Id,
        ErrorMessage__c = sr.getErrors()[0].getMessage()
      );
      insert q;
    }
  }
}

Always include an IdempotencyKey__c. Subscribers can dedupe even if you accidentally publish twice.

Code: subscribing via Pub/Sub API (Node)

import { PubSubClient } from '@salesforce/pubsub';

const client = new PubSubClient({
  accessToken: process.env.SF_ACCESS_TOKEN,
  instanceUrl: process.env.SF_INSTANCE_URL,
  organizationId: process.env.SF_ORG_ID
});

await client.subscribe({
  topicName: '/event/OrderPlaced__e',
  numRequested: 100,
  replayPreset: 'LATEST',
  onEvent: async (event) => {
    const key = event.payload.IdempotencyKey__c;
    if (await alreadyProcessed(key)) return;
    await processOrder(event.payload);
    await markProcessed(key);
  },
  onError: async (err) => {
    // Pub/Sub API surfaces errors per-subscription. Reconnect with backoff.
    console.error(err);
    await sleep(exponentialBackoff());
    // Library auto-resubscribes from last commit; you don't track replayId yourself
  }
});

The Pub/Sub API maintains commits per consumer; you do not store replayId manually in 2026.

When CDC beats Platform Events

  • You’re standing up a data lake mirror.
  • You need delete and undelete capture (Platform Events don’t fire on delete unless you wire it manually).
  • You want zero Apex/flow code on the publisher side.
  • The downstream truly wants the raw diff.

When Platform Events beats CDC

  • The event has business semantics (“payment failed”, “agent escalation triggered”).
  • Multiple changes should debounce to one event.
  • The payload should include data from related records.
  • You need versioning of the event schema.

UX note

If users trigger Platform Events from a Lightning page (e.g. “Approve and notify”), give them an explicit “Event published” toast with the event ID. Silent fire-and-forget makes users repeat the click. Two events for one approval is worse than no event.

Bottom line

  • Platform Events: business signals, schema you own, published by your logic.
  • CDC: record-level replication, fixed envelope, no code needed.
  • Pub/Sub API: transport for both, replacing CometD; commits managed for you.
  • Always run volume math against your edition’s event allocation BEFORE committing to a design.
  • Always include an idempotency key in custom Platform Events; subscribers will need it.
[object Object]
Share