Every integration that relies on polling has the same flaw: you are either polling too frequently (wasting API calls) or not frequently enough (missing events). Platform Events are Salesforce's answer to this problem. Instead of asking "has anything changed?" on a schedule, you publish a message the moment something happens — and any subscriber receives it in near real-time without knowing or caring who sent it.
Platform Events are part of Salesforce's enterprise messaging platform. They implement a publish-subscribe pattern: producers and consumers are decoupled, and the event bus handles delivery. This session covers the complete developer workflow — defining events, publishing from Apex and external systems, subscribing via Apex triggers, using CometD for real-time LWC subscriptions, and understanding limits and delivery guarantees.
What a Platform Event Is
A Platform Event is a custom object type defined with Setup → Platform Events → New Platform Event. The API name ends with __e (the event suffix, same as __c for custom objects or __mdt for custom metadata). You define fields on the event — strings, numbers, booleans, dates — that carry the event payload.
Key properties of Platform Events:
- Immutable: Once published, an event message cannot be modified or deleted
- Not stored as records: Events are not queryable via SOQL after delivery (unlike standard objects)
- Retained 72 hours: Unprocessed events remain in the bus for 72 hours, retrievable via Replay ID
- Asynchronous delivery: Events are delivered after the publishing transaction commits
- Schema-based: The event definition is metadata deployed via Change Sets or SFDX
Defining a Platform Event
In Setup, navigate to Platform Events → New Platform Event. Provide:
- Label and plural label — used in UI references
- API Name — the
__eobject name used in Apex and SOQL - Publish Behavior — Publish After Commit (default, safest) or Publish Immediately
Then add custom fields. Example for an order notification event:
// Event API name: Order_Notification__e
// Fields: Order_Id__c (Text), Status__c (Text), Amount__c (Number)
Order_Notification__e evt = new Order_Notification__e();
evt.Order_Id__c = 'ORD-001';
evt.Status__c = 'SHIPPED';
evt.Amount__c = 249.99;
Publishing Platform Events from Apex
Two methods: EventBus.publish() and DML insert. Always prefer EventBus.publish().
EventBus.publish() — preferred
Order_Notification__e evt = new Order_Notification__e(
Order_Id__c = order.Id,
Status__c = 'SHIPPED',
Amount__c = order.Total_Amount__c
);
Database.SaveResult sr = EventBus.publish(evt);
if (!sr.isSuccess()) {
for (Database.Error err : sr.getErrors()) {
System.debug('Publish error: ' + err.getMessage());
}
}
To publish multiple events in one call:
List<Order_Notification__e> events = new List<Order_Notification__e>();
for (Order__c o : orders) {
events.add(new Order_Notification__e(
Order_Id__c = o.Id,
Status__c = o.Status__c
));
}
List<Database.SaveResult> results = EventBus.publish(events);
Publish Behavior — After Commit vs Immediately
| Behavior | When Event is Published | Use Case |
|---|---|---|
| Publish After Commit | After the transaction successfully commits | Default. Event only fires if the transaction succeeds — safe for data consistency. |
| Publish Immediately | Before the transaction commits | Events fire even if the transaction later rolls back. Useful for logging errors or alerting on failures. |
Subscribing via Apex Trigger
The most common subscriber is an Apex trigger on the event object. The trigger fires after insert — because Platform Events are immutable, only the after insert event fires.
trigger OrderNotificationTrigger on Order_Notification__e (after insert) {
for (Order_Notification__e evt : Trigger.new) {
// Process each event message
System.debug('Order: ' + evt.Order_Id__c +
' Status: ' + evt.Status__c);
// Update a record, send email, call a flow, etc.
}
}
Important: Platform Event triggers run in a new transaction with a new set of governor limits. They are not part of the publishing transaction. This means they cannot roll back the publisher's DML, and they have their own heap, query, and DML limits.
EventBus.TriggerContext — controlling the subscriber
Inside a Platform Event trigger, EventBus.TriggerContext.currentContext() gives you control over processing:
trigger OrderNotificationTrigger on Order_Notification__e (after insert) {
Integer failedIdx = -1;
try {
for (Integer i = 0; i < Trigger.new.size(); i++) {
processEvent(Trigger.new[i]);
failedIdx = i;
}
} catch (Exception e) {
// Resume from the event after the one that failed
EventBus.TriggerContext.currentContext().setResumeCheckpoint(
Trigger.new[failedIdx + 1].ReplayId
);
}
}
Subscribing via CometD (LWC / External Systems)
For real-time subscriptions in Lightning Web Components, subscribe to the Platform Event channel using the lightning/empApi wire adapter:
// LWC JavaScript
import { subscribe, unsubscribe, onError } from 'lightning/empApi';
const channel = '/event/Order_Notification__e';
let subscription;
async function subscribeToEvents() {
subscription = await subscribe(channel, -1, (event) => {
// -1 = receive new events only
// Use a stored Replay ID to replay missed events
console.log('Event received:', event);
});
}
The second argument to subscribe() is the Replay ID. Pass -1 for new events only, -2 to replay all retained events (72 hours), or a specific Replay ID to replay from a known position.
Publishing from External Systems
External systems can publish Platform Events via the Salesforce REST API:
# POST to publish an event from any external system
POST /services/data/v63.0/sobjects/Order_Notification__e/
Authorization: Bearer {access_token}
Content-Type: application/json
{
"Order_Id__c": "ORD-9012",
"Status__c": "PAID",
"Amount__c": 599.00
}
This makes Platform Events a full bidirectional integration channel: Salesforce publishes events that external systems subscribe to via CometD, and external systems publish events that Apex triggers process.
Platform Events vs Change Data Capture vs Outbound Messages
| Feature | Platform Events | Change Data Capture | Outbound Messages |
|---|---|---|---|
| Publisher | Developer-controlled | Salesforce (automatic) | Workflow / Approval |
| Trigger | EventBus.publish() or DML | Any record create/update/delete | Workflow rule fires |
| Schema | Custom fields you define | Standard change event header + changed fields | Specific fields on a record |
| Delivery | CometD, Apex trigger | CometD, Apex trigger | SOAP endpoint |
| Best for | Business events, integrations | Data sync, audit, replication | Legacy SOAP integrations |
Limits and Considerations
- Publishing limits: 250,000 Platform Event publishes per 24 hours (Enterprise Edition); check your edition limit
- Apex trigger limits: The trigger runs in its own transaction with standard governor limits
- Batch size: A single
EventBus.publish()call can publish up to 2,000 events - Retention: Events are stored for 72 hours for replay; after that they are purged
- CometD connections: Each connected browser client counts as one streaming API concurrent client; orgs have a concurrency limit
- Error handling: If an Apex trigger fails, Salesforce retries delivery up to a configured retry count
Common Use Cases
- Real-time order notifications: Publish when an order status changes; LWC subscribes to update a dashboard without polling
- IoT integration: External devices publish events to Salesforce which triggers Apex processing
- Decoupled service integration: Two Apex systems communicate via events rather than direct callouts — the publisher doesn't need to know if the subscriber is available
- Error notification: Use Publish Immediately behavior to fire error events even when a transaction rolls back
- Cross-org integration: Publish from one Salesforce org, subscribe via REST/CometD in another
For the full deployment workflow covering how Platform Events metadata is packaged alongside Named Credentials and other configuration, see Session 76 — Named Credentials. The next session covers Change Data Capture — the system-managed complement to Platform Events.
Frequently Asked Questions
What are Platform Events in Salesforce?
Platform Events are Salesforce's enterprise messaging mechanism based on event-driven architecture. They allow systems to communicate asynchronously by publishing event messages to a channel and subscribing to receive them. Platform Events are defined as custom objects with the __e suffix, and messages are delivered in near real-time via the Streaming API. They decouple producers from consumers — the publisher does not know who is listening, and the subscriber does not care who published.
How do you publish a Platform Event from Apex?
Use EventBus.publish(event), which returns a SaveResult you can inspect for errors without catching exceptions. Create an instance of your event object, set its fields, then call EventBus.publish(). Publishing is always asynchronous — the event enters the bus and subscribers receive it after the transaction commits. You can also publish a list of up to 2,000 events in one call.
What is a Replay ID in Platform Events?
Each Platform Event message is assigned a Replay ID — a sequential integer identifying its position in the event stream. CometD subscribers can use it to replay missed events after a disconnection by passing the last-processed Replay ID to the subscribe call. Events are retained for 72 hours. Apex triggers cannot replay using Replay IDs directly — that is a CometD subscriber capability.
What is the difference between Platform Events and Change Data Capture?
Platform Events are custom-defined events you publish explicitly — you control the schema, payload, and when they fire. Change Data Capture (CDC) events are system-generated automatically whenever a record is created, updated, deleted, or undeleted. Use Platform Events for application-level business events. Use CDC for data synchronisation where you need to react to any record change without custom publishing logic.
Can external systems publish and subscribe to Platform Events?
Yes. External systems can publish via the Salesforce REST API (POST to /services/data/vXX.0/sobjects/EventName__e) and subscribe via CometD using the Streaming API endpoint /event/EventName__e. This makes Platform Events a bidirectional integration mechanism. OAuth authentication is required for both directions.